1 /******************************************************************************
2 *
3 * Project: OpenGIS Simple Features Reference Implementation
4 * Purpose: The OGRSimpleCurve and OGRLineString geometry classes.
5 * Author: Frank Warmerdam, warmerdam@pobox.com
6 *
7 ******************************************************************************
8 * Copyright (c) 1999, Frank Warmerdam
9 * Copyright (c) 2008-2014, Even Rouault <even dot rouault at spatialys.com>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "ogr_geometry.h"
31 #include "ogr_geos.h"
32 #include "ogr_p.h"
33
34 #include <cmath>
35 #include <cstdlib>
36 #include <algorithm>
37 #include <limits>
38 #include <new>
39
40 CPL_CVSID("$Id: ogrlinestring.cpp 113586cc903e1c16a745d7334479a55b48526138 2021-04-20 20:45:26 +0200 Even Rouault $")
41
42 namespace {
43
44 int DoubleToIntClamp(double dfValue) {
45 if( CPLIsNan(dfValue) ) return 0;
46 if( dfValue >= std::numeric_limits<int>::max() )
47 return std::numeric_limits<int>::max();
48 if( dfValue <= std::numeric_limits<int>::min() )
49 return std::numeric_limits<int>::min();
50 return static_cast<int>(dfValue);
51 }
52
53 } // namespace
54
55 /************************************************************************/
56 /* OGRSimpleCurve() */
57 /************************************************************************/
58
59 /** Constructor */
60 OGRSimpleCurve::OGRSimpleCurve() :
61 nPointCount(0),
62 paoPoints(nullptr),
63 padfZ(nullptr),
64 padfM(nullptr)
65 {}
66
67 /************************************************************************/
68 /* OGRSimpleCurve( const OGRSimpleCurve& ) */
69 /************************************************************************/
70
71 /**
72 * \brief Copy constructor.
73 *
74 * Note: before GDAL 2.1, only the default implementation of the constructor
75 * existed, which could be unsafe to use.
76 *
77 * @since GDAL 2.1
78 */
OGRLinearRing(OGRLinearRing * poSrcRing)79
80 OGRSimpleCurve::OGRSimpleCurve( const OGRSimpleCurve& other ) :
81 OGRCurve(other),
82 nPointCount(0),
83 paoPoints(nullptr),
84 padfZ(nullptr),
85 padfM(nullptr)
86 {
87 if( other.nPointCount > 0 )
88 setPoints( other.nPointCount, other.paoPoints, other.padfZ, other.padfM );
89 }
90
91 /************************************************************************/
92 /* ~OGRSimpleCurve() */
93 /************************************************************************/
94
95 OGRSimpleCurve::~OGRSimpleCurve()
96
97 {
98 CPLFree( paoPoints );
99 CPLFree( padfZ );
100 CPLFree( padfM );
101 }
102
103 /************************************************************************/
104 /* operator=( const OGRPoint& ) */
105 /************************************************************************/
106
107 /**
108 * \brief Assignment operator.
109 *
110 * Note: before GDAL 2.1, only the default implementation of the operator
111 * existed, which could be unsafe to use.
112 *
113 * @since GDAL 2.1
114 */
operator =(const OGRLinearRing & other)115
116 OGRSimpleCurve& OGRSimpleCurve::operator=( const OGRSimpleCurve& other )
117 {
118 if( this == &other)
119 return *this;
120
121 OGRCurve::operator=( other );
122
123 setPoints(other.nPointCount, other.paoPoints, other.padfZ, other.padfM);
124 flags = other.flags;
125
126 return *this;
127 }
getGeometryName() const128
129 /************************************************************************/
130 /* flattenTo2D() */
131 /************************************************************************/
132
133 void OGRSimpleCurve::flattenTo2D()
134
135 {
136 Make2D();
137 setMeasured(FALSE);
138 }
139
WkbSize() const140 /************************************************************************/
141 /* empty() */
142 /************************************************************************/
143
144 void OGRSimpleCurve::empty()
145
146 {
147 setNumPoints( 0 );
148 }
149
150 /************************************************************************/
151 /* setCoordinateDimension() */
importFromWkb(const unsigned char *,size_t,OGRwkbVariant,size_t &)152 /************************************************************************/
153
154 void OGRSimpleCurve::setCoordinateDimension( int nNewDimension )
155
156 {
157 if( nNewDimension == 2 )
158 Make2D();
159 else if( nNewDimension == 3 )
160 Make3D();
161 setMeasured(FALSE);
162 }
163
164 void OGRSimpleCurve::set3D( OGRBoolean bIs3D )
165
166 {
exportToWkb(CPL_UNUSED OGRwkbByteOrder eByteOrder,CPL_UNUSED unsigned char * pabyData,CPL_UNUSED OGRwkbVariant eWkbVariant) const167 if( bIs3D )
168 Make3D();
169 else
170 Make2D();
171 }
172
173 void OGRSimpleCurve::setMeasured( OGRBoolean bIsMeasured )
174
175 {
176 if( bIsMeasured )
177 AddM();
178 else
179 RemoveM();
180 }
181
182 /************************************************************************/
_importFromWkb(OGRwkbByteOrder eByteOrder,int _flags,const unsigned char * pabyData,size_t nBytesAvailable,size_t & nBytesConsumedOut)183 /* WkbSize() */
184 /* */
185 /* Return the size of this object in well known binary */
186 /* representation including the byte order, and type information. */
187 /************************************************************************/
188
189 size_t OGRSimpleCurve::WkbSize() const
190
191 {
192 return 5 + 4 + 8 * static_cast<size_t>(nPointCount) * CoordinateDimension();
193 }
194
195 //! @cond Doxygen_Suppress
196
197 /************************************************************************/
198 /* Make2D() */
199 /************************************************************************/
200
201 void OGRSimpleCurve::Make2D()
202
203 {
204 if( padfZ != nullptr )
205 {
206 CPLFree( padfZ );
207 padfZ = nullptr;
208 }
209 flags &= ~OGR_G_3D;
210 }
211
212 /************************************************************************/
213 /* Make3D() */
214 /************************************************************************/
215
216 void OGRSimpleCurve::Make3D()
217
218 {
219 if( padfZ == nullptr )
220 {
221 if( nPointCount == 0 )
222 padfZ =
223 static_cast<double *>(VSI_CALLOC_VERBOSE(sizeof(double), 1));
224 else
225 padfZ = static_cast<double *>(VSI_CALLOC_VERBOSE(
226 sizeof(double), nPointCount));
227 if( padfZ == nullptr )
228 {
229 flags &= ~OGR_G_3D;
230 CPLError(CE_Failure, CPLE_AppDefined,
231 "OGRSimpleCurve::Make3D() failed");
232 return;
233 }
234 }
235 flags |= OGR_G_3D;
236 }
237
238 /************************************************************************/
239 /* RemoveM() */
240 /************************************************************************/
241
242 void OGRSimpleCurve::RemoveM()
243
244 {
245 if( padfM != nullptr )
246 {
247 CPLFree( padfM );
248 padfM = nullptr;
249 }
250 flags &= ~OGR_G_MEASURED;
251 }
252
253 /************************************************************************/
254 /* AddM() */
255 /************************************************************************/
256
257 void OGRSimpleCurve::AddM()
258
259 {
260 if( padfM == nullptr )
261 {
262 if( nPointCount == 0 )
263 padfM =
264 static_cast<double *>(VSI_CALLOC_VERBOSE(sizeof(double), 1));
265 else
266 padfM = static_cast<double *>(
267 VSI_CALLOC_VERBOSE(sizeof(double), nPointCount));
268 if( padfM == nullptr )
269 {
270 flags &= ~OGR_G_MEASURED;
271 CPLError(CE_Failure, CPLE_AppDefined,
272 "OGRSimpleCurve::AddM() failed");
273 return;
274 }
275 }
276 flags |= OGR_G_MEASURED;
277 }
278
279 //! @endcond
280
281 /************************************************************************/
282 /* getPoint() */
283 /************************************************************************/
284
285 /**
286 * \brief Fetch a point in line string.
287 *
288 * This method relates to the SFCOM ILineString::get_Point() method.
289 *
290 * @param i the vertex to fetch, from 0 to getNumPoints()-1.
291 * @param poPoint a point to initialize with the fetched point.
292 */
293
294 void OGRSimpleCurve::getPoint( int i, OGRPoint * poPoint ) const
295
296 {
297 CPLAssert( i >= 0 );
298 CPLAssert( i < nPointCount );
299 CPLAssert( poPoint != nullptr );
300
301 poPoint->setX( paoPoints[i].x );
302 poPoint->setY( paoPoints[i].y );
303
304 if( (flags & OGR_G_3D) && padfZ != nullptr )
305 poPoint->setZ( padfZ[i] );
306 if( (flags & OGR_G_MEASURED) && padfM != nullptr )
307 poPoint->setM( padfM[i] );
308 }
309
_exportToWkb(OGRwkbByteOrder eByteOrder,int _flags,unsigned char * pabyData) const310 /**
311 * \fn int OGRSimpleCurve::getNumPoints() const;
312 *
313 * \brief Fetch vertex count.
314 *
315 * Returns the number of vertices in the line string.
316 *
317 * @return vertex count.
318 */
319
320 /**
321 * \fn double OGRSimpleCurve::getX( int iVertex ) const;
322 *
323 * \brief Get X at vertex.
324 *
325 * Returns the X value at the indicated vertex. If iVertex is out of range a
326 * crash may occur, no internal range checking is performed.
327 *
328 * @param iVertex the vertex to return, between 0 and getNumPoints()-1.
329 *
330 * @return X value.
331 */
332
333 /**
334 * \fn double OGRSimpleCurve::getY( int iVertex ) const;
335 *
336 * \brief Get Y at vertex.
337 *
338 * Returns the Y value at the indicated vertex. If iVertex is out of range a
339 * crash may occur, no internal range checking is performed.
340 *
341 * @param iVertex the vertex to return, between 0 and getNumPoints()-1.
342 *
343 * @return X value.
344 */
345
346 /************************************************************************/
347 /* getZ() */
348 /************************************************************************/
349
350 /**
351 * \brief Get Z at vertex.
352 *
353 * Returns the Z (elevation) value at the indicated vertex. If no Z
354 * value is available, 0.0 is returned. If iVertex is out of range a
355 * crash may occur, no internal range checking is performed.
356 *
357 * @param iVertex the vertex to return, between 0 and getNumPoints()-1.
358 *
359 * @return Z value.
360 */
361
362 double OGRSimpleCurve::getZ( int iVertex ) const
363
364 {
365 if( padfZ != nullptr && iVertex >= 0 && iVertex < nPointCount
366 && (flags & OGR_G_3D) )
367 return( padfZ[iVertex] );
368 else
369 return 0.0;
370 }
371
372 /************************************************************************/
373 /* getM() */
374 /************************************************************************/
375
376 /**
377 * \brief Get measure at vertex.
378 *
379 * Returns the M (measure) value at the indicated vertex. If no M
380 * value is available, 0.0 is returned.
381 *
382 * @param iVertex the vertex to return, between 0 and getNumPoints()-1.
383 *
384 * @return M value.
385 */
386
387 double OGRSimpleCurve::getM( int iVertex ) const
388
389 {
390 if( padfM != nullptr && iVertex >= 0 && iVertex < nPointCount
391 && (flags & OGR_G_MEASURED) )
392 return( padfM[iVertex] );
393 else
394 return 0.0;
395 }
_WkbSize(int _flags) const396
397 /************************************************************************/
398 /* setNumPoints() */
399 /************************************************************************/
400
401 /**
402 * \brief Set number of points in geometry.
403 *
404 * This method primary exists to preset the number of points in a linestring
405 * geometry before setPoint() is used to assign them to avoid reallocating
406 * the array larger with each call to addPoint().
407 *
408 * This method has no SFCOM analog.
409 *
410 * @param nNewPointCount the new number of points for geometry.
411 * @param bZeroizeNewContent whether to set to zero the new elements of arrays
412 * that are extended.
413 */
414
415 void OGRSimpleCurve::setNumPoints( int nNewPointCount, int bZeroizeNewContent )
416
417 {
418 CPLAssert( nNewPointCount >= 0 );
419
420 if( nNewPointCount == 0 )
421 {
422 CPLFree( paoPoints );
423 paoPoints = nullptr;
424
425 CPLFree( padfZ );
426 padfZ = nullptr;
427
428 CPLFree( padfM );
429 padfM = nullptr;
430
431 nPointCount = 0;
432 return;
433 }
434
435 if( nNewPointCount > nPointCount )
436 {
437 // Overflow of sizeof(OGRRawPoint) * nNewPointCount can only occur on
438 // 32 bit, but we don't really want to allocate 2 billion points even on
439 // 64 bit...
440 if( nNewPointCount > std::numeric_limits<int>::max() /
441 static_cast<int>(sizeof(OGRRawPoint)) )
442 {
443 CPLError(CE_Failure, CPLE_IllegalArg, "Too big point count.");
444 return;
445 }
446 OGRRawPoint* paoNewPoints = static_cast<OGRRawPoint *>(
447 VSI_REALLOC_VERBOSE(paoPoints,
448 sizeof(OGRRawPoint) * nNewPointCount));
449 if( paoNewPoints == nullptr )
450 {
451 return;
452 }
453 paoPoints = paoNewPoints;
454
455 if( bZeroizeNewContent )
456 {
457 // gcc 8.0 (dev) complains about -Wclass-memaccess since
458 // OGRRawPoint() has a constructor. So use a void* pointer. Doing
459 // the memset() here is correct since the constructor sets to 0. We
460 // could instead use a std::fill(), but at every other place, we
461 // treat this class as a regular POD (see above use of realloc())
462 void* dest = static_cast<void*>(paoPoints + nPointCount);
463 memset( dest,
464 0, sizeof(OGRRawPoint) * (nNewPointCount - nPointCount) );
465 }
466
467 if( flags & OGR_G_3D )
468 {
469 double* padfNewZ = static_cast<double *>(
470 VSI_REALLOC_VERBOSE(padfZ, sizeof(double) * nNewPointCount));
471 if( padfNewZ == nullptr )
472 {
473 return;
474 }
475 padfZ = padfNewZ;
476 if( bZeroizeNewContent )
477 memset( padfZ + nPointCount, 0,
478 sizeof(double) * (nNewPointCount - nPointCount) );
479 }
480
481 if( flags & OGR_G_MEASURED )
482 {
483 double* padfNewM = static_cast<double *>(
484 VSI_REALLOC_VERBOSE(padfM, sizeof(double) * nNewPointCount));
485 if( padfNewM == nullptr )
486 {
487 return;
488 }
489 padfM = padfNewM;
490 if( bZeroizeNewContent )
491 memset( padfM + nPointCount, 0,
492 sizeof(double) * (nNewPointCount - nPointCount) );
493 }
494 }
495
496 nPointCount = nNewPointCount;
497 }
498
499 /************************************************************************/
500 /* setPoint() */
501 /************************************************************************/
502
503 /**
504 * \brief Set the location of a vertex in line string.
505 *
506 * If iPoint is larger than the number of necessary the number of existing
507 * points in the line string, the point count will be increased to
508 * accommodate the request.
509 *
510 * There is no SFCOM analog to this method.
511 *
512 * @param iPoint the index of the vertex to assign (zero based).
513 * @param poPoint the value to assign to the vertex.
514 */
515
516 void OGRSimpleCurve::setPoint( int iPoint, OGRPoint * poPoint )
517
518 {
519 if( (flags & OGR_G_3D) && (flags & OGR_G_MEASURED) )
520 setPoint( iPoint, poPoint->getX(), poPoint->getY(), poPoint->getZ(), poPoint->getM() );
521 else if( flags & OGR_G_3D )
522 setPoint( iPoint, poPoint->getX(), poPoint->getY(), poPoint->getZ() );
523 else if( flags & OGR_G_MEASURED )
524 setPointM( iPoint, poPoint->getX(), poPoint->getY(), poPoint->getM() );
525 else
526 setPoint( iPoint, poPoint->getX(), poPoint->getY() );
527 }
528
529 /************************************************************************/
530 /* setPoint() */
531 /************************************************************************/
532
533 /**
534 * \brief Set the location of a vertex in line string.
535 *
536 * If iPoint is larger than the number of necessary the number of existing
537 * points in the line string, the point count will be increased to
538 * accommodate the request.
539 *
540 * There is no SFCOM analog to this method.
541 *
542 * @param iPoint the index of the vertex to assign (zero based).
543 * @param xIn input X coordinate to assign.
544 * @param yIn input Y coordinate to assign.
545 * @param zIn input Z coordinate to assign (defaults to zero).
546 */
547
548 void OGRSimpleCurve::setPoint( int iPoint, double xIn, double yIn, double zIn )
reverseWindingOrder()549
550 {
551 if( !(flags & OGR_G_3D) )
552 Make3D();
553
554 if( iPoint >= nPointCount )
555 {
556 setNumPoints( iPoint+1 );
557 if( nPointCount < iPoint + 1 )
558 return;
559 }
560 #ifdef DEBUG
561 if( paoPoints == nullptr )
562 return;
563 #endif
564
565 paoPoints[iPoint].x = xIn;
566 paoPoints[iPoint].y = yIn;
567
568 if( padfZ != nullptr )
569 {
570 padfZ[iPoint] = zIn;
571 }
572 }
573
574 /**
575 * \brief Set the location of a vertex in line string.
576 *
577 * If iPoint is larger than the number of necessary the number of existing
578 * points in the line string, the point count will be increased to
579 * accommodate the request.
580 *
581 * There is no SFCOM analog to this method.
582 *
583 * @param iPoint the index of the vertex to assign (zero based).
584 * @param xIn input X coordinate to assign.
585 * @param yIn input Y coordinate to assign.
586 * @param mIn input M coordinate to assign (defaults to zero).
587 */
588
589 void OGRSimpleCurve::setPointM( int iPoint, double xIn, double yIn, double mIn )
590
591 {
592 if( !(flags & OGR_G_MEASURED) )
593 AddM();
594
isPointInRing(const OGRPoint * poPoint,int bTestEnvelope) const595 if( iPoint >= nPointCount )
596 {
597 setNumPoints( iPoint+1 );
598 if( nPointCount < iPoint + 1 )
599 return;
600 }
601 #ifdef DEBUG
602 if( paoPoints == nullptr )
603 return;
604 #endif
605
606 paoPoints[iPoint].x = xIn;
607 paoPoints[iPoint].y = yIn;
608
609 if( padfM != nullptr )
610 {
611 padfM[iPoint] = mIn;
612 }
613 }
614
615 /**
616 * \brief Set the location of a vertex in line string.
617 *
618 * If iPoint is larger than the number of necessary the number of existing
619 * points in the line string, the point count will be increased to
620 * accommodate the request.
621 *
622 * There is no SFCOM analog to this method.
623 *
624 * @param iPoint the index of the vertex to assign (zero based).
625 * @param xIn input X coordinate to assign.
626 * @param yIn input Y coordinate to assign.
627 * @param zIn input Z coordinate to assign (defaults to zero).
628 * @param mIn input M coordinate to assign (defaults to zero).
629 */
630
631 void OGRSimpleCurve::setPoint( int iPoint, double xIn, double yIn,
632 double zIn, double mIn )
633
634 {
635 if( !(flags & OGR_G_3D) )
636 Make3D();
637 if( !(flags & OGR_G_MEASURED) )
638 AddM();
639
640 if( iPoint >= nPointCount )
641 {
642 setNumPoints( iPoint+1 );
643 if( nPointCount < iPoint + 1 )
644 return;
645 }
646 #ifdef DEBUG
647 if( paoPoints == nullptr )
648 return;
649 #endif
650
651 paoPoints[iPoint].x = xIn;
652 paoPoints[iPoint].y = yIn;
653
654 if( padfZ != nullptr )
655 {
656 padfZ[iPoint] = zIn;
657 }
658 if( padfM != nullptr )
659 {
660 padfM[iPoint] = mIn;
661 }
662 }
663
664 /**
665 * \brief Set the location of a vertex in line string.
666 *
667 * If iPoint is larger than the number of necessary the number of existing
668 * points in the line string, the point count will be increased to
669 * accommodate the request.
670 *
671 * There is no SFCOM analog to this method.
672 *
673 * @param iPoint the index of the vertex to assign (zero based).
674 * @param xIn input X coordinate to assign.
675 * @param yIn input Y coordinate to assign.
isPointOnRingBoundary(const OGRPoint * poPoint,int bTestEnvelope) const676 */
677
678 void OGRSimpleCurve::setPoint( int iPoint, double xIn, double yIn )
679
680 {
681 if( iPoint >= nPointCount )
682 {
683 setNumPoints( iPoint+1 );
684 if( nPointCount < iPoint + 1 || paoPoints == nullptr )
685 return;
686 }
687
688 paoPoints[iPoint].x = xIn;
689 paoPoints[iPoint].y = yIn;
690 }
691
692 /************************************************************************/
693 /* setZ() */
694 /************************************************************************/
695
696 /**
697 * \brief Set the Z of a vertex in line string.
698 *
699 * If iPoint is larger than the number of necessary the number of existing
700 * points in the line string, the point count will be increased to
701 * accommodate the request.
702 *
703 * There is no SFCOM analog to this method.
704 *
705 * @param iPoint the index of the vertex to assign (zero based).
706 * @param zIn input Z coordinate to assign.
707 */
708
709 void OGRSimpleCurve::setZ( int iPoint, double zIn )
710 {
711 if( getCoordinateDimension() == 2 )
712 Make3D();
713
714 if( iPoint >= nPointCount )
715 {
716 setNumPoints( iPoint+1 );
717 if( nPointCount < iPoint + 1 )
718 return;
719 }
720
721 if( padfZ != nullptr )
722 padfZ[iPoint] = zIn;
723 }
724
725 /************************************************************************/
726 /* setM() */
727 /************************************************************************/
728
729 /**
730 * \brief Set the M of a vertex in line string.
731 *
732 * If iPoint is larger than the number of necessary the number of existing
733 * points in the line string, the point count will be increased to
734 * accommodate the request.
735 *
736 * There is no SFCOM analog to this method.
737 *
738 * @param iPoint the index of the vertex to assign (zero based).
739 * @param mIn input M coordinate to assign.
740 */
741
742 void OGRSimpleCurve::setM( int iPoint, double mIn )
743 {
744 if( !(flags & OGR_G_MEASURED) )
745 AddM();
746
747 if( iPoint >= nPointCount )
748 {
749 setNumPoints( iPoint+1 );
750 if( nPointCount < iPoint + 1 )
751 return;
752 }
753
754 if( padfM != nullptr )
755 padfM[iPoint] = mIn;
756 }
transform(OGRCoordinateTransformation * poCT)757
758 /************************************************************************/
759 /* addPoint() */
760 /************************************************************************/
761
762 /**
763 * \brief Add a point to a line string.
764 *
765 * The vertex count of the line string is increased by one, and assigned from
766 * the passed location value.
767 *
768 * There is no SFCOM analog to this method.
769 *
770 * @param poPoint the point to assign to the new vertex.
771 */
772
773 void OGRSimpleCurve::addPoint( const OGRPoint * poPoint )
774
775 {
776 if( poPoint->Is3D() && poPoint->IsMeasured() )
777 setPoint( nPointCount, poPoint->getX(), poPoint->getY(), poPoint->getZ(), poPoint->getM() );
778 else if( poPoint->Is3D() )
779 setPoint( nPointCount, poPoint->getX(), poPoint->getY(), poPoint->getZ() );
780 else if( poPoint->IsMeasured() )
781 setPointM( nPointCount, poPoint->getX(), poPoint->getY(), poPoint->getM() );
782 else
783 setPoint( nPointCount, poPoint->getX(), poPoint->getY() );
784 }
785
786 /************************************************************************/
787 /* addPoint() */
788 /************************************************************************/
789
790 /**
791 * \brief Add a point to a line string.
792 *
CastToLineString(OGRLinearRing * poLR)793 * The vertex count of the line string is increased by one, and assigned from
794 * the passed location value.
795 *
796 * There is no SFCOM analog to this method.
797 *
798 * @param x the X coordinate to assign to the new point.
799 * @param y the Y coordinate to assign to the new point.
800 * @param z the Z coordinate to assign to the new point (defaults to zero).
801 * @param m the M coordinate to assign to the new point (defaults to zero).
802 */
803
804 void OGRSimpleCurve::addPoint( double x, double y, double z, double m )
805
806 {
807 setPoint( nPointCount, x, y, z, m );
808 }
809
810 /**
811 * \brief Add a point to a line string.
812 *
813 * The vertex count of the line string is increased by one, and assigned from
814 * the passed location value.
815 *
816 * There is no SFCOM analog to this method.
CasterToLinearRing(OGRCurve * poCurve)817 *
818 * @param x the X coordinate to assign to the new point.
819 * @param y the Y coordinate to assign to the new point.
820 * @param z the Z coordinate to assign to the new point (defaults to zero).
821 */
822
823 void OGRSimpleCurve::addPoint( double x, double y, double z )
824
825 {
826 setPoint( nPointCount, x, y, z );
827 }
828
829 /**
830 * \brief Add a point to a line string.
831 *
832 * The vertex count of the line string is increased by one, and assigned from
833 * the passed location value.
834 *
835 * There is no SFCOM analog to this method.
836 *
837 * @param x the X coordinate to assign to the new point.
838 * @param y the Y coordinate to assign to the new point.
839 */
840
841 void OGRSimpleCurve::addPoint( double x, double y )
842
843 {
844 setPoint( nPointCount, x, y );
845 }
846
847 /**
848 * \brief Add a point to a line string.
849 *
850 * The vertex count of the line string is increased by one, and assigned from
851 * the passed location value.
852 *
853 * There is no SFCOM analog to this method.
854 *
855 * @param x the X coordinate to assign to the new point.
856 * @param y the Y coordinate to assign to the new point.
857 * @param m the M coordinate to assign to the new point.
858 */
859
860 void OGRSimpleCurve::addPointM( double x, double y, double m )
861
862 {
863 setPointM( nPointCount, x, y, m );
864 }
865
866 /************************************************************************/
867 /* removePoint() */
868 /************************************************************************/
869
870 /**
871 * \brief Remove a point from a line string.
872 *
873 * There is no SFCOM analog to this method.
874 *
875 * @param nIndex Point index
876 * @since GDAL 3.3
877 */
878
879 bool OGRSimpleCurve::removePoint( int nIndex )
880 {
881 if( nIndex < 0 || nIndex >= nPointCount )
882 return false;
883 if( nIndex < nPointCount - 1 )
884 {
885 memmove( paoPoints + nIndex, paoPoints + nIndex + 1,
886 sizeof(OGRRawPoint) * (nPointCount - 1 - nIndex));
887 if( padfZ )
888 {
889 memmove( padfZ + nIndex, padfZ + nIndex + 1,
890 sizeof(double) * (nPointCount - 1 - nIndex));
891 }
892 if( padfM )
893 {
894 memmove( padfM + nIndex, padfM + nIndex + 1,
895 sizeof(double) * (nPointCount - 1 - nIndex));
896 }
897 }
898 nPointCount --;
899 return true;
900 }
901
902
903 /************************************************************************/
904 /* setPointsM() */
905 /************************************************************************/
906
907 /**
908 * \brief Assign all points in a line string.
909 *
910 * This method clears any existing points assigned to this line string,
911 * and assigns a whole new set. It is the most efficient way of assigning
912 * the value of a line string.
913 *
914 * There is no SFCOM analog to this method.
915 *
916 * @param nPointsIn number of points being passed in paoPointsIn
917 * @param paoPointsIn list of points being assigned.
918 * @param padfMIn the M values that go with the points.
919 */
920
921 void OGRSimpleCurve::setPointsM( int nPointsIn,
922 const OGRRawPoint * paoPointsIn,
923 const double * padfMIn )
924
925 {
926 setNumPoints( nPointsIn, FALSE );
927 if( nPointCount < nPointsIn
928 #ifdef DEBUG
929 || paoPoints == nullptr
930 #endif
931 )
932 return;
933
934 if( nPointsIn )
935 memcpy( paoPoints, paoPointsIn, sizeof(OGRRawPoint) * nPointsIn);
936
937 /* -------------------------------------------------------------------- */
938 /* Check measures. */
939 /* -------------------------------------------------------------------- */
940 if( padfMIn == nullptr && (flags & OGR_G_MEASURED) )
941 {
942 RemoveM();
943 }
944 else if( padfMIn )
945 {
946 AddM();
947 if( padfM && nPointsIn )
948 memcpy( padfM, padfMIn, sizeof(double) * nPointsIn );
949 }
950 }
951
952 /************************************************************************/
953 /* setPoints() */
954 /************************************************************************/
955
956 /**
957 * \brief Assign all points in a line string.
958 *
959 * This method clears any existing points assigned to this line string,
960 * and assigns a whole new set. It is the most efficient way of assigning
961 * the value of a line string.
962 *
963 * There is no SFCOM analog to this method.
964 *
965 * @param nPointsIn number of points being passed in paoPointsIn
966 * @param paoPointsIn list of points being assigned.
967 * @param padfZIn the Z values that go with the points.
968 * @param padfMIn the M values that go with the points.
969 */
970
971 void OGRSimpleCurve::setPoints( int nPointsIn,
972 const OGRRawPoint * paoPointsIn,
973 const double * padfZIn,
974 const double * padfMIn )
975
976 {
977 setNumPoints( nPointsIn, FALSE );
978 if( nPointCount < nPointsIn
979 #ifdef DEBUG
980 || paoPoints == nullptr
981 #endif
982 )
983 return;
984
985 if( nPointsIn )
986 memcpy( paoPoints, paoPointsIn, sizeof(OGRRawPoint) * nPointsIn);
987
988 /* -------------------------------------------------------------------- */
989 /* Check 2D/3D. */
990 /* -------------------------------------------------------------------- */
991 if( padfZIn == nullptr && getCoordinateDimension() > 2 )
992 {
993 Make2D();
994 }
995 else if( padfZIn )
996 {
997 Make3D();
998 if( padfZ && nPointsIn )
999 memcpy( padfZ, padfZIn, sizeof(double) * nPointsIn );
1000 }
1001
1002 /* -------------------------------------------------------------------- */
1003 /* Check measures. */
1004 /* -------------------------------------------------------------------- */
1005 if( padfMIn == nullptr && (flags & OGR_G_MEASURED) )
1006 {
1007 RemoveM();
1008 }
1009 else if( padfMIn )
1010 {
1011 AddM();
1012 if( padfM && nPointsIn )
1013 memcpy( padfM, padfMIn, sizeof(double) * nPointsIn );
1014 }
1015 }
1016
1017 /************************************************************************/
1018 /* setPoints() */
1019 /************************************************************************/
1020
1021 /**
1022 * \brief Assign all points in a line string.
1023 *
1024 * This method clears any existing points assigned to this line string,
1025 * and assigns a whole new set. It is the most efficient way of assigning
1026 * the value of a line string.
1027 *
1028 * There is no SFCOM analog to this method.
1029 *
1030 * @param nPointsIn number of points being passed in paoPointsIn
1031 * @param paoPointsIn list of points being assigned.
1032 * @param padfZIn the Z values that go with the points (optional, may be NULL).
1033 */
1034
1035 void OGRSimpleCurve::setPoints( int nPointsIn,
1036 const OGRRawPoint * paoPointsIn,
1037 const double * padfZIn )
1038
1039 {
1040 setNumPoints( nPointsIn, FALSE );
1041 if( nPointCount < nPointsIn
1042 #ifdef DEBUG
1043 || paoPoints == nullptr
1044 #endif
1045 )
1046 return;
1047
1048 if( nPointsIn )
1049 memcpy( paoPoints, paoPointsIn, sizeof(OGRRawPoint) * nPointsIn);
1050
1051 /* -------------------------------------------------------------------- */
1052 /* Check 2D/3D. */
1053 /* -------------------------------------------------------------------- */
1054 if( padfZIn == nullptr && getCoordinateDimension() > 2 )
1055 {
1056 Make2D();
1057 }
1058 else if( padfZIn )
1059 {
1060 Make3D();
1061 if( padfZ && nPointsIn )
1062 memcpy( padfZ, padfZIn, sizeof(double) * nPointsIn );
1063 }
1064 }
1065
1066 /************************************************************************/
1067 /* setPoints() */
1068 /************************************************************************/
1069
1070 /**
1071 * \brief Assign all points in a line string.
1072 *
1073 * This method clear any existing points assigned to this line string,
1074 * and assigns a whole new set.
1075 *
1076 * There is no SFCOM analog to this method.
1077 *
1078 * @param nPointsIn number of points being passed in padfX and padfY.
1079 * @param padfX list of X coordinates of points being assigned.
1080 * @param padfY list of Y coordinates of points being assigned.
1081 * @param padfZIn list of Z coordinates of points being assigned (defaults to
1082 * NULL for 2D objects).
1083 */
1084
1085 void OGRSimpleCurve::setPoints( int nPointsIn,
1086 const double * padfX,
1087 const double * padfY,
1088 const double * padfZIn )
1089
1090 {
1091 /* -------------------------------------------------------------------- */
1092 /* Check 2D/3D. */
1093 /* -------------------------------------------------------------------- */
1094 if( padfZIn == nullptr )
1095 Make2D();
1096 else
1097 Make3D();
1098
1099 /* -------------------------------------------------------------------- */
1100 /* Assign values. */
1101 /* -------------------------------------------------------------------- */
1102 setNumPoints( nPointsIn, FALSE );
1103 if( nPointCount < nPointsIn )
1104 return;
1105
1106 for( int i = 0; i < nPointsIn; i++ )
1107 {
1108 paoPoints[i].x = padfX[i];
1109 paoPoints[i].y = padfY[i];
1110 }
1111
1112 if( padfZ == nullptr || !padfZIn || !nPointsIn )
1113 {
1114 return;
1115 }
1116
1117 memcpy( padfZ, padfZIn, sizeof(double) * nPointsIn );
1118 }
1119
1120 /************************************************************************/
1121 /* setPointsM() */
1122 /************************************************************************/
1123
1124 /**
1125 * \brief Assign all points in a line string.
1126 *
1127 * This method clear any existing points assigned to this line string,
1128 * and assigns a whole new set.
1129 *
1130 * There is no SFCOM analog to this method.
1131 *
1132 * @param nPointsIn number of points being passed in padfX and padfY.
1133 * @param padfX list of X coordinates of points being assigned.
1134 * @param padfY list of Y coordinates of points being assigned.
1135 * @param padfMIn list of M coordinates of points being assigned.
1136 */
1137
1138 void OGRSimpleCurve::setPointsM( int nPointsIn,
1139 const double * padfX,
1140 const double * padfY,
1141 const double * padfMIn )
1142
1143 {
1144 /* -------------------------------------------------------------------- */
1145 /* Check 2D/3D. */
1146 /* -------------------------------------------------------------------- */
1147 if( padfMIn == nullptr )
1148 RemoveM();
1149 else
1150 AddM();
1151
1152 /* -------------------------------------------------------------------- */
1153 /* Assign values. */
1154 /* -------------------------------------------------------------------- */
1155 setNumPoints( nPointsIn, FALSE );
1156 if( nPointCount < nPointsIn )
1157 return;
1158
1159 for( int i = 0; i < nPointsIn; i++ )
1160 {
1161 paoPoints[i].x = padfX[i];
1162 paoPoints[i].y = padfY[i];
1163 }
1164
1165 if( padfMIn == nullptr || !padfM || !nPointsIn )
1166 {
1167 return;
1168 }
1169
1170 memcpy( padfM, padfMIn, sizeof(double) * nPointsIn );
1171 }
1172
1173 /************************************************************************/
1174 /* setPoints() */
1175 /************************************************************************/
1176
1177 /**
1178 * \brief Assign all points in a line string.
1179 *
1180 * This method clear any existing points assigned to this line string,
1181 * and assigns a whole new set.
1182 *
1183 * There is no SFCOM analog to this method.
1184 *
1185 * @param nPointsIn number of points being passed in padfX and padfY.
1186 * @param padfX list of X coordinates of points being assigned.
1187 * @param padfY list of Y coordinates of points being assigned.
1188 * @param padfZIn list of Z coordinates of points being assigned.
1189 * @param padfMIn list of M coordinates of points being assigned.
1190 */
1191
1192 void OGRSimpleCurve::setPoints( int nPointsIn,
1193 const double * padfX,
1194 const double * padfY,
1195 const double * padfZIn,
1196 const double * padfMIn )
1197
1198 {
1199 /* -------------------------------------------------------------------- */
1200 /* Check 2D/3D. */
1201 /* -------------------------------------------------------------------- */
1202 if( padfZIn == nullptr )
1203 Make2D();
1204 else
1205 Make3D();
1206
1207 /* -------------------------------------------------------------------- */
1208 /* Check measures. */
1209 /* -------------------------------------------------------------------- */
1210 if( padfMIn == nullptr )
1211 RemoveM();
1212 else
1213 AddM();
1214
1215 /* -------------------------------------------------------------------- */
1216 /* Assign values. */
1217 /* -------------------------------------------------------------------- */
1218 setNumPoints( nPointsIn, FALSE );
1219 if( nPointCount < nPointsIn )
1220 return;
1221
1222 for( int i = 0; i < nPointsIn; i++ )
1223 {
1224 paoPoints[i].x = padfX[i];
1225 paoPoints[i].y = padfY[i];
1226 }
1227
1228 if( padfZ != nullptr && padfZIn && nPointsIn )
1229 memcpy( padfZ, padfZIn, sizeof(double) * nPointsIn );
1230 if( padfM != nullptr && padfMIn && nPointsIn )
1231 memcpy( padfM, padfMIn, sizeof(double) * nPointsIn );
1232 }
1233
1234 /************************************************************************/
1235 /* getPoints() */
1236 /************************************************************************/
1237
1238 /**
1239 * \brief Returns all points of line string.
1240 *
1241 * This method copies all points into user list. This list must be at
1242 * least sizeof(OGRRawPoint) * OGRGeometry::getNumPoints() byte in size.
1243 * It also copies all Z coordinates.
1244 *
1245 * There is no SFCOM analog to this method.
1246 *
1247 * @param paoPointsOut a buffer into which the points is written.
1248 * @param padfZOut the Z values that go with the points (optional, may be NULL).
1249 */
1250
1251 void OGRSimpleCurve::getPoints( OGRRawPoint * paoPointsOut,
1252 double * padfZOut ) const
1253 {
1254 if( !paoPointsOut || nPointCount == 0 )
1255 return;
1256
1257 memcpy( paoPointsOut, paoPoints, sizeof(OGRRawPoint) * nPointCount );
1258
1259 /* -------------------------------------------------------------------- */
1260 /* Check 2D/3D. */
1261 /* -------------------------------------------------------------------- */
1262 if( padfZOut )
1263 {
1264 if( padfZ )
1265 memcpy( padfZOut, padfZ, sizeof(double) * nPointCount );
1266 else
1267 memset( padfZOut, 0, sizeof(double) * nPointCount );
1268 }
1269 }
1270
1271 /**
1272 * \brief Returns all points of line string.
1273 *
1274 * This method copies all points into user arrays. The user provides the
1275 * stride between 2 consecutive elements of the array.
1276 *
1277 * On some CPU architectures, care must be taken so that the arrays are properly aligned.
1278 *
1279 * There is no SFCOM analog to this method.
1280 *
1281 * @param pabyX a buffer of at least (nXStride * nPointCount) bytes, may be NULL.
1282 * @param nXStride the number of bytes between 2 elements of pabyX.
1283 * @param pabyY a buffer of at least (nYStride * nPointCount) bytes, may be NULL.
1284 * @param nYStride the number of bytes between 2 elements of pabyY.
1285 * @param pabyZ a buffer of at last size (nZStride * nPointCount) bytes, may be NULL.
1286 * @param nZStride the number of bytes between 2 elements of pabyZ.
1287 * @param pabyM a buffer of at last size (nMStride * nPointCount) bytes, may be NULL.
1288 * @param nMStride the number of bytes between 2 elements of pabyM.
1289 *
1290 * @since OGR 2.1.0
1291 */
1292
1293 void OGRSimpleCurve::getPoints( void* pabyX, int nXStride,
1294 void* pabyY, int nYStride,
1295 void* pabyZ, int nZStride,
1296 void* pabyM, int nMStride ) const
1297 {
1298 if( pabyX != nullptr && nXStride == 0 )
1299 return;
1300 if( pabyY != nullptr && nYStride == 0 )
1301 return;
1302 if( pabyZ != nullptr && nZStride == 0 )
1303 return;
1304 if( pabyM != nullptr && nMStride == 0 )
1305 return;
1306 if( nXStride == sizeof(OGRRawPoint) &&
1307 nYStride == sizeof(OGRRawPoint) &&
1308 static_cast<char *>(pabyY) ==
1309 static_cast<char *>(pabyX) + sizeof(double) &&
1310 (pabyZ == nullptr || nZStride == sizeof(double)) )
1311 {
1312 getPoints(static_cast<OGRRawPoint *>(pabyX),
1313 static_cast<double *>(pabyZ));
1314 }
1315 else
1316 {
1317 for( int i = 0; i < nPointCount; i++ )
1318 {
1319 if( pabyX ) *reinterpret_cast<double*>(static_cast<char*>(pabyX) + i * nXStride) = paoPoints[i].x;
1320 if( pabyY ) *reinterpret_cast<double*>(static_cast<char*>(pabyY) + i * nYStride) = paoPoints[i].y;
1321 }
1322
1323 if( pabyZ )
1324 {
1325 if( nZStride == sizeof(double) )
1326 {
1327 if( padfZ )
1328 memcpy( pabyZ, padfZ, sizeof(double) * nPointCount );
1329 else
1330 memset( pabyZ, 0, sizeof(double) * nPointCount );
1331 }
1332 else
1333 {
1334 for( int i = 0; i < nPointCount; i++ )
1335 {
1336 *reinterpret_cast<double*>(static_cast<char*>(pabyZ) + i * nZStride) = (padfZ) ? padfZ[i] : 0.0;
1337 }
1338 }
1339 }
1340 }
1341 if( pabyM )
1342 {
1343 if( nMStride == sizeof(double) )
1344 {
1345 if( padfM )
1346 memcpy( pabyM, padfM, sizeof(double) * nPointCount );
1347 else
1348 memset( pabyM, 0, sizeof(double) * nPointCount );
1349 }
1350 else
1351 {
1352 for( int i = 0; i < nPointCount; i++ )
1353 {
1354 *reinterpret_cast<double*>(static_cast<char*>(pabyM) + i * nMStride) = (padfM) ? padfM[i] : 0.0;
1355 }
1356 }
1357 }
1358 }
1359
1360 /************************************************************************/
1361 /* reversePoints() */
1362 /************************************************************************/
1363
1364 /**
1365 * \brief Reverse point order.
1366 *
1367 * This method updates the points in this line string in place
1368 * reversing the point ordering (first for last, etc).
1369 */
1370
1371 void OGRSimpleCurve::reversePoints()
1372
1373 {
1374 for( int i = 0; i < nPointCount/2; i++ )
1375 {
1376 std::swap(paoPoints[i], paoPoints[nPointCount-i-1]);
1377 if( padfZ )
1378 {
1379 std::swap(padfZ[i], padfZ[nPointCount-i-1]);
1380 }
1381
1382 if( padfM )
1383 {
1384 std::swap(padfM[i], padfM[nPointCount-i-1]);
1385 }
1386 }
1387 }
1388
1389 /************************************************************************/
1390 /* addSubLineString() */
1391 /************************************************************************/
1392
1393 /**
1394 * \brief Add a segment of another linestring to this one.
1395 *
1396 * Adds the request range of vertices to the end of this line string
1397 * in an efficient manner. If the nStartVertex is larger than the
1398 * nEndVertex then the vertices will be reversed as they are copied.
1399 *
1400 * @param poOtherLine the other OGRLineString.
1401 * @param nStartVertex the first vertex to copy, defaults to 0 to start
1402 * with the first vertex in the other linestring.
1403 * @param nEndVertex the last vertex to copy, defaults to -1 indicating
1404 * the last vertex of the other line string.
1405 */
1406
1407 void OGRSimpleCurve::addSubLineString( const OGRLineString *poOtherLine,
1408 int nStartVertex, int nEndVertex )
1409
1410 {
1411 int nOtherLineNumPoints = poOtherLine->getNumPoints();
1412 if( nOtherLineNumPoints == 0 )
1413 return;
1414
1415 /* -------------------------------------------------------------------- */
1416 /* Do a bit of argument defaulting and validation. */
1417 /* -------------------------------------------------------------------- */
1418 if( nEndVertex == -1 )
1419 nEndVertex = nOtherLineNumPoints - 1;
1420
1421 if( nStartVertex < 0 || nEndVertex < 0
1422 || nStartVertex >= nOtherLineNumPoints
1423 || nEndVertex >= nOtherLineNumPoints )
1424 {
1425 CPLAssert( false );
1426 return;
1427 }
1428
1429 /* -------------------------------------------------------------------- */
1430 /* Grow this linestring to hold the additional points. */
1431 /* -------------------------------------------------------------------- */
1432 int nOldPoints = nPointCount;
1433 int nPointsToAdd = std::abs(nEndVertex - nStartVertex) + 1;
1434
1435 setNumPoints( nPointsToAdd + nOldPoints, FALSE );
1436 if( nPointCount < nPointsToAdd + nOldPoints
1437 #ifdef DEBUG
1438 || paoPoints == nullptr
1439 #endif
1440 )
1441 return;
1442
1443 /* -------------------------------------------------------------------- */
1444 /* Copy the x/y points - forward copies use memcpy. */
1445 /* -------------------------------------------------------------------- */
1446 if( nEndVertex >= nStartVertex )
1447 {
1448 memcpy( paoPoints + nOldPoints,
1449 poOtherLine->paoPoints + nStartVertex,
1450 sizeof(OGRRawPoint) * nPointsToAdd );
1451 if( poOtherLine->padfZ != nullptr )
1452 {
1453 Make3D();
1454 if( padfZ != nullptr )
1455 {
1456 memcpy( padfZ + nOldPoints, poOtherLine->padfZ + nStartVertex,
1457 sizeof(double) * nPointsToAdd );
1458 }
1459 }
1460 if( poOtherLine->padfM != nullptr )
1461 {
1462 AddM();
1463 if( padfM != nullptr )
1464 {
1465 memcpy( padfM + nOldPoints, poOtherLine->padfM + nStartVertex,
1466 sizeof(double) * nPointsToAdd );
1467 }
1468 }
1469 }
1470
1471 /* -------------------------------------------------------------------- */
1472 /* Copy the x/y points - reverse copies done double by double. */
1473 /* -------------------------------------------------------------------- */
1474 else
1475 {
1476 for( int i = 0; i < nPointsToAdd; i++ )
1477 {
1478 paoPoints[i+nOldPoints].x =
1479 poOtherLine->paoPoints[nStartVertex-i].x;
1480 paoPoints[i+nOldPoints].y =
1481 poOtherLine->paoPoints[nStartVertex-i].y;
1482 }
1483
1484 if( poOtherLine->padfZ != nullptr )
1485 {
1486 Make3D();
1487 if( padfZ != nullptr )
1488 {
1489 for( int i = 0; i < nPointsToAdd; i++ )
1490 {
1491 padfZ[i+nOldPoints] = poOtherLine->padfZ[nStartVertex-i];
1492 }
1493 }
1494 }
1495 if( poOtherLine->padfM != nullptr )
1496 {
1497 AddM();
1498 if( padfM != nullptr )
1499 {
1500 for( int i = 0; i < nPointsToAdd; i++ )
1501 {
1502 padfM[i+nOldPoints] = poOtherLine->padfM[nStartVertex-i];
1503 }
1504 }
1505 }
1506 }
1507 }
1508
1509 /************************************************************************/
1510 /* importFromWkb() */
1511 /* */
1512 /* Initialize from serialized stream in well known binary */
1513 /* format. */
1514 /************************************************************************/
1515
1516 OGRErr OGRSimpleCurve::importFromWkb( const unsigned char *pabyData,
1517 size_t nSize,
1518 OGRwkbVariant eWkbVariant,
1519 size_t& nBytesConsumedOut )
1520
1521 {
1522 OGRwkbByteOrder eByteOrder;
1523 size_t nDataOffset = 0;
1524 int nNewNumPoints = 0;
1525
1526 nBytesConsumedOut = 0;
1527 OGRErr eErr = importPreambleOfCollectionFromWkb( pabyData,
1528 nSize,
1529 nDataOffset,
1530 eByteOrder,
1531 16,
1532 nNewNumPoints,
1533 eWkbVariant );
1534 if( eErr != OGRERR_NONE )
1535 return eErr;
1536
1537 // Check if the wkb stream buffer is big enough to store
1538 // fetched number of points.
1539 const int dim = CoordinateDimension();
1540 const size_t nPointSize = dim*sizeof(double);
1541 if( nNewNumPoints < 0 ||
1542 static_cast<size_t>(nNewNumPoints) > std::numeric_limits<size_t>::max() / nPointSize )
1543 {
1544 return OGRERR_CORRUPT_DATA;
1545 }
1546 const size_t nBufferMinSize = nPointSize * nNewNumPoints;
1547
1548 if( nSize != static_cast<size_t>(-1) && nBufferMinSize > nSize )
1549 {
1550 CPLError( CE_Failure, CPLE_AppDefined,
1551 "Length of input WKB is too small" );
1552 return OGRERR_NOT_ENOUGH_DATA;
1553 }
1554
1555 setNumPoints( nNewNumPoints, FALSE );
1556 if( nPointCount < nNewNumPoints )
1557 return OGRERR_FAILURE;
1558
1559 nBytesConsumedOut = 9 + 8 * static_cast<size_t>(nPointCount) *
1560 (2 + ((flags & OGR_G_3D) ? 1 : 0)+
1561 ((flags & OGR_G_MEASURED) ? 1 : 0));
1562
1563 /* -------------------------------------------------------------------- */
1564 /* Get the vertex. */
1565 /* -------------------------------------------------------------------- */
1566 if( (flags & OGR_G_3D) && (flags & OGR_G_MEASURED) )
1567 {
1568 for( size_t i = 0; i < static_cast<size_t>(nPointCount); i++ )
1569 {
1570 memcpy( paoPoints + i, pabyData + 9 + i*32, 16 );
1571 memcpy( padfZ + i, pabyData + 9 + 16 + i*32, 8 );
1572 memcpy( padfM + i, pabyData + 9 + 24 + i*32, 8 );
1573 }
1574 }
1575 else if( flags & OGR_G_MEASURED )
1576 {
1577 for( size_t i = 0; i < static_cast<size_t>(nPointCount); i++ )
1578 {
1579 memcpy( paoPoints + i, pabyData + 9 + i*24, 16 );
1580 memcpy( padfM + i, pabyData + 9 + 16 + i*24, 8 );
1581 }
1582 }
1583 else if( flags & OGR_G_3D )
1584 {
1585 for( size_t i = 0; i < static_cast<size_t>(nPointCount); i++ )
1586 {
1587 memcpy( paoPoints + i, pabyData + 9 + i*24, 16 );
1588 memcpy( padfZ + i, pabyData + 9 + 16 + i*24, 8 );
1589 }
1590 }
1591 else if( nPointCount )
1592 {
1593 memcpy( paoPoints, pabyData + 9, 16 * static_cast<size_t>(nPointCount) );
1594 }
1595
1596 /* -------------------------------------------------------------------- */
1597 /* Byte swap if needed. */
1598 /* -------------------------------------------------------------------- */
1599 if( OGR_SWAP( eByteOrder ) )
1600 {
1601 for( size_t i = 0; i < static_cast<size_t>(nPointCount); i++ )
1602 {
1603 CPL_SWAPDOUBLE( &(paoPoints[i].x) );
1604 CPL_SWAPDOUBLE( &(paoPoints[i].y) );
1605 }
1606
1607 if( flags & OGR_G_3D )
1608 {
1609 for( size_t i = 0; i < static_cast<size_t>(nPointCount); i++ )
1610 {
1611 CPL_SWAPDOUBLE( padfZ + i );
1612 }
1613 }
1614
1615 if( flags & OGR_G_MEASURED )
1616 {
1617 for( size_t i = 0; i < static_cast<size_t>(nPointCount); i++ )
1618 {
1619 CPL_SWAPDOUBLE( padfM + i );
1620 }
1621 }
1622 }
1623
1624 return OGRERR_NONE;
1625 }
1626
1627 /************************************************************************/
1628 /* exportToWkb() */
1629 /* */
1630 /* Build a well known binary representation of this object. */
1631 /************************************************************************/
1632
1633 OGRErr OGRSimpleCurve::exportToWkb( OGRwkbByteOrder eByteOrder,
1634 unsigned char * pabyData,
1635 OGRwkbVariant eWkbVariant ) const
1636
1637 {
1638 /* -------------------------------------------------------------------- */
1639 /* Set the byte order. */
1640 /* -------------------------------------------------------------------- */
1641 pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER(static_cast<unsigned char>(eByteOrder));
1642
1643 /* -------------------------------------------------------------------- */
1644 /* Set the geometry feature type. */
1645 /* -------------------------------------------------------------------- */
1646 GUInt32 nGType = getGeometryType();
1647
1648 if( eWkbVariant == wkbVariantPostGIS1 )
1649 {
1650 nGType = wkbFlatten(nGType);
1651 if( Is3D() )
1652 // Explicitly set wkb25DBit.
1653 nGType = static_cast<OGRwkbGeometryType>(nGType | wkb25DBitInternalUse);
1654 if( IsMeasured() )
1655 nGType = static_cast<OGRwkbGeometryType>(nGType | 0x40000000);
1656 }
1657 else if( eWkbVariant == wkbVariantIso )
1658 nGType = getIsoGeometryType();
1659
1660 if( eByteOrder == wkbNDR )
1661 {
1662 CPL_LSBPTR32( &nGType );
1663 }
1664 else
1665 {
1666 CPL_MSBPTR32( &nGType );
1667 }
1668
1669 memcpy( pabyData + 1, &nGType, 4 );
1670
1671 /* -------------------------------------------------------------------- */
1672 /* Copy in the data count. */
1673 /* -------------------------------------------------------------------- */
1674 memcpy( pabyData+5, &nPointCount, 4 );
1675
1676 /* -------------------------------------------------------------------- */
1677 /* Copy in the raw data. */
1678 /* -------------------------------------------------------------------- */
1679 if( (flags & OGR_G_3D) && (flags & OGR_G_MEASURED) )
1680 {
1681 for( size_t i = 0; i < static_cast<size_t>(nPointCount); i++ )
1682 {
1683 memcpy( pabyData + 9 + 32*i, paoPoints+i, 16 );
1684 memcpy( pabyData + 9 + 16 + 32*i, padfZ+i, 8 );
1685 memcpy( pabyData + 9 + 24 + 32*i, padfM+i, 8 );
1686 }
1687 }
1688 else if( flags & OGR_G_MEASURED )
1689 {
1690 for( size_t i = 0; i < static_cast<size_t>(nPointCount); i++ )
1691 {
1692 memcpy( pabyData + 9 + 24*i, paoPoints+i, 16 );
1693 memcpy( pabyData + 9 + 16 + 24*i, padfM+i, 8 );
1694 }
1695 }
1696 else if( flags & OGR_G_3D )
1697 {
1698 for( size_t i = 0; i < static_cast<size_t>(nPointCount); i++ )
1699 {
1700 memcpy( pabyData + 9 + 24*i, paoPoints+i, 16 );
1701 memcpy( pabyData + 9 + 16 + 24*i, padfZ+i, 8 );
1702 }
1703 }
1704 else if( nPointCount )
1705 memcpy( pabyData+9, paoPoints, 16 * static_cast<size_t>(nPointCount) );
1706
1707 /* -------------------------------------------------------------------- */
1708 /* Swap if needed. */
1709 /* -------------------------------------------------------------------- */
1710 if( OGR_SWAP( eByteOrder ) )
1711 {
1712 const int nCount = CPL_SWAP32( nPointCount );
1713 memcpy( pabyData+5, &nCount, 4 );
1714
1715 const size_t nCoords = CoordinateDimension() * static_cast<size_t>(nPointCount);
1716 for( size_t i = 0; i < nCoords; i++ )
1717 {
1718 CPL_SWAP64PTR( pabyData + 9 + 8 * i );
1719 }
1720 }
1721
1722 return OGRERR_NONE;
1723 }
1724
1725 /************************************************************************/
1726 /* importFromWkt() */
1727 /* */
1728 /* Instantiate from well known text format. Currently this is */
1729 /* `LINESTRING ( x y, x y, ...)', */
1730 /************************************************************************/
1731
1732 OGRErr OGRSimpleCurve::importFromWkt( const char ** ppszInput )
1733
1734 {
1735 int bHasZ = FALSE;
1736 int bHasM = FALSE;
1737 bool bIsEmpty = false;
1738 const OGRErr eErr =
1739 importPreambleFromWkt(ppszInput, &bHasZ, &bHasM, &bIsEmpty);
1740 flags = 0;
1741 if( eErr != OGRERR_NONE )
1742 return eErr;
1743 if( bHasZ ) flags |= OGR_G_3D;
1744 if( bHasM ) flags |= OGR_G_MEASURED;
1745 if( bIsEmpty )
1746 {
1747 return OGRERR_NONE;
1748 }
1749
1750 const char *pszInput = *ppszInput;
1751
1752 /* -------------------------------------------------------------------- */
1753 /* Read the point list. */
1754 /* -------------------------------------------------------------------- */
1755 int flagsFromInput = flags;
1756 nPointCount = 0;
1757
1758 int nMaxPoints = 0;
1759 pszInput = OGRWktReadPointsM( pszInput, &paoPoints, &padfZ, &padfM,
1760 &flagsFromInput,
1761 &nMaxPoints, &nPointCount );
1762 if( pszInput == nullptr )
1763 return OGRERR_CORRUPT_DATA;
1764
1765 if( (flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D) )
1766 {
1767 set3D(TRUE);
1768 }
1769 if( (flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED) )
1770 {
1771 setMeasured(TRUE);
1772 }
1773
1774 *ppszInput = pszInput;
1775
1776 return OGRERR_NONE;
1777 }
1778
1779 //! @cond Doxygen_Suppress
1780 /************************************************************************/
1781 /* importFromWKTListOnly() */
1782 /* */
1783 /* Instantiate from "(x y, x y, ...)" */
1784 /************************************************************************/
1785
1786 OGRErr OGRSimpleCurve::importFromWKTListOnly( const char ** ppszInput,
1787 int bHasZ, int bHasM,
1788 OGRRawPoint*& paoPointsIn,
1789 int& nMaxPointsIn,
1790 double*& padfZIn )
1791
1792 {
1793 const char *pszInput = *ppszInput;
1794
1795 /* -------------------------------------------------------------------- */
1796 /* Read the point list. */
1797 /* -------------------------------------------------------------------- */
1798 int flagsFromInput = flags;
1799 int nPointCountRead = 0;
1800 double *padfMIn = nullptr;
1801 if( flagsFromInput == 0 ) // Flags was not set, this is not called by us.
1802 {
1803 if( bHasM )
1804 flagsFromInput |= OGR_G_MEASURED;
1805 if( bHasZ )
1806 flagsFromInput |= OGR_G_3D;
1807 }
1808
1809 pszInput = OGRWktReadPointsM( pszInput, &paoPointsIn, &padfZIn, &padfMIn,
1810 &flagsFromInput,
1811 &nMaxPointsIn, &nPointCountRead );
1812
1813 if( pszInput == nullptr )
1814 {
1815 CPLFree( padfMIn );
1816 return OGRERR_CORRUPT_DATA;
1817 }
1818 if( (flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D) )
1819 {
1820 flags |= OGR_G_3D;
1821 bHasZ = TRUE;
1822 }
1823 if( (flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED) )
1824 {
1825 flags |= OGR_G_MEASURED;
1826 bHasM = TRUE;
1827 }
1828
1829 *ppszInput = pszInput;
1830
1831 if( bHasM && bHasZ )
1832 setPoints( nPointCountRead, paoPointsIn, padfZIn, padfMIn );
1833 else if( bHasM && !bHasZ )
1834 setPointsM( nPointCountRead, paoPointsIn, padfMIn );
1835 else
1836 setPoints( nPointCountRead, paoPointsIn, padfZIn );
1837
1838 CPLFree( padfMIn );
1839
1840 return OGRERR_NONE;
1841 }
1842 //! @endcond
1843
1844 /************************************************************************/
1845 /* exportToWkt() */
1846 /* */
1847 /* Translate this structure into its well known text format */
1848 /* equivalent. This could be made a lot more CPU efficient. */
1849 /************************************************************************/
1850
1851 std::string OGRSimpleCurve::exportToWkt(const OGRWktOptions& opts, OGRErr *err) const
1852 {
1853 // LINEARRING or LINESTRING or CIRCULARSTRING
1854 std::string wkt = getGeometryName();
1855 wkt += wktTypeString(opts.variant);
1856 if( IsEmpty() )
1857 {
1858 wkt += "EMPTY";
1859 }
1860 else
1861 {
1862 wkt += '(';
1863
1864 OGRBoolean hasZ = Is3D();
1865 OGRBoolean hasM =
1866 (opts.variant != wkbVariantIso ? FALSE : IsMeasured());
1867
1868 try
1869 {
1870 const int nOrdinatesPerVertex =
1871 2 + ((hasZ) ? 1 : 0) + ((hasM) ? 1 : 0);
1872 // At least 2 bytes per ordinate: one for the value,
1873 // and one for the separator...
1874 wkt.reserve(wkt.size() + 2 * nPointCount * nOrdinatesPerVertex);
1875
1876 for( int i = 0; i < nPointCount; i++ )
1877 {
1878 if (i > 0)
1879 wkt += ',';
1880
1881 wkt += OGRMakeWktCoordinateM(paoPoints[i].x, paoPoints[i].y,
1882 padfZ ? padfZ[i] : 0.0,
1883 padfM ? padfM[i] : 0.0,
1884 hasZ, hasM, opts );
1885 }
1886 wkt += ')';
1887 }
1888 catch( const std::bad_alloc& e )
1889 {
1890 CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
1891 if (err)
1892 *err = OGRERR_FAILURE;
1893 return std::string();
1894 }
1895 }
1896 if (err)
1897 *err = OGRERR_NONE;
1898 return wkt;
1899 }
1900
1901 /************************************************************************/
1902 /* get_Length() */
1903 /* */
1904 /* For now we return a simple euclidean 2D distance. */
1905 /************************************************************************/
1906
1907 double OGRSimpleCurve::get_Length() const
1908
1909 {
1910 double dfLength = 0.0;
1911
1912 for( int i = 0; i < nPointCount-1; i++ )
1913 {
1914
1915 const double dfDeltaX = paoPoints[i+1].x - paoPoints[i].x;
1916 const double dfDeltaY = paoPoints[i+1].y - paoPoints[i].y;
1917 dfLength += sqrt(dfDeltaX*dfDeltaX + dfDeltaY*dfDeltaY);
1918 }
1919
1920 return dfLength;
1921 }
1922
1923 /************************************************************************/
1924 /* StartPoint() */
1925 /************************************************************************/
1926
1927 void OGRSimpleCurve::StartPoint( OGRPoint * poPoint ) const
1928
1929 {
1930 getPoint( 0, poPoint );
1931 }
1932
1933 /************************************************************************/
1934 /* EndPoint() */
1935 /************************************************************************/
1936
1937 void OGRSimpleCurve::EndPoint( OGRPoint * poPoint ) const
1938
1939 {
1940 getPoint( nPointCount-1, poPoint );
1941 }
1942
1943 /************************************************************************/
1944 /* Value() */
1945 /* */
1946 /* Get an interpolated point at some distance along the curve. */
1947 /************************************************************************/
1948
1949 void OGRSimpleCurve::Value( double dfDistance, OGRPoint * poPoint ) const
1950
1951 {
1952 if( dfDistance < 0 )
1953 {
1954 StartPoint( poPoint );
1955 return;
1956 }
1957
1958 double dfLength = 0.0;
1959
1960 for( int i = 0; i < nPointCount-1; i++ )
1961 {
1962 const double dfDeltaX = paoPoints[i+1].x - paoPoints[i].x;
1963 const double dfDeltaY = paoPoints[i+1].y - paoPoints[i].y;
1964 const double dfSegLength = sqrt(dfDeltaX*dfDeltaX + dfDeltaY*dfDeltaY);
1965
1966 if( dfSegLength > 0 )
1967 {
1968 if( (dfLength <= dfDistance) && ((dfLength + dfSegLength) >=
1969 dfDistance) )
1970 {
1971 double dfRatio = (dfDistance - dfLength) / dfSegLength;
1972
1973 poPoint->setX( paoPoints[i].x * (1 - dfRatio)
1974 + paoPoints[i+1].x * dfRatio );
1975 poPoint->setY( paoPoints[i].y * (1 - dfRatio)
1976 + paoPoints[i+1].y * dfRatio );
1977
1978 if( getCoordinateDimension() == 3 )
1979 poPoint->setZ( padfZ[i] * (1 - dfRatio)
1980 + padfZ[i+1] * dfRatio );
1981
1982 return;
1983 }
1984
1985 dfLength += dfSegLength;
1986 }
1987 }
1988
1989 EndPoint( poPoint );
1990 }
1991
1992 /************************************************************************/
1993 /* Project() */
1994 /* */
1995 /* Return distance of point projected on line from origin of this line. */
1996 /************************************************************************/
1997
1998 /**
1999 * \brief Project point on linestring.
2000 *
2001 * The input point projected on linestring. This is the shortest distance
2002 * from point to the linestring. The distance from begin of linestring to
2003 * the point projection returned.
2004 *
2005 * This method is built on the GEOS library (GEOS >= 3.2.0), check it for the
2006 * definition of the geometry operation.
2007 * If OGR is built without the GEOS library, this method will always return -1,
2008 * issuing a CPLE_NotSupported error.
2009 *
2010 * @return a distance from the begin of the linestring to the projected point.
2011 *
2012 * @since OGR 1.11.0
2013 */
2014
2015 // GEOS >= 3.2.0 for project capability.
2016 #if defined(HAVE_GEOS)
2017 #if GEOS_VERSION_MAJOR > 3 || (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR >= 2)
2018 #define HAVE_GEOS_PROJECT
2019 #endif
2020 #endif
2021
2022 double OGRSimpleCurve::Project(const OGRPoint *
2023 #ifdef HAVE_GEOS_PROJECT
2024 poPoint
2025 #endif
2026 ) const
2027
2028 {
2029 double dfResult = -1;
2030 #ifndef HAVE_GEOS_PROJECT
2031 CPLError(CE_Failure, CPLE_NotSupported,
2032 "GEOS support not enabled.");
2033 return dfResult;
2034 #else
2035 GEOSGeom hThisGeosGeom = nullptr;
2036 GEOSGeom hPointGeosGeom = nullptr;
2037
2038 GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
2039 hThisGeosGeom = exportToGEOS(hGEOSCtxt);
2040 hPointGeosGeom = poPoint->exportToGEOS(hGEOSCtxt);
2041 if( hThisGeosGeom != nullptr && hPointGeosGeom != nullptr )
2042 {
2043 dfResult = GEOSProject_r(hGEOSCtxt, hThisGeosGeom, hPointGeosGeom);
2044 }
2045 GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
2046 GEOSGeom_destroy_r(hGEOSCtxt, hPointGeosGeom);
2047 freeGEOSContext(hGEOSCtxt);
2048
2049 return dfResult;
2050
2051 #endif // HAVE_GEOS
2052 }
2053
2054 /************************************************************************/
2055 /* getSubLine() */
2056 /* */
2057 /* Extracts a portion of this OGRLineString into a new OGRLineString. */
2058 /************************************************************************/
2059
2060 /**
2061 * \brief Get the portion of linestring.
2062 *
2063 * The portion of the linestring extracted to new one. The input distances
2064 * (maybe present as ratio of length of linestring) set begin and end of
2065 * extracted portion.
2066 *
2067 * @param dfDistanceFrom The distance from the origin of linestring, where the subline should begins
2068 * @param dfDistanceTo The distance from the origin of linestring, where the subline should ends
2069 * @param bAsRatio The flag indicating that distances are the ratio of the linestring length.
2070 *
2071 * @return a newly allocated linestring now owned by the caller, or NULL on failure.
2072 *
2073 * @since OGR 1.11.0
2074 */
2075
2076 OGRLineString* OGRSimpleCurve::getSubLine(double dfDistanceFrom,
2077 double dfDistanceTo,
2078 int bAsRatio) const
2079
2080 {
2081 OGRLineString *poNewLineString = new OGRLineString();
2082
2083 poNewLineString->assignSpatialReference(getSpatialReference());
2084 poNewLineString->setCoordinateDimension(getCoordinateDimension());
2085
2086 const double dfLen = get_Length();
2087 if( bAsRatio == TRUE )
2088 {
2089 // Convert to real distance.
2090 dfDistanceFrom *= dfLen;
2091 dfDistanceTo *= dfLen;
2092 }
2093
2094 if( dfDistanceFrom < 0 )
2095 dfDistanceFrom = 0;
2096 if( dfDistanceTo > dfLen )
2097 dfDistanceTo = dfLen;
2098
2099 if( dfDistanceFrom > dfDistanceTo || dfDistanceFrom >= dfLen )
2100 {
2101 CPLError(CE_Failure, CPLE_IllegalArg, "Input distances are invalid.");
2102
2103 return nullptr;
2104 }
2105
2106 double dfLength = 0.0;
2107
2108 // Get first point.
2109
2110 int i = 0; // Used after if blocks.
2111 if( dfDistanceFrom == 0 )
2112 {
2113 if( getCoordinateDimension() == 3 )
2114 poNewLineString->addPoint(paoPoints[0].x, paoPoints[0].y, padfZ[0]);
2115 else
2116 poNewLineString->addPoint(paoPoints[0].x, paoPoints[0].y);
2117 }
2118 else
2119 {
2120 for( i = 0; i < nPointCount - 1; i++ )
2121 {
2122 const double dfDeltaX = paoPoints[i + 1].x - paoPoints[i].x;
2123 const double dfDeltaY = paoPoints[i + 1].y - paoPoints[i].y;
2124 const double dfSegLength =
2125 sqrt(dfDeltaX*dfDeltaX + dfDeltaY*dfDeltaY);
2126
2127 if( dfSegLength > 0 )
2128 {
2129 if( (dfLength <= dfDistanceFrom) && ((dfLength + dfSegLength) >=
2130 dfDistanceFrom) )
2131 {
2132 double dfRatio = (dfDistanceFrom - dfLength) / dfSegLength;
2133
2134 double dfX = paoPoints[i].x * (1 - dfRatio)
2135 + paoPoints[i + 1].x * dfRatio;
2136 double dfY = paoPoints[i].y * (1 - dfRatio)
2137 + paoPoints[i + 1].y * dfRatio;
2138
2139 if( getCoordinateDimension() == 3 )
2140 {
2141 poNewLineString->
2142 addPoint(dfX, dfY, padfZ[i] * (1 - dfRatio)
2143 + padfZ[i+1] * dfRatio);
2144 }
2145 else
2146 {
2147 poNewLineString->addPoint(dfX, dfY);
2148 }
2149
2150 // Check if dfDistanceTo is in same segment.
2151 if( dfLength <= dfDistanceTo &&
2152 (dfLength + dfSegLength) >= dfDistanceTo )
2153 {
2154 dfRatio = (dfDistanceTo - dfLength) / dfSegLength;
2155
2156 dfX = paoPoints[i].x * (1 - dfRatio)
2157 + paoPoints[i + 1].x * dfRatio;
2158 dfY = paoPoints[i].y * (1 - dfRatio)
2159 + paoPoints[i + 1].y * dfRatio;
2160
2161 if( getCoordinateDimension() == 3 )
2162 {
2163 poNewLineString->
2164 addPoint(dfX, dfY, padfZ[i] * (1 - dfRatio)
2165 + padfZ[i + 1] * dfRatio);
2166 }
2167 else
2168 {
2169 poNewLineString->addPoint(dfX, dfY);
2170 }
2171
2172 if( poNewLineString->getNumPoints() < 2 )
2173 {
2174 delete poNewLineString;
2175 poNewLineString = nullptr;
2176 }
2177
2178 return poNewLineString;
2179 }
2180 i++;
2181 dfLength += dfSegLength;
2182 break;
2183 }
2184
2185 dfLength += dfSegLength;
2186 }
2187 }
2188 }
2189
2190 // Add points.
2191 for( ; i < nPointCount - 1; i++ )
2192 {
2193 if( getCoordinateDimension() == 3 )
2194 poNewLineString->addPoint(paoPoints[i].x, paoPoints[i].y, padfZ[i]);
2195 else
2196 poNewLineString->addPoint(paoPoints[i].x, paoPoints[i].y);
2197
2198 const double dfDeltaX = paoPoints[i + 1].x - paoPoints[i].x;
2199 const double dfDeltaY = paoPoints[i + 1].y - paoPoints[i].y;
2200 const double dfSegLength = sqrt(dfDeltaX*dfDeltaX + dfDeltaY*dfDeltaY);
2201
2202 if( dfSegLength > 0 )
2203 {
2204 if( (dfLength <= dfDistanceTo) && ((dfLength + dfSegLength) >=
2205 dfDistanceTo) )
2206 {
2207 const double dfRatio = (dfDistanceTo - dfLength) / dfSegLength;
2208
2209 const double dfX = paoPoints[i].x * (1 - dfRatio)
2210 + paoPoints[i + 1].x * dfRatio;
2211 const double dfY = paoPoints[i].y * (1 - dfRatio)
2212 + paoPoints[i + 1].y * dfRatio;
2213
2214 if( getCoordinateDimension() == 3 )
2215 poNewLineString->addPoint(dfX, dfY, padfZ[i] * (1 - dfRatio)
2216 + padfZ[i + 1] * dfRatio);
2217 else
2218 poNewLineString->addPoint(dfX, dfY);
2219
2220 return poNewLineString;
2221 }
2222
2223 dfLength += dfSegLength;
2224 }
2225 }
2226
2227 if( getCoordinateDimension() == 3 )
2228 poNewLineString->
2229 addPoint(paoPoints[nPointCount - 1].x,
2230 paoPoints[nPointCount - 1].y,
2231 padfZ[nPointCount - 1]);
2232 else
2233 poNewLineString->
2234 addPoint(paoPoints[nPointCount - 1].x,
2235 paoPoints[nPointCount - 1].y);
2236
2237 if( poNewLineString->getNumPoints() < 2 )
2238 {
2239 delete poNewLineString;
2240 poNewLineString = nullptr;
2241 }
2242
2243 return poNewLineString;
2244 }
2245
2246 /************************************************************************/
2247 /* getEnvelope() */
2248 /************************************************************************/
2249
2250 void OGRSimpleCurve::getEnvelope( OGREnvelope * psEnvelope ) const
2251
2252 {
2253 if( IsEmpty() )
2254 {
2255 psEnvelope->MinX = 0.0;
2256 psEnvelope->MaxX = 0.0;
2257 psEnvelope->MinY = 0.0;
2258 psEnvelope->MaxY = 0.0;
2259 return;
2260 }
2261
2262 double dfMinX = paoPoints[0].x;
2263 double dfMaxX = paoPoints[0].x;
2264 double dfMinY = paoPoints[0].y;
2265 double dfMaxY = paoPoints[0].y;
2266
2267 for( int iPoint = 1; iPoint < nPointCount; iPoint++ )
2268 {
2269 if( dfMaxX < paoPoints[iPoint].x )
2270 dfMaxX = paoPoints[iPoint].x;
2271 if( dfMaxY < paoPoints[iPoint].y )
2272 dfMaxY = paoPoints[iPoint].y;
2273 if( dfMinX > paoPoints[iPoint].x )
2274 dfMinX = paoPoints[iPoint].x;
2275 if( dfMinY > paoPoints[iPoint].y )
2276 dfMinY = paoPoints[iPoint].y;
2277 }
2278
2279 psEnvelope->MinX = dfMinX;
2280 psEnvelope->MaxX = dfMaxX;
2281 psEnvelope->MinY = dfMinY;
2282 psEnvelope->MaxY = dfMaxY;
2283 }
2284
2285 /************************************************************************/
2286 /* getEnvelope() */
2287 /************************************************************************/
2288
2289 void OGRSimpleCurve::getEnvelope( OGREnvelope3D * psEnvelope ) const
2290
2291 {
2292 getEnvelope(static_cast<OGREnvelope*>(psEnvelope));
2293
2294 if( IsEmpty() || padfZ == nullptr )
2295 {
2296 psEnvelope->MinZ = 0.0;
2297 psEnvelope->MaxZ = 0.0;
2298 return;
2299 }
2300
2301 double dfMinZ = padfZ[0];
2302 double dfMaxZ = padfZ[0];
2303
2304 for( int iPoint = 1; iPoint < nPointCount; iPoint++ )
2305 {
2306 if( dfMinZ > padfZ[iPoint] )
2307 dfMinZ = padfZ[iPoint];
2308 if( dfMaxZ < padfZ[iPoint] )
2309 dfMaxZ = padfZ[iPoint];
2310 }
2311
2312 psEnvelope->MinZ = dfMinZ;
2313 psEnvelope->MaxZ = dfMaxZ;
2314 }
2315
2316 /************************************************************************/
2317 /* Equals() */
2318 /************************************************************************/
2319
2320 OGRBoolean OGRSimpleCurve::Equals( const OGRGeometry * poOther ) const
2321
2322 {
2323 if( poOther == this )
2324 return TRUE;
2325
2326 if( poOther->getGeometryType() != getGeometryType() )
2327 return FALSE;
2328
2329 if( IsEmpty() && poOther->IsEmpty() )
2330 return TRUE;
2331
2332 // TODO(schwehr): Test the SRS.
2333
2334 auto poOLine = poOther->toSimpleCurve();
2335 if( getNumPoints() != poOLine->getNumPoints() )
2336 return FALSE;
2337
2338 for( int iPoint = 0; iPoint < getNumPoints(); iPoint++ )
2339 {
2340 if( getX(iPoint) != poOLine->getX(iPoint)
2341 || getY(iPoint) != poOLine->getY(iPoint)
2342 || getZ(iPoint) != poOLine->getZ(iPoint) )
2343 return FALSE;
2344 }
2345
2346 return TRUE;
2347 }
2348
2349 /************************************************************************/
2350 /* transform() */
2351 /************************************************************************/
2352
2353 OGRErr OGRSimpleCurve::transform( OGRCoordinateTransformation *poCT )
2354
2355 {
2356 /* -------------------------------------------------------------------- */
2357 /* Make a copy of the points to operate on, so as to be able to */
2358 /* keep only valid reprojected points if partial reprojection enabled */
2359 /* or keeping intact the original geometry if only full reprojection */
2360 /* allowed. */
2361 /* -------------------------------------------------------------------- */
2362 double *xyz = static_cast<double *>(
2363 VSI_MALLOC_VERBOSE(sizeof(double) * nPointCount * 3));
2364 int *pabSuccess = static_cast<int *>(
2365 VSI_CALLOC_VERBOSE(sizeof(int), nPointCount));
2366 if( xyz == nullptr || pabSuccess == nullptr )
2367 {
2368 VSIFree(xyz);
2369 VSIFree(pabSuccess);
2370 return OGRERR_NOT_ENOUGH_MEMORY;
2371 }
2372
2373 for( int i = 0; i < nPointCount; i++ )
2374 {
2375 xyz[i] = paoPoints[i].x;
2376 xyz[i+nPointCount] = paoPoints[i].y;
2377 if( padfZ )
2378 xyz[i+nPointCount*2] = padfZ[i];
2379 else
2380 xyz[i+nPointCount*2] = 0.0;
2381 }
2382
2383 /* -------------------------------------------------------------------- */
2384 /* Transform and reapply. */
2385 /* -------------------------------------------------------------------- */
2386 poCT->Transform( nPointCount, xyz, xyz + nPointCount,
2387 xyz+nPointCount*2, nullptr, pabSuccess );
2388
2389 const char* pszEnablePartialReprojection = nullptr;
2390
2391 int j = 0; // Used after for.
2392 for( int i = 0; i < nPointCount; i++ )
2393 {
2394 if( pabSuccess[i] )
2395 {
2396 xyz[j] = xyz[i];
2397 xyz[j+nPointCount] = xyz[i+nPointCount];
2398 xyz[j+2*nPointCount] = xyz[i+2*nPointCount];
2399 j++;
2400 }
2401 else
2402 {
2403 if( pszEnablePartialReprojection == nullptr )
2404 pszEnablePartialReprojection =
2405 CPLGetConfigOption("OGR_ENABLE_PARTIAL_REPROJECTION", nullptr);
2406 if( pszEnablePartialReprojection == nullptr )
2407 {
2408 static bool bHasWarned = false;
2409 if( !bHasWarned )
2410 {
2411 // Check that there is at least one valid reprojected point
2412 // and issue an error giving an hint to use
2413 // OGR_ENABLE_PARTIAL_REPROJECTION.
2414 bool bHasOneValidPoint = j != 0;
2415 for( ; i < nPointCount && !bHasOneValidPoint; i++ )
2416 {
2417 if( pabSuccess[i] )
2418 bHasOneValidPoint = true;
2419 }
2420 if( bHasOneValidPoint )
2421 {
2422 bHasWarned = true;
2423 CPLError(CE_Failure, CPLE_AppDefined,
2424 "Full reprojection failed, but partial is "
2425 "possible if you define "
2426 "OGR_ENABLE_PARTIAL_REPROJECTION "
2427 "configuration option to TRUE");
2428 }
2429 }
2430
2431 CPLFree( xyz );
2432 CPLFree( pabSuccess );
2433 return OGRERR_FAILURE;
2434 }
2435 else if( !CPLTestBool(pszEnablePartialReprojection) )
2436 {
2437 CPLFree( xyz );
2438 CPLFree( pabSuccess );
2439 return OGRERR_FAILURE;
2440 }
2441 }
2442 }
2443
2444 if( j == 0 && nPointCount != 0 )
2445 {
2446 CPLFree( xyz );
2447 CPLFree( pabSuccess );
2448 return OGRERR_FAILURE;
2449 }
2450
2451 setPoints( j, xyz, xyz+nPointCount,
2452 ( padfZ ) ? xyz+nPointCount*2 : nullptr);
2453 CPLFree( xyz );
2454 CPLFree( pabSuccess );
2455
2456 assignSpatialReference( poCT->GetTargetCS() );
2457
2458 return OGRERR_NONE;
2459 }
2460
2461 /************************************************************************/
2462 /* IsEmpty() */
2463 /************************************************************************/
2464
2465 OGRBoolean OGRSimpleCurve::IsEmpty() const
2466 {
2467 return (nPointCount == 0);
2468 }
2469
2470 /************************************************************************/
2471 /* OGRSimpleCurve::segmentize() */
2472 /************************************************************************/
2473
2474 void OGRSimpleCurve::segmentize( double dfMaxLength )
2475 {
2476 if( dfMaxLength <= 0 )
2477 {
2478 CPLError(CE_Failure, CPLE_AppDefined,
2479 "dfMaxLength must be strictly positive");
2480 return;
2481 }
2482 if( nPointCount < 2 )
2483 return;
2484
2485 // So as to make sure that the same line followed in both directions
2486 // result in the same segmentized line.
2487 if( paoPoints[0].x < paoPoints[nPointCount - 1].x ||
2488 (paoPoints[0].x == paoPoints[nPointCount - 1].x &&
2489 paoPoints[0].y < paoPoints[nPointCount - 1].y) )
2490 {
2491 reversePoints();
2492 segmentize(dfMaxLength);
2493 reversePoints();
2494 return;
2495 }
2496
2497 OGRRawPoint* paoNewPoints = nullptr;
2498 double* padfNewZ = nullptr;
2499 double* padfNewM = nullptr;
2500 int nNewPointCount = 0;
2501 const double dfSquareMaxLength = dfMaxLength * dfMaxLength;
2502
2503 for( int i = 0; i < nPointCount; i++ )
2504 {
2505 paoNewPoints = static_cast<OGRRawPoint *>(
2506 CPLRealloc(paoNewPoints,
2507 sizeof(OGRRawPoint) * (nNewPointCount + 1)));
2508 paoNewPoints[nNewPointCount] = paoPoints[i];
2509
2510 if( padfZ != nullptr )
2511 {
2512 padfNewZ = static_cast<double *>(
2513 CPLRealloc(padfNewZ, sizeof(double) * (nNewPointCount + 1)));
2514 padfNewZ[nNewPointCount] = padfZ[i];
2515 }
2516
2517 if( padfM != nullptr )
2518 {
2519 padfNewM = static_cast<double *>(
2520 CPLRealloc(padfNewM, sizeof(double) * (nNewPointCount + 1)));
2521 padfNewM[nNewPointCount] = padfM[i];
2522 }
2523
2524 nNewPointCount++;
2525
2526 if( i == nPointCount - 1 )
2527 break;
2528
2529 const double dfX = paoPoints[i+1].x - paoPoints[i].x;
2530 const double dfY = paoPoints[i+1].y - paoPoints[i].y;
2531 const double dfSquareDist = dfX * dfX + dfY * dfY;
2532 if( dfSquareDist - dfSquareMaxLength > 1e-5 * dfSquareMaxLength )
2533 {
2534 const double dfIntermediatePoints =
2535 floor(sqrt(dfSquareDist / dfSquareMaxLength) - 1e-2);
2536 const int nIntermediatePoints =
2537 DoubleToIntClamp(dfIntermediatePoints);
2538
2539 // TODO(schwehr): Can these be tighter?
2540 // Limit allocation of paoNewPoints to a few GB of memory.
2541 // An OGRRawPoint is 2 doubles.
2542 // kMax is a guess of what a reasonable max might be.
2543 const int kMax = 2 << 26;
2544 if ( nNewPointCount > kMax || nIntermediatePoints > kMax )
2545 {
2546 CPLError(CE_Failure, CPLE_AppDefined,
2547 "Too many points in a segment: %d or %d",
2548 nNewPointCount, nIntermediatePoints);
2549 CPLFree(paoNewPoints);
2550 CPLFree(padfNewZ);
2551 CPLFree(padfNewM);
2552 return;
2553 }
2554
2555 paoNewPoints = static_cast<OGRRawPoint *>(
2556 CPLRealloc(paoNewPoints,
2557 sizeof(OGRRawPoint) * (nNewPointCount +
2558 nIntermediatePoints)));
2559 if( padfZ != nullptr )
2560 {
2561 padfNewZ = static_cast<double *>(
2562 CPLRealloc(padfNewZ,
2563 sizeof(double) * (nNewPointCount +
2564 nIntermediatePoints)));
2565 }
2566 if( padfM != nullptr )
2567 {
2568 padfNewM = static_cast<double *>(
2569 CPLRealloc(padfNewM,
2570 sizeof(double) * (nNewPointCount +
2571 nIntermediatePoints)));
2572 }
2573
2574 for( int j = 1; j <= nIntermediatePoints; j++ )
2575 {
2576 paoNewPoints[nNewPointCount + j - 1].x =
2577 paoPoints[i].x + j * dfX / (nIntermediatePoints + 1);
2578 paoNewPoints[nNewPointCount + j - 1].y =
2579 paoPoints[i].y + j * dfY / (nIntermediatePoints + 1);
2580 if( padfZ != nullptr )
2581 {
2582 // No interpolation.
2583 padfNewZ[nNewPointCount + j - 1] = padfZ[i];
2584 }
2585 if( padfM != nullptr )
2586 {
2587 // No interpolation.
2588 padfNewM[nNewPointCount + j - 1] = padfM[i];
2589 }
2590 }
2591
2592 nNewPointCount += nIntermediatePoints;
2593 }
2594 }
2595
2596 CPLFree(paoPoints);
2597 paoPoints = paoNewPoints;
2598 nPointCount = nNewPointCount;
2599
2600 if( padfZ != nullptr )
2601 {
2602 CPLFree(padfZ);
2603 padfZ = padfNewZ;
2604 }
2605 if( padfM != nullptr )
2606 {
2607 CPLFree(padfM);
2608 padfM = padfNewM;
2609 }
2610 }
2611
2612 /************************************************************************/
2613 /* swapXY() */
2614 /************************************************************************/
2615
2616 void OGRSimpleCurve::swapXY()
2617 {
2618 for( int i = 0; i < nPointCount; i++ )
2619 {
2620 std::swap(paoPoints[i].x, paoPoints[i].y);
2621 }
2622 }
2623
2624 /************************************************************************/
2625 /* OGRSimpleCurvePointIterator */
2626 /************************************************************************/
2627
2628 class OGRSimpleCurvePointIterator final: public OGRPointIterator
2629 {
2630 CPL_DISALLOW_COPY_ASSIGN(OGRSimpleCurvePointIterator)
2631
2632 const OGRSimpleCurve* poSC = nullptr;
2633 int iCurPoint = 0;
2634
2635 public:
2636 explicit OGRSimpleCurvePointIterator(const OGRSimpleCurve* poSCIn) :
2637 poSC(poSCIn) {}
2638
2639 OGRBoolean getNextPoint( OGRPoint* p ) override;
2640 };
2641
2642 /************************************************************************/
2643 /* getNextPoint() */
2644 /************************************************************************/
2645
2646 OGRBoolean OGRSimpleCurvePointIterator::getNextPoint(OGRPoint* p)
2647 {
2648 if( iCurPoint >= poSC->getNumPoints() )
2649 return FALSE;
2650 poSC->getPoint(iCurPoint, p);
2651 iCurPoint++;
2652 return TRUE;
2653 }
2654
2655 /************************************************************************/
2656 /* getPointIterator() */
2657 /************************************************************************/
2658
2659 OGRPointIterator* OGRSimpleCurve::getPointIterator() const
2660 {
2661 return new OGRSimpleCurvePointIterator(this);
2662 }
2663
2664 /************************************************************************/
2665 /* OGRLineString() */
2666 /************************************************************************/
2667
2668 /**
2669 * \brief Create an empty line string.
2670 */
2671
2672 OGRLineString::OGRLineString() = default;
2673
2674 /************************************************************************/
2675 /* OGRLineString( const OGRLineString& ) */
2676 /************************************************************************/
2677
2678 /**
2679 * \brief Copy constructor.
2680 *
2681 * Note: before GDAL 2.1, only the default implementation of the constructor
2682 * existed, which could be unsafe to use.
2683 *
2684 * @since GDAL 2.1
2685 */
2686
2687 OGRLineString::OGRLineString( const OGRLineString& ) = default;
2688
2689 /************************************************************************/
2690 /* ~OGRLineString() */
2691 /************************************************************************/
2692
2693 OGRLineString::~OGRLineString() = default;
2694
2695 /************************************************************************/
2696 /* operator=( const OGRLineString& ) */
2697 /************************************************************************/
2698
2699 /**
2700 * \brief Assignment operator.
2701 *
2702 * Note: before GDAL 2.1, only the default implementation of the operator
2703 * existed, which could be unsafe to use.
2704 *
2705 * @since GDAL 2.1
2706 */
2707
2708 OGRLineString& OGRLineString::operator=( const OGRLineString& other )
2709 {
2710 if( this != &other)
2711 {
2712 OGRSimpleCurve::operator=( other );
2713 }
2714 return *this;
2715 }
2716
2717 /************************************************************************/
2718 /* getGeometryType() */
2719 /************************************************************************/
2720
2721 OGRwkbGeometryType OGRLineString::getGeometryType() const
2722
2723 {
2724 if( (flags & OGR_G_3D) && (flags & OGR_G_MEASURED) )
2725 return wkbLineStringZM;
2726 else if( flags & OGR_G_MEASURED )
2727 return wkbLineStringM;
2728 else if( flags & OGR_G_3D )
2729 return wkbLineString25D;
2730 else
2731 return wkbLineString;
2732 }
2733
2734 /************************************************************************/
2735 /* getGeometryName() */
2736 /************************************************************************/
2737
2738 const char * OGRLineString::getGeometryName() const
2739
2740 {
2741 return "LINESTRING";
2742 }
2743
2744 /************************************************************************/
2745 /* curveToLine() */
2746 /************************************************************************/
2747
2748 OGRLineString* OGRLineString::CurveToLine(
2749 CPL_UNUSED double /* dfMaxAngleStepSizeDegrees */,
2750 CPL_UNUSED const char* const* /* papszOptions */ ) const
2751 {
2752 return clone();
2753 }
2754
2755 /************************************************************************/
2756 /* get_LinearArea() */
2757 /************************************************************************/
2758
2759 /**
2760 * \brief Compute area of ring / closed linestring.
2761 *
2762 * The area is computed according to Green's Theorem:
2763 *
2764 * Area is "Sum(x(i)*(y(i+1) - y(i-1)))/2" for i = 0 to pointCount-1,
2765 * assuming the last point is a duplicate of the first.
2766 *
2767 * @return computed area.
2768 */
2769
2770 double OGRSimpleCurve::get_LinearArea() const
2771
2772 {
2773 if( nPointCount < 2 ||
2774 (WkbSize() != 0 && /* if not a linearring, check it is closed */
2775 (paoPoints[0].x != paoPoints[nPointCount-1].x ||
2776 paoPoints[0].y != paoPoints[nPointCount-1].y)) )
2777 {
2778 return 0;
2779 }
2780
2781 double dfAreaSum =
2782 paoPoints[0].x * (paoPoints[1].y - paoPoints[nPointCount-1].y);
2783
2784 for( int i = 1; i < nPointCount-1; i++ )
2785 {
2786 dfAreaSum += paoPoints[i].x * (paoPoints[i+1].y - paoPoints[i-1].y);
2787 }
2788
2789 dfAreaSum +=
2790 paoPoints[nPointCount-1].x *
2791 (paoPoints[0].y - paoPoints[nPointCount-2].y);
2792
2793 return 0.5 * fabs(dfAreaSum);
2794 }
2795
2796 /************************************************************************/
2797 /* getCurveGeometry() */
2798 /************************************************************************/
2799
2800 OGRGeometry *
2801 OGRLineString::getCurveGeometry( const char* const* papszOptions ) const
2802 {
2803 return OGRGeometryFactory::curveFromLineString(this, papszOptions);
2804 }
2805
2806 /************************************************************************/
2807 /* TransferMembersAndDestroy() */
2808 /************************************************************************/
2809 //! @cond Doxygen_Suppress
2810 OGRLineString* OGRLineString::TransferMembersAndDestroy(
2811 OGRLineString* poSrc,
2812 OGRLineString* poDst )
2813 {
2814 if( poSrc->Is3D())
2815 poDst->flags |= OGR_G_3D;
2816 if( poSrc->IsMeasured())
2817 poDst->flags |= OGR_G_MEASURED;
2818 poDst->assignSpatialReference(poSrc->getSpatialReference());
2819 poDst->nPointCount = poSrc->nPointCount;
2820 poDst->paoPoints = poSrc->paoPoints;
2821 poDst->padfZ = poSrc->padfZ;
2822 poDst->padfM = poSrc->padfM;
2823 poSrc->nPointCount = 0;
2824 poSrc->paoPoints = nullptr;
2825 poSrc->padfZ = nullptr;
2826 poSrc->padfM = nullptr;
2827 delete poSrc;
2828 return poDst;
2829 }
2830 //! @endcond
2831 /************************************************************************/
2832 /* CastToLinearRing() */
2833 /************************************************************************/
2834
2835 /**
2836 * \brief Cast to linear ring.
2837 *
2838 * The passed in geometry is consumed and a new one returned (or NULL in case
2839 * of failure)
2840 *
2841 * @param poLS the input geometry - ownership is passed to the method.
2842 * @return new geometry.
2843 */
2844
2845 OGRLinearRing* OGRLineString::CastToLinearRing( OGRLineString* poLS )
2846 {
2847 if( poLS->nPointCount < 2 || !poLS->get_IsClosed() )
2848 {
2849 CPLError(CE_Failure, CPLE_AppDefined,
2850 "Cannot convert non-closed linestring to linearring");
2851 delete poLS;
2852 return nullptr;
2853 }
2854 OGRLinearRing* poLR = new OGRLinearRing();
2855 TransferMembersAndDestroy(poLS, poLR);
2856 return poLR;
2857 }
2858
2859 /************************************************************************/
2860 /* clone() */
2861 /************************************************************************/
2862
2863 OGRLineString *OGRLineString::clone() const
2864 {
2865 return new (std::nothrow) OGRLineString(*this);
2866 }
2867
2868 //! @cond Doxygen_Suppress
2869
2870 /************************************************************************/
2871 /* GetCasterToLineString() */
2872 /************************************************************************/
2873
2874 static OGRLineString* CasterToLineString(OGRCurve* poCurve)
2875 {
2876 return poCurve->toLineString();
2877 }
2878
2879 OGRCurveCasterToLineString OGRLineString::GetCasterToLineString() const
2880 {
2881 return ::CasterToLineString;
2882 }
2883
2884 /************************************************************************/
2885 /* GetCasterToLinearRing() */
2886 /************************************************************************/
2887
2888 OGRLinearRing* OGRLineString::CasterToLinearRing(OGRCurve* poCurve)
2889 {
2890 return OGRLineString::CastToLinearRing(poCurve->toLineString());
2891 }
2892
2893 OGRCurveCasterToLinearRing OGRLineString::GetCasterToLinearRing() const
2894 {
2895 return OGRLineString::CasterToLinearRing;
2896 }
2897
2898 /************************************************************************/
2899 /* get_Area() */
2900 /************************************************************************/
2901
2902 double OGRLineString::get_Area() const
2903 {
2904 return get_LinearArea();
2905 }
2906
2907 /************************************************************************/
2908 /* get_AreaOfCurveSegments() */
2909 /************************************************************************/
2910
2911 double OGRLineString::get_AreaOfCurveSegments() const
2912 {
2913 return 0;
2914 }
2915 //! @endcond
2916