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