LCOV - code coverage report
Current view: top level - ogr - ogrlinestring.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1053 1220 86.3 %
Date: 2024-11-21 22:18:42 Functions: 86 87 98.9 %

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

Generated by: LCOV version 1.14