LCOV - code coverage report
Current view: top level - ogr - ogrlinestring.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 994 1146 86.7 %
Date: 2024-05-03 15:49:35 Functions: 81 82 98.8 %

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

Generated by: LCOV version 1.14