LCOV - code coverage report
Current view: top level - ogr - ogrlinestring.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1077 1246 86.4 %
Date: 2025-06-28 21:28:23 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         611 : int DoubleToIntClamp(double dfValue)
      30             : {
      31         611 :     if (std::isnan(dfValue))
      32           0 :         return 0;
      33         611 :     if (dfValue >= std::numeric_limits<int>::max())
      34           1 :         return std::numeric_limits<int>::max();
      35         610 :     if (dfValue <= std::numeric_limits<int>::min())
      36           0 :         return std::numeric_limits<int>::min();
      37         610 :     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      302376 : OGRSimpleCurve::OGRSimpleCurve(const OGRSimpleCurve &other)
      56             :     : OGRCurve(other), nPointCount(0), paoPoints(nullptr), padfZ(nullptr),
      57      302376 :       padfM(nullptr)
      58             : {
      59      302376 :     if (other.nPointCount > 0)
      60      302168 :         setPoints(other.nPointCount, other.paoPoints, other.padfZ, other.padfM);
      61      302376 : }
      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     3734650 : OGRSimpleCurve::~OGRSimpleCurve()
      93             : 
      94             : {
      95     3734680 :     CPLFree(paoPoints);
      96     3734680 :     CPLFree(padfZ);
      97     3734660 :     CPLFree(padfM);
      98     3734670 : }
      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        1069 : void OGRSimpleCurve::flattenTo2D()
     168             : 
     169             : {
     170        1069 :     Make2D();
     171        1069 :     setMeasured(FALSE);
     172        1069 : }
     173             : 
     174             : /************************************************************************/
     175             : /*                               empty()                                */
     176             : /************************************************************************/
     177             : 
     178       18764 : void OGRSimpleCurve::empty()
     179             : 
     180             : {
     181       18764 :     setNumPoints(0);
     182       18763 : }
     183             : 
     184             : /************************************************************************/
     185             : /*                       setCoordinateDimension()                       */
     186             : /************************************************************************/
     187             : 
     188        2179 : bool OGRSimpleCurve::setCoordinateDimension(int nNewDimension)
     189             : 
     190             : {
     191        2179 :     setMeasured(FALSE);
     192        2179 :     if (nNewDimension == 2)
     193        1150 :         Make2D();
     194        1029 :     else if (nNewDimension == 3)
     195        1029 :         return Make3D();
     196        1150 :     return true;
     197             : }
     198             : 
     199      119692 : bool OGRSimpleCurve::set3D(OGRBoolean bIs3D)
     200             : 
     201             : {
     202      119692 :     if (bIs3D)
     203      117097 :         return Make3D();
     204             :     else
     205        2595 :         Make2D();
     206        2595 :     return true;
     207             : }
     208             : 
     209      119340 : bool OGRSimpleCurve::setMeasured(OGRBoolean bIsMeasured)
     210             : 
     211             : {
     212      119340 :     if (bIsMeasured)
     213        8193 :         return AddM();
     214             :     else
     215      111147 :         RemoveM();
     216      111147 :     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       92896 : size_t OGRSimpleCurve::WkbSize() const
     227             : 
     228             : {
     229       92896 :     return 5 + 4 + 8 * static_cast<size_t>(nPointCount) * CoordinateDimension();
     230             : }
     231             : 
     232             : //! @cond Doxygen_Suppress
     233             : 
     234             : /************************************************************************/
     235             : /*                               Make2D()                               */
     236             : /************************************************************************/
     237             : 
     238       54783 : void OGRSimpleCurve::Make2D()
     239             : 
     240             : {
     241       54783 :     if (padfZ != nullptr)
     242             :     {
     243        1652 :         CPLFree(padfZ);
     244        1652 :         padfZ = nullptr;
     245             :     }
     246       54783 :     flags &= ~OGR_G_3D;
     247       54783 : }
     248             : 
     249             : /************************************************************************/
     250             : /*                               Make3D()                               */
     251             : /************************************************************************/
     252             : 
     253     2780800 : bool OGRSimpleCurve::Make3D()
     254             : 
     255             : {
     256     2780800 :     if (padfZ == nullptr)
     257             :     {
     258     2660180 :         padfZ = static_cast<double *>(
     259     2660180 :             VSI_CALLOC_VERBOSE(sizeof(double), std::max(1, m_nPointCapacity)));
     260     2660180 :         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     2780800 :     flags |= OGR_G_3D;
     269     2780800 :     return true;
     270             : }
     271             : 
     272             : /************************************************************************/
     273             : /*                               RemoveM()                              */
     274             : /************************************************************************/
     275             : 
     276      126583 : void OGRSimpleCurve::RemoveM()
     277             : 
     278             : {
     279      126583 :     if (padfM != nullptr)
     280             :     {
     281         250 :         CPLFree(padfM);
     282         250 :         padfM = nullptr;
     283             :     }
     284      126583 :     flags &= ~OGR_G_MEASURED;
     285      126583 : }
     286             : 
     287             : /************************************************************************/
     288             : /*                               AddM()                                 */
     289             : /************************************************************************/
     290             : 
     291       39013 : bool OGRSimpleCurve::AddM()
     292             : 
     293             : {
     294       39013 :     if (padfM == nullptr)
     295             :     {
     296       34603 :         padfM = static_cast<double *>(
     297       34603 :             VSI_CALLOC_VERBOSE(sizeof(double), std::max(1, m_nPointCapacity)));
     298       34603 :         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       39013 :     flags |= OGR_G_MEASURED;
     307       39013 :     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     1180760 : void OGRSimpleCurve::getPoint(int i, OGRPoint *poPoint) const
     326             : 
     327             : {
     328     1180760 :     CPLAssert(i >= 0);
     329     1180760 :     CPLAssert(i < nPointCount);
     330     1180760 :     CPLAssert(poPoint != nullptr);
     331             : 
     332     1180760 :     poPoint->setX(paoPoints[i].x);
     333     1180760 :     poPoint->setY(paoPoints[i].y);
     334             : 
     335     1180760 :     if ((flags & OGR_G_3D) && padfZ != nullptr)
     336       45190 :         poPoint->setZ(padfZ[i]);
     337     1180760 :     if ((flags & OGR_G_MEASURED) && padfM != nullptr)
     338       28415 :         poPoint->setM(padfM[i]);
     339     1180760 : }
     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      688314 : double OGRSimpleCurve::getZ(int iVertex) const
     394             : 
     395             : {
     396      688314 :     if (padfZ != nullptr && iVertex >= 0 && iVertex < nPointCount &&
     397      252729 :         (flags & OGR_G_3D))
     398      252729 :         return (padfZ[iVertex]);
     399             :     else
     400      435585 :         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    21579600 : bool OGRSimpleCurve::setNumPoints(int nNewPointCount, int bZeroizeNewContent)
     448             : 
     449             : {
     450    21579600 :     CPLAssert(nNewPointCount >= 0);
     451             : 
     452    21579600 :     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     8637790 :         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          12 :                      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    13548900 :             (nPointCount == 0 ||
     474     4911110 :              nNewPointCount > std::numeric_limits<int>::max() /
     475     4911110 :                                       static_cast<int>(sizeof(OGRRawPoint)) -
     476     4911110 :                                   nNewPointCount / 3)
     477     8637770 :                 ? nNewPointCount
     478     4911110 :                 : nNewPointCount + nNewPointCount / 3;
     479             : 
     480     8637770 :         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          19 :             VSIFree(paoPoints);
     486          19 :             paoPoints = nullptr;
     487          19 :             VSIFree(padfZ);
     488          19 :             padfZ = nullptr;
     489          19 :             VSIFree(padfM);
     490          19 :             padfM = nullptr;
     491          19 :             m_nPointCapacity = 0;
     492             :         }
     493             : 
     494             :         OGRRawPoint *paoNewPoints = static_cast<OGRRawPoint *>(
     495     8637770 :             VSI_REALLOC_VERBOSE(paoPoints, sizeof(OGRRawPoint) * nNewCapacity));
     496     8637770 :         if (paoNewPoints == nullptr)
     497             :         {
     498           0 :             return false;
     499             :         }
     500     8637770 :         paoPoints = paoNewPoints;
     501             : 
     502     8637770 :         if (flags & OGR_G_3D)
     503             :         {
     504             :             double *padfNewZ = static_cast<double *>(
     505     3865920 :                 VSI_REALLOC_VERBOSE(padfZ, sizeof(double) * nNewCapacity));
     506     3865920 :             if (padfNewZ == nullptr)
     507             :             {
     508           0 :                 return false;
     509             :             }
     510     3865920 :             padfZ = padfNewZ;
     511             :         }
     512             : 
     513     8637770 :         if (flags & OGR_G_MEASURED)
     514             :         {
     515             :             double *padfNewM = static_cast<double *>(
     516        4419 :                 VSI_REALLOC_VERBOSE(padfM, sizeof(double) * nNewCapacity));
     517        4419 :             if (padfNewM == nullptr)
     518             :             {
     519           0 :                 return false;
     520             :             }
     521        4419 :             padfM = padfNewM;
     522             :         }
     523             : 
     524     8637770 :         m_nPointCapacity = nNewCapacity;
     525             :     }
     526             : 
     527    21579600 :     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    19526600 :         void *dest = static_cast<void *>(paoPoints + nPointCount);
     535    19526600 :         memset(dest, 0, sizeof(OGRRawPoint) * (nNewPointCount - nPointCount));
     536             : 
     537    19526600 :         if ((flags & OGR_G_3D) && padfZ)
     538     5503670 :             memset(padfZ + nPointCount, 0,
     539     5503670 :                    sizeof(double) * (nNewPointCount - nPointCount));
     540             : 
     541    19526600 :         if ((flags & OGR_G_MEASURED) && padfM)
     542         409 :             memset(padfM + nPointCount, 0,
     543         409 :                    sizeof(double) * (nNewPointCount - nPointCount));
     544             :     }
     545             : 
     546    21579600 :     nPointCount = nNewPointCount;
     547    21579600 :     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        1602 : bool OGRSimpleCurve::setPoint(int iPoint, OGRPoint *poPoint)
     569             : 
     570             : {
     571        1602 :     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        1543 :     else if (flags & OGR_G_3D)
     575         864 :         return setPoint(iPoint, poPoint->getX(), poPoint->getY(),
     576         864 :                         poPoint->getZ());
     577         679 :     else if (flags & OGR_G_MEASURED)
     578           3 :         return setPointM(iPoint, poPoint->getX(), poPoint->getY(),
     579           3 :                          poPoint->getM());
     580             :     else
     581         676 :         return setPoint(iPoint, poPoint->getX(), poPoint->getY());
     582             : }
     583             : 
     584             : /************************************************************************/
     585             : /*                           CheckPointCount()                          */
     586             : /************************************************************************/
     587             : 
     588    19507400 : static inline bool CheckPointCount(int iPoint)
     589             : {
     590    19507400 :     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    19507400 :     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     5563110 : bool OGRSimpleCurve::setPoint(int iPoint, double xIn, double yIn, double zIn)
     619             : 
     620             : {
     621     5563110 :     if (!(flags & OGR_G_3D))
     622             :     {
     623     1263540 :         if (!Make3D())
     624           0 :             return false;
     625             :     }
     626             : 
     627     5563110 :     if (iPoint >= nPointCount)
     628             :     {
     629     5503410 :         if (!CheckPointCount(iPoint) || !setNumPoints(iPoint + 1))
     630           1 :             return false;
     631             :     }
     632             : #ifdef DEBUG
     633     5563100 :     if (paoPoints == nullptr)
     634           0 :         return false;
     635             : #endif
     636             : 
     637     5563100 :     paoPoints[iPoint].x = xIn;
     638     5563100 :     paoPoints[iPoint].y = yIn;
     639             : 
     640     5563100 :     if (padfZ != nullptr)
     641             :     {
     642     5563100 :         padfZ[iPoint] = zIn;
     643             :     }
     644     5563100 :     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    27708700 : bool OGRSimpleCurve::setPoint(int iPoint, double xIn, double yIn)
     764             : 
     765             : {
     766    27708700 :     if (iPoint >= nPointCount)
     767             :     {
     768    14003700 :         if (!CheckPointCount(iPoint) || !setNumPoints(iPoint + 1) || !paoPoints)
     769           2 :             return false;
     770             :     }
     771             : 
     772    27708700 :     paoPoints[iPoint].x = xIn;
     773    27708700 :     paoPoints[iPoint].y = yIn;
     774    27708700 :     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        7157 : bool OGRSimpleCurve::setZ(int iPoint, double zIn)
     796             : {
     797        7157 :     if (getCoordinateDimension() == 2)
     798             :     {
     799         860 :         if (!Make3D())
     800           0 :             return false;
     801             :     }
     802             : 
     803        7157 :     if (iPoint >= nPointCount)
     804             :     {
     805           0 :         if (!CheckPointCount(iPoint) || !setNumPoints(iPoint + 1))
     806           0 :             return false;
     807             :     }
     808             : 
     809        7157 :     if (padfZ != nullptr)
     810        7157 :         padfZ[iPoint] = zIn;
     811        7157 :     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         842 : bool OGRSimpleCurve::setM(int iPoint, double mIn)
     833             : {
     834         842 :     if (!(flags & OGR_G_MEASURED))
     835             :     {
     836         103 :         if (!AddM())
     837           0 :             return false;
     838             :     }
     839             : 
     840         842 :     if (iPoint >= nPointCount)
     841             :     {
     842           0 :         if (!CheckPointCount(iPoint) || !setNumPoints(iPoint + 1))
     843           0 :             return false;
     844             :     }
     845             : 
     846         842 :     if (padfM != nullptr)
     847         842 :         padfM[iPoint] = mIn;
     848         842 :     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     5023370 : bool OGRSimpleCurve::addPoint(const OGRPoint *poPoint)
     868             : 
     869             : {
     870     5023370 :     if (poPoint->Is3D() && poPoint->IsMeasured())
     871         250 :         return setPoint(nPointCount, poPoint->getX(), poPoint->getY(),
     872         250 :                         poPoint->getZ(), poPoint->getM());
     873     5023120 :     else if (poPoint->Is3D())
     874     4986960 :         return setPoint(nPointCount, poPoint->getX(), poPoint->getY(),
     875     4986960 :                         poPoint->getZ());
     876       36157 :     else if (poPoint->IsMeasured())
     877           0 :         return setPointM(nPointCount, poPoint->getX(), poPoint->getY(),
     878           0 :                          poPoint->getM());
     879             :     else
     880       36157 :         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      507279 : bool OGRSimpleCurve::addPoint(double x, double y, double z)
     923             : 
     924             : {
     925      507279 :     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    13905600 : bool OGRSimpleCurve::addPoint(double x, double y)
     942             : 
     943             : {
     944    13905600 :     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             :     {
    1035         190 :         const void *pUnaligned = paoPointsIn;
    1036         190 :         memcpy(paoPoints, pUnaligned, sizeof(OGRRawPoint) * nPointsIn);
    1037             :     }
    1038             : 
    1039             :     /* -------------------------------------------------------------------- */
    1040             :     /*      Check measures.                                                 */
    1041             :     /* -------------------------------------------------------------------- */
    1042         190 :     if (padfMIn == nullptr && (flags & OGR_G_MEASURED))
    1043             :     {
    1044           0 :         RemoveM();
    1045             :     }
    1046         190 :     else if (padfMIn)
    1047             :     {
    1048         190 :         if (!AddM())
    1049           0 :             return false;
    1050         190 :         if (padfM && nPointsIn)
    1051             :         {
    1052         190 :             const void *pUnaligned = padfMIn;
    1053         190 :             memcpy(padfM, pUnaligned, sizeof(double) * nPointsIn);
    1054             :         }
    1055             :     }
    1056         190 :     return true;
    1057             : }
    1058             : 
    1059             : /************************************************************************/
    1060             : /*                             setPoints()                              */
    1061             : /************************************************************************/
    1062             : 
    1063             : /**
    1064             :  * \brief Assign all points in a line string.
    1065             :  *
    1066             :  * This method clears any existing points assigned to this line string,
    1067             :  * and assigns a whole new set.  It is the most efficient way of assigning
    1068             :  * the value of a line string.
    1069             :  *
    1070             :  * There is no SFCOM analog to this method.
    1071             :  *
    1072             :  * @param nPointsIn number of points being passed in paoPointsIn
    1073             :  * @param paoPointsIn list of points being assigned.
    1074             :  * @param padfZIn the Z values that go with the points.
    1075             :  * @param padfMIn the M values that go with the points.
    1076             :  * @return (since 3.10) true in case of success, false in case of memory allocation error
    1077             :  */
    1078             : 
    1079     1855230 : bool OGRSimpleCurve::setPoints(int nPointsIn, const OGRRawPoint *paoPointsIn,
    1080             :                                const double *padfZIn, const double *padfMIn)
    1081             : 
    1082             : {
    1083     1855230 :     if (!setNumPoints(nPointsIn, FALSE)
    1084             : #ifdef DEBUG
    1085     1855230 :         || paoPoints == nullptr
    1086             : #endif
    1087             :     )
    1088          89 :         return false;
    1089             : 
    1090     1855140 :     if (nPointsIn)
    1091             :     {
    1092     1855140 :         const void *pUnaligned = paoPointsIn;
    1093     1855140 :         memcpy(paoPoints, pUnaligned, sizeof(OGRRawPoint) * nPointsIn);
    1094             :     }
    1095             : 
    1096             :     /* -------------------------------------------------------------------- */
    1097             :     /*      Check 2D/3D.                                                    */
    1098             :     /* -------------------------------------------------------------------- */
    1099     1855140 :     if (padfZIn == nullptr && getCoordinateDimension() > 2)
    1100             :     {
    1101           0 :         Make2D();
    1102             :     }
    1103     1855140 :     else if (padfZIn)
    1104             :     {
    1105     1352330 :         if (!Make3D())
    1106           0 :             return false;
    1107     1352330 :         if (padfZ && nPointsIn)
    1108             :         {
    1109     1352330 :             const void *pUnaligned = padfZIn;
    1110     1352330 :             memcpy(padfZ, pUnaligned, sizeof(double) * nPointsIn);
    1111             :         }
    1112             :     }
    1113             : 
    1114             :     /* -------------------------------------------------------------------- */
    1115             :     /*      Check measures.                                                 */
    1116             :     /* -------------------------------------------------------------------- */
    1117     1855140 :     if (padfMIn == nullptr && (flags & OGR_G_MEASURED))
    1118             :     {
    1119           0 :         RemoveM();
    1120             :     }
    1121     1855140 :     else if (padfMIn)
    1122             :     {
    1123         598 :         if (!AddM())
    1124           0 :             return false;
    1125         598 :         if (padfM && nPointsIn)
    1126             :         {
    1127         598 :             const void *pUnaligned = padfMIn;
    1128         598 :             memcpy(padfM, pUnaligned, sizeof(double) * nPointsIn);
    1129             :         }
    1130             :     }
    1131     1855140 :     return true;
    1132             : }
    1133             : 
    1134             : /************************************************************************/
    1135             : /*                             setPoints()                              */
    1136             : /************************************************************************/
    1137             : 
    1138             : /**
    1139             :  * \brief Assign all points in a line string.
    1140             :  *
    1141             :  * This method clears any existing points assigned to this line string,
    1142             :  * and assigns a whole new set.  It is the most efficient way of assigning
    1143             :  * the value of a line string.
    1144             :  *
    1145             :  * There is no SFCOM analog to this method.
    1146             :  *
    1147             :  * @param nPointsIn number of points being passed in paoPointsIn
    1148             :  * @param paoPointsIn list of points being assigned.
    1149             :  * @param padfZIn the Z values that go with the points (optional, may be NULL).
    1150             :  * @return (since 3.10) true in case of success, false in case of memory allocation error
    1151             :  */
    1152             : 
    1153       20624 : bool OGRSimpleCurve::setPoints(int nPointsIn, const OGRRawPoint *paoPointsIn,
    1154             :                                const double *padfZIn)
    1155             : 
    1156             : {
    1157       20624 :     if (!setNumPoints(nPointsIn, FALSE)
    1158             : #ifdef DEBUG
    1159       20624 :         || paoPoints == nullptr
    1160             : #endif
    1161             :     )
    1162           7 :         return false;
    1163             : 
    1164       20617 :     if (nPointsIn)
    1165             :     {
    1166       20617 :         const void *pUnaligned = paoPointsIn;
    1167       20617 :         memcpy(paoPoints, pUnaligned, sizeof(OGRRawPoint) * nPointsIn);
    1168             :     }
    1169             : 
    1170             :     /* -------------------------------------------------------------------- */
    1171             :     /*      Check 2D/3D.                                                    */
    1172             :     /* -------------------------------------------------------------------- */
    1173       20617 :     if (padfZIn == nullptr && getCoordinateDimension() > 2)
    1174             :     {
    1175           0 :         Make2D();
    1176             :     }
    1177       20617 :     else if (padfZIn)
    1178             :     {
    1179        1237 :         if (!Make3D())
    1180           0 :             return false;
    1181        1237 :         if (padfZ && nPointsIn)
    1182             :         {
    1183        1237 :             const void *pUnaligned = padfZIn;
    1184        1237 :             memcpy(padfZ, pUnaligned, sizeof(double) * nPointsIn);
    1185             :         }
    1186             :     }
    1187       20617 :     return true;
    1188             : }
    1189             : 
    1190             : /************************************************************************/
    1191             : /*                             setPoints()                              */
    1192             : /************************************************************************/
    1193             : 
    1194             : /**
    1195             :  * \brief Assign all points in a line string.
    1196             :  *
    1197             :  * This method clear any existing points assigned to this line string,
    1198             :  * and assigns a whole new set.
    1199             :  *
    1200             :  * There is no SFCOM analog to this method.
    1201             :  *
    1202             :  * @param nPointsIn number of points being passed in padfX and padfY.
    1203             :  * @param padfX list of X coordinates of points being assigned.
    1204             :  * @param padfY list of Y coordinates of points being assigned.
    1205             :  * @param padfZIn list of Z coordinates of points being assigned (defaults to
    1206             :  * NULL for 2D objects).
    1207             :  * @return (since 3.10) true in case of success, false in case of memory allocation error
    1208             :  */
    1209             : 
    1210       48369 : bool OGRSimpleCurve::setPoints(int nPointsIn, const double *padfX,
    1211             :                                const double *padfY, const double *padfZIn)
    1212             : 
    1213             : {
    1214             :     /* -------------------------------------------------------------------- */
    1215             :     /*      Check 2D/3D.                                                    */
    1216             :     /* -------------------------------------------------------------------- */
    1217       48369 :     if (padfZIn == nullptr)
    1218       40070 :         Make2D();
    1219             :     else
    1220             :     {
    1221        8299 :         if (!Make3D())
    1222           0 :             return false;
    1223             :     }
    1224             : 
    1225             :     /* -------------------------------------------------------------------- */
    1226             :     /*      Assign values.                                                  */
    1227             :     /* -------------------------------------------------------------------- */
    1228       48369 :     if (!setNumPoints(nPointsIn, FALSE))
    1229           0 :         return false;
    1230             : 
    1231      567342 :     for (int i = 0; i < nPointsIn; i++)
    1232             :     {
    1233      518973 :         paoPoints[i].x = padfX[i];
    1234      518973 :         paoPoints[i].y = padfY[i];
    1235             :     }
    1236             : 
    1237       48369 :     if (padfZ && padfZIn && nPointsIn)
    1238             :     {
    1239        8299 :         const void *pUnaligned = padfZIn;
    1240        8299 :         memcpy(padfZ, pUnaligned, sizeof(double) * nPointsIn);
    1241             :     }
    1242       48369 :     return true;
    1243             : }
    1244             : 
    1245             : /************************************************************************/
    1246             : /*                             setPointsM()                             */
    1247             : /************************************************************************/
    1248             : 
    1249             : /**
    1250             :  * \brief Assign all points in a line string.
    1251             :  *
    1252             :  * This method clear any existing points assigned to this line string,
    1253             :  * and assigns a whole new set.
    1254             :  *
    1255             :  * There is no SFCOM analog to this method.
    1256             :  *
    1257             :  * @param nPointsIn number of points being passed in padfX and padfY.
    1258             :  * @param padfX list of X coordinates of points being assigned.
    1259             :  * @param padfY list of Y coordinates of points being assigned.
    1260             :  * @param padfMIn list of M coordinates of points being assigned.
    1261             :  * @return (since 3.10) true in case of success, false in case of memory allocation error
    1262             :  */
    1263             : 
    1264          22 : bool OGRSimpleCurve::setPointsM(int nPointsIn, const double *padfX,
    1265             :                                 const double *padfY, const double *padfMIn)
    1266             : 
    1267             : {
    1268             :     /* -------------------------------------------------------------------- */
    1269             :     /*      Check 2D/3D.                                                    */
    1270             :     /* -------------------------------------------------------------------- */
    1271          22 :     if (padfMIn == nullptr)
    1272           4 :         RemoveM();
    1273             :     else
    1274             :     {
    1275          18 :         if (!AddM())
    1276           0 :             return false;
    1277             :     }
    1278             : 
    1279             :     /* -------------------------------------------------------------------- */
    1280             :     /*      Assign values.                                                  */
    1281             :     /* -------------------------------------------------------------------- */
    1282          22 :     if (!setNumPoints(nPointsIn, FALSE))
    1283           0 :         return false;
    1284             : 
    1285          90 :     for (int i = 0; i < nPointsIn; i++)
    1286             :     {
    1287          68 :         paoPoints[i].x = padfX[i];
    1288          68 :         paoPoints[i].y = padfY[i];
    1289             :     }
    1290             : 
    1291          22 :     if (padfMIn && padfM && nPointsIn)
    1292             :     {
    1293          18 :         const void *pUnaligned = padfMIn;
    1294          18 :         memcpy(padfM, pUnaligned, sizeof(double) * nPointsIn);
    1295             :     }
    1296          22 :     return true;
    1297             : }
    1298             : 
    1299             : /************************************************************************/
    1300             : /*                             setPoints()                              */
    1301             : /************************************************************************/
    1302             : 
    1303             : /**
    1304             :  * \brief Assign all points in a line string.
    1305             :  *
    1306             :  * This method clear any existing points assigned to this line string,
    1307             :  * and assigns a whole new set.
    1308             :  *
    1309             :  * There is no SFCOM analog to this method.
    1310             :  *
    1311             :  * @param nPointsIn number of points being passed in padfX and padfY.
    1312             :  * @param padfX list of X coordinates of points being assigned.
    1313             :  * @param padfY list of Y coordinates of points being assigned.
    1314             :  * @param padfZIn list of Z coordinates of points being assigned.
    1315             :  * @param padfMIn list of M coordinates of points being assigned.
    1316             :  * @return (since 3.10) true in case of success, false in case of memory allocation error
    1317             :  */
    1318             : 
    1319        3281 : bool OGRSimpleCurve::setPoints(int nPointsIn, const double *padfX,
    1320             :                                const double *padfY, const double *padfZIn,
    1321             :                                const double *padfMIn)
    1322             : 
    1323             : {
    1324             :     /* -------------------------------------------------------------------- */
    1325             :     /*      Check 2D/3D.                                                    */
    1326             :     /* -------------------------------------------------------------------- */
    1327        3281 :     if (padfZIn == nullptr)
    1328          66 :         Make2D();
    1329             :     else
    1330             :     {
    1331        3215 :         if (!Make3D())
    1332           0 :             return false;
    1333             :     }
    1334             : 
    1335             :     /* -------------------------------------------------------------------- */
    1336             :     /*      Check measures.                                                 */
    1337             :     /* -------------------------------------------------------------------- */
    1338        3281 :     if (padfMIn == nullptr)
    1339        3253 :         RemoveM();
    1340             :     else
    1341             :     {
    1342          28 :         if (!AddM())
    1343           0 :             return false;
    1344             :     }
    1345             : 
    1346             :     /* -------------------------------------------------------------------- */
    1347             :     /*      Assign values.                                                  */
    1348             :     /* -------------------------------------------------------------------- */
    1349        3281 :     if (!setNumPoints(nPointsIn, FALSE))
    1350           0 :         return false;
    1351             : 
    1352       60728 :     for (int i = 0; i < nPointsIn; i++)
    1353             :     {
    1354       57447 :         paoPoints[i].x = padfX[i];
    1355       57447 :         paoPoints[i].y = padfY[i];
    1356             :     }
    1357             : 
    1358        3281 :     if (padfZ != nullptr && padfZIn && nPointsIn)
    1359             :     {
    1360        3215 :         const void *pUnaligned = padfZIn;
    1361        3215 :         memcpy(padfZ, pUnaligned, sizeof(double) * nPointsIn);
    1362             :     }
    1363        3281 :     if (padfM != nullptr && padfMIn && nPointsIn)
    1364             :     {
    1365          28 :         const void *pUnaligned = padfMIn;
    1366          28 :         memcpy(padfM, pUnaligned, sizeof(double) * nPointsIn);
    1367             :     }
    1368        3281 :     return true;
    1369             : }
    1370             : 
    1371             : /************************************************************************/
    1372             : /*                          getPoints()                                 */
    1373             : /************************************************************************/
    1374             : 
    1375             : /**
    1376             :  * \brief Returns all points of line string.
    1377             :  *
    1378             :  * This method copies all points into user list. This list must be at
    1379             :  * least sizeof(OGRRawPoint) * OGRGeometry::getNumPoints() byte in size.
    1380             :  * It also copies all Z coordinates.
    1381             :  *
    1382             :  * There is no SFCOM analog to this method.
    1383             :  *
    1384             :  * @param paoPointsOut a buffer into which the points is written.
    1385             :  * @param padfZOut the Z values that go with the points (optional, may be NULL).
    1386             :  */
    1387             : 
    1388         329 : void OGRSimpleCurve::getPoints(OGRRawPoint *paoPointsOut,
    1389             :                                double *padfZOut) const
    1390             : {
    1391         329 :     if (!paoPointsOut || nPointCount == 0)
    1392           3 :         return;
    1393             : 
    1394             :     {
    1395         326 :         void *pUnaligned = paoPointsOut;
    1396         326 :         memcpy(pUnaligned, paoPoints, sizeof(OGRRawPoint) * nPointCount);
    1397             :     }
    1398             : 
    1399             :     /* -------------------------------------------------------------------- */
    1400             :     /*      Check 2D/3D.                                                    */
    1401             :     /* -------------------------------------------------------------------- */
    1402         326 :     if (padfZOut)
    1403             :     {
    1404          77 :         void *pUnaligned = padfZOut;
    1405          77 :         if (padfZ)
    1406          75 :             memcpy(pUnaligned, padfZ, sizeof(double) * nPointCount);
    1407             :         else
    1408           2 :             memset(pUnaligned, 0, sizeof(double) * nPointCount);
    1409             :     }
    1410             : }
    1411             : 
    1412             : /**
    1413             :  * \brief Returns all points of line string.
    1414             :  *
    1415             :  * This method copies all points into user arrays. The user provides the
    1416             :  * stride between 2 consecutive elements of the array.
    1417             :  *
    1418             :  * On some CPU architectures, care must be taken so that the arrays are properly
    1419             :  * aligned.
    1420             :  *
    1421             :  * There is no SFCOM analog to this method.
    1422             :  *
    1423             :  * @param pabyX a buffer of at least (nXStride * nPointCount) bytes, may be
    1424             :  * NULL.
    1425             :  * @param nXStride the number of bytes between 2 elements of pabyX.
    1426             :  * @param pabyY a buffer of at least (nYStride * nPointCount) bytes, may be
    1427             :  * NULL.
    1428             :  * @param nYStride the number of bytes between 2 elements of pabyY.
    1429             :  * @param pabyZ a buffer of at last size (nZStride * nPointCount) bytes, may be
    1430             :  * NULL.
    1431             :  * @param nZStride the number of bytes between 2 elements of pabyZ.
    1432             :  * @param pabyM a buffer of at last size (nMStride * nPointCount) bytes, may be
    1433             :  * NULL.
    1434             :  * @param nMStride the number of bytes between 2 elements of pabyM.
    1435             :  *
    1436             :  * @since OGR 2.1.0
    1437             :  */
    1438             : 
    1439         186 : void OGRSimpleCurve::getPoints(void *pabyX, int nXStride, void *pabyY,
    1440             :                                int nYStride, void *pabyZ, int nZStride,
    1441             :                                void *pabyM, int nMStride) const
    1442             : {
    1443         186 :     if (pabyX != nullptr && nXStride == 0)
    1444           0 :         return;
    1445         186 :     if (pabyY != nullptr && nYStride == 0)
    1446           0 :         return;
    1447         186 :     if (pabyZ != nullptr && nZStride == 0)
    1448           0 :         return;
    1449         186 :     if (pabyM != nullptr && nMStride == 0)
    1450           0 :         return;
    1451         186 :     if (nXStride == sizeof(OGRRawPoint) && nYStride == sizeof(OGRRawPoint) &&
    1452             :         static_cast<char *>(pabyY) ==
    1453         186 :             static_cast<char *>(pabyX) + sizeof(double) &&
    1454          77 :         (pabyZ == nullptr || nZStride == sizeof(double)))
    1455             :     {
    1456         186 :         getPoints(static_cast<OGRRawPoint *>(pabyX),
    1457             :                   static_cast<double *>(pabyZ));
    1458             :     }
    1459             :     else
    1460             :     {
    1461           0 :         for (int i = 0; i < nPointCount; i++)
    1462             :         {
    1463           0 :             if (pabyX)
    1464           0 :                 *reinterpret_cast<double *>(static_cast<char *>(pabyX) +
    1465           0 :                                             i * nXStride) = paoPoints[i].x;
    1466           0 :             if (pabyY)
    1467           0 :                 *reinterpret_cast<double *>(static_cast<char *>(pabyY) +
    1468           0 :                                             i * nYStride) = paoPoints[i].y;
    1469             :         }
    1470             : 
    1471           0 :         if (pabyZ)
    1472             :         {
    1473           0 :             if (nZStride == sizeof(double))
    1474             :             {
    1475           0 :                 if (padfZ)
    1476           0 :                     memcpy(pabyZ, padfZ, sizeof(double) * nPointCount);
    1477             :                 else
    1478           0 :                     memset(pabyZ, 0, sizeof(double) * nPointCount);
    1479             :             }
    1480             :             else
    1481             :             {
    1482           0 :                 for (int i = 0; i < nPointCount; i++)
    1483             :                 {
    1484           0 :                     *reinterpret_cast<double *>(static_cast<char *>(pabyZ) +
    1485           0 :                                                 i * nZStride) =
    1486           0 :                         (padfZ) ? padfZ[i] : 0.0;
    1487             :                 }
    1488             :             }
    1489             :         }
    1490             :     }
    1491         186 :     if (pabyM)
    1492             :     {
    1493          58 :         if (nMStride == sizeof(double))
    1494             :         {
    1495          58 :             if (padfM)
    1496          58 :                 memcpy(pabyM, padfM, sizeof(double) * nPointCount);
    1497             :             else
    1498           0 :                 memset(pabyM, 0, sizeof(double) * nPointCount);
    1499             :         }
    1500             :         else
    1501             :         {
    1502           0 :             for (int i = 0; i < nPointCount; i++)
    1503             :             {
    1504           0 :                 *reinterpret_cast<double *>(static_cast<char *>(pabyM) +
    1505           0 :                                             i * nMStride) =
    1506           0 :                     (padfM) ? padfM[i] : 0.0;
    1507             :             }
    1508             :         }
    1509             :     }
    1510             : }
    1511             : 
    1512             : /************************************************************************/
    1513             : /*                           reversePoints()                            */
    1514             : /************************************************************************/
    1515             : 
    1516             : /**
    1517             :  * \brief Reverse point order.
    1518             :  *
    1519             :  * This method updates the points in this line string in place
    1520             :  * reversing the point ordering (first for last, etc).
    1521             :  */
    1522             : 
    1523        2533 : void OGRSimpleCurve::reversePoints()
    1524             : 
    1525             : {
    1526       62843 :     for (int i = 0; i < nPointCount / 2; i++)
    1527             :     {
    1528       60310 :         std::swap(paoPoints[i], paoPoints[nPointCount - i - 1]);
    1529       60310 :         if (padfZ)
    1530             :         {
    1531        2401 :             std::swap(padfZ[i], padfZ[nPointCount - i - 1]);
    1532             :         }
    1533             : 
    1534       60310 :         if (padfM)
    1535             :         {
    1536           6 :             std::swap(padfM[i], padfM[nPointCount - i - 1]);
    1537             :         }
    1538             :     }
    1539        2533 : }
    1540             : 
    1541             : /************************************************************************/
    1542             : /*                          addSubLineString()                          */
    1543             : /************************************************************************/
    1544             : 
    1545             : /**
    1546             :  * \brief Add a segment of another linestring to this one.
    1547             :  *
    1548             :  * Adds the request range of vertices to the end of this line string
    1549             :  * in an efficient manner.  If the nStartVertex is larger than the
    1550             :  * nEndVertex then the vertices will be reversed as they are copied.
    1551             :  *
    1552             :  * @param poOtherLine the other OGRLineString.
    1553             :  * @param nStartVertex the first vertex to copy, defaults to 0 to start
    1554             :  * with the first vertex in the other linestring.
    1555             :  * @param nEndVertex the last vertex to copy, defaults to -1 indicating
    1556             :  * the last vertex of the other line string.
    1557             :  */
    1558             : 
    1559        9233 : void OGRSimpleCurve::addSubLineString(const OGRLineString *poOtherLine,
    1560             :                                       int nStartVertex, int nEndVertex)
    1561             : 
    1562             : {
    1563        9233 :     int nOtherLineNumPoints = poOtherLine->getNumPoints();
    1564        9233 :     if (nOtherLineNumPoints == 0)
    1565           0 :         return;
    1566             : 
    1567             :     /* -------------------------------------------------------------------- */
    1568             :     /*      Do a bit of argument defaulting and validation.                 */
    1569             :     /* -------------------------------------------------------------------- */
    1570        9233 :     if (nEndVertex == -1)
    1571        6453 :         nEndVertex = nOtherLineNumPoints - 1;
    1572             : 
    1573        9233 :     if (nStartVertex < 0 || nEndVertex < 0 ||
    1574        9233 :         nStartVertex >= nOtherLineNumPoints ||
    1575             :         nEndVertex >= nOtherLineNumPoints)
    1576             :     {
    1577           0 :         CPLAssert(false);
    1578             :         return;
    1579             :     }
    1580             : 
    1581             :     /* -------------------------------------------------------------------- */
    1582             :     /*      Grow this linestring to hold the additional points.             */
    1583             :     /* -------------------------------------------------------------------- */
    1584        9233 :     int nOldPoints = nPointCount;
    1585        9233 :     int nPointsToAdd = std::abs(nEndVertex - nStartVertex) + 1;
    1586             : 
    1587        9233 :     if (!setNumPoints(nPointsToAdd + nOldPoints, FALSE)
    1588             : #ifdef DEBUG
    1589        9233 :         || paoPoints == nullptr
    1590             : #endif
    1591             :     )
    1592           0 :         return;
    1593             : 
    1594             :     /* -------------------------------------------------------------------- */
    1595             :     /*      Copy the x/y points - forward copies use memcpy.                */
    1596             :     /* -------------------------------------------------------------------- */
    1597        9233 :     if (nEndVertex >= nStartVertex)
    1598             :     {
    1599        9042 :         memcpy(paoPoints + nOldPoints, poOtherLine->paoPoints + nStartVertex,
    1600        9042 :                sizeof(OGRRawPoint) * nPointsToAdd);
    1601        9042 :         if (poOtherLine->padfZ != nullptr)
    1602             :         {
    1603        1171 :             Make3D();
    1604        1171 :             if (padfZ != nullptr)
    1605             :             {
    1606        1171 :                 memcpy(padfZ + nOldPoints, poOtherLine->padfZ + nStartVertex,
    1607        1171 :                        sizeof(double) * nPointsToAdd);
    1608             :             }
    1609             :         }
    1610        9042 :         if (poOtherLine->padfM != nullptr)
    1611             :         {
    1612          92 :             AddM();
    1613          92 :             if (padfM != nullptr)
    1614             :             {
    1615          92 :                 memcpy(padfM + nOldPoints, poOtherLine->padfM + nStartVertex,
    1616          92 :                        sizeof(double) * nPointsToAdd);
    1617             :             }
    1618             :         }
    1619             :     }
    1620             : 
    1621             :     /* -------------------------------------------------------------------- */
    1622             :     /*      Copy the x/y points - reverse copies done double by double.     */
    1623             :     /* -------------------------------------------------------------------- */
    1624             :     else
    1625             :     {
    1626        1480 :         for (int i = 0; i < nPointsToAdd; i++)
    1627             :         {
    1628        1289 :             paoPoints[i + nOldPoints].x =
    1629        1289 :                 poOtherLine->paoPoints[nStartVertex - i].x;
    1630        1289 :             paoPoints[i + nOldPoints].y =
    1631        1289 :                 poOtherLine->paoPoints[nStartVertex - i].y;
    1632             :         }
    1633             : 
    1634         191 :         if (poOtherLine->padfZ != nullptr)
    1635             :         {
    1636           0 :             Make3D();
    1637           0 :             if (padfZ != nullptr)
    1638             :             {
    1639           0 :                 for (int i = 0; i < nPointsToAdd; i++)
    1640             :                 {
    1641           0 :                     padfZ[i + nOldPoints] =
    1642           0 :                         poOtherLine->padfZ[nStartVertex - i];
    1643             :                 }
    1644             :             }
    1645             :         }
    1646         191 :         if (poOtherLine->padfM != nullptr)
    1647             :         {
    1648           0 :             AddM();
    1649           0 :             if (padfM != nullptr)
    1650             :             {
    1651           0 :                 for (int i = 0; i < nPointsToAdd; i++)
    1652             :                 {
    1653           0 :                     padfM[i + nOldPoints] =
    1654           0 :                         poOtherLine->padfM[nStartVertex - i];
    1655             :                 }
    1656             :             }
    1657             :         }
    1658             :     }
    1659             : }
    1660             : 
    1661             : /************************************************************************/
    1662             : /*                           importFromWkb()                            */
    1663             : /*                                                                      */
    1664             : /*      Initialize from serialized stream in well known binary          */
    1665             : /*      format.                                                         */
    1666             : /************************************************************************/
    1667             : 
    1668        7053 : OGRErr OGRSimpleCurve::importFromWkb(const unsigned char *pabyData,
    1669             :                                      size_t nSize, OGRwkbVariant eWkbVariant,
    1670             :                                      size_t &nBytesConsumedOut)
    1671             : 
    1672             : {
    1673             :     OGRwkbByteOrder eByteOrder;
    1674        7053 :     size_t nDataOffset = 0;
    1675        7053 :     int nNewNumPoints = 0;
    1676             : 
    1677        7053 :     nBytesConsumedOut = 0;
    1678        7053 :     OGRErr eErr = importPreambleOfCollectionFromWkb(pabyData, nSize,
    1679             :                                                     nDataOffset, eByteOrder, 16,
    1680             :                                                     nNewNumPoints, eWkbVariant);
    1681        7054 :     if (eErr != OGRERR_NONE)
    1682         203 :         return eErr;
    1683             : 
    1684             :     // Check if the wkb stream buffer is big enough to store
    1685             :     // fetched number of points.
    1686        6851 :     const int dim = CoordinateDimension();
    1687        6852 :     const size_t nPointSize = dim * sizeof(double);
    1688       13704 :     if (nNewNumPoints < 0 ||
    1689        6851 :         static_cast<size_t>(nNewNumPoints) >
    1690        6851 :             std::numeric_limits<size_t>::max() / nPointSize)
    1691             :     {
    1692           0 :         return OGRERR_CORRUPT_DATA;
    1693             :     }
    1694        6853 :     const size_t nBufferMinSize = nPointSize * nNewNumPoints;
    1695             : 
    1696        6853 :     if (nSize != static_cast<size_t>(-1) && nBufferMinSize > nSize)
    1697             :     {
    1698          67 :         CPLError(CE_Failure, CPLE_AppDefined,
    1699             :                  "Length of input WKB is too small");
    1700          67 :         return OGRERR_NOT_ENOUGH_DATA;
    1701             :     }
    1702             : 
    1703        6786 :     if (!setNumPoints(nNewNumPoints, FALSE))
    1704           0 :         return OGRERR_NOT_ENOUGH_MEMORY;
    1705             : 
    1706        6784 :     nBytesConsumedOut = 9 + 8 * static_cast<size_t>(nPointCount) *
    1707        6784 :                                 (2 + ((flags & OGR_G_3D) ? 1 : 0) +
    1708        6784 :                                  ((flags & OGR_G_MEASURED) ? 1 : 0));
    1709             : 
    1710             :     /* -------------------------------------------------------------------- */
    1711             :     /*      Get the vertex.                                                 */
    1712             :     /* -------------------------------------------------------------------- */
    1713        6784 :     if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
    1714             :     {
    1715        8832 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
    1716             :         {
    1717        5328 :             memcpy(paoPoints + i, pabyData + 9 + i * 32, 16);
    1718        5328 :             memcpy(padfZ + i, pabyData + 9 + 16 + i * 32, 8);
    1719        5328 :             memcpy(padfM + i, pabyData + 9 + 24 + i * 32, 8);
    1720        3504 :         }
    1721             :     }
    1722        3280 :     else if (flags & OGR_G_MEASURED)
    1723             :     {
    1724         252 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
    1725             :         {
    1726         185 :             memcpy(paoPoints + i, pabyData + 9 + i * 24, 16);
    1727         185 :             memcpy(padfM + i, pabyData + 9 + 16 + i * 24, 8);
    1728             :         }
    1729             :     }
    1730        3213 :     else if (flags & OGR_G_3D)
    1731             :     {
    1732         574 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
    1733             :         {
    1734         413 :             memcpy(paoPoints + i, pabyData + 9 + i * 24, 16);
    1735         413 :             memcpy(padfZ + i, pabyData + 9 + 16 + i * 24, 8);
    1736             :         }
    1737             :     }
    1738        3052 :     else if (nPointCount)
    1739             :     {
    1740        3018 :         memcpy(paoPoints, pabyData + 9, 16 * static_cast<size_t>(nPointCount));
    1741             :     }
    1742             : 
    1743             :     /* -------------------------------------------------------------------- */
    1744             :     /*      Byte swap if needed.                                            */
    1745             :     /* -------------------------------------------------------------------- */
    1746        6784 :     if (OGR_SWAP(eByteOrder))
    1747             :     {
    1748         440 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
    1749             :         {
    1750         310 :             CPL_SWAPDOUBLE(&(paoPoints[i].x));
    1751         310 :             CPL_SWAPDOUBLE(&(paoPoints[i].y));
    1752             :         }
    1753             : 
    1754         130 :         if (flags & OGR_G_3D)
    1755             :         {
    1756          14 :             for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
    1757             :             {
    1758          10 :                 CPL_SWAPDOUBLE(padfZ + i);
    1759             :             }
    1760             :         }
    1761             : 
    1762         130 :         if (flags & OGR_G_MEASURED)
    1763             :         {
    1764           6 :             for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
    1765             :             {
    1766           4 :                 CPL_SWAPDOUBLE(padfM + i);
    1767             :             }
    1768             :         }
    1769             :     }
    1770             : 
    1771        6784 :     return OGRERR_NONE;
    1772             : }
    1773             : 
    1774             : /************************************************************************/
    1775             : /*                            exportToWkb()                             */
    1776             : /*                                                                      */
    1777             : /*      Build a well known binary representation of this object.        */
    1778             : /************************************************************************/
    1779             : 
    1780       10697 : OGRErr OGRSimpleCurve::exportToWkb(unsigned char *pabyData,
    1781             :                                    const OGRwkbExportOptions *psOptions) const
    1782             : 
    1783             : {
    1784       10697 :     if (psOptions == nullptr)
    1785             :     {
    1786             :         static const OGRwkbExportOptions defaultOptions;
    1787           0 :         psOptions = &defaultOptions;
    1788             :     }
    1789             : 
    1790             :     /* -------------------------------------------------------------------- */
    1791             :     /*      Set the byte order.                                             */
    1792             :     /* -------------------------------------------------------------------- */
    1793       10697 :     pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER(
    1794             :         static_cast<unsigned char>(psOptions->eByteOrder));
    1795             : 
    1796             :     /* -------------------------------------------------------------------- */
    1797             :     /*      Set the geometry feature type.                                  */
    1798             :     /* -------------------------------------------------------------------- */
    1799       10697 :     GUInt32 nGType = getGeometryType();
    1800             : 
    1801       10697 :     if (psOptions->eWkbVariant == wkbVariantPostGIS1)
    1802             :     {
    1803           6 :         nGType = wkbFlatten(nGType);
    1804           6 :         if (Is3D())
    1805             :             // Explicitly set wkb25DBit.
    1806           1 :             nGType =
    1807           1 :                 static_cast<OGRwkbGeometryType>(nGType | wkb25DBitInternalUse);
    1808           6 :         if (IsMeasured())
    1809           0 :             nGType = static_cast<OGRwkbGeometryType>(nGType | 0x40000000);
    1810             :     }
    1811       10691 :     else if (psOptions->eWkbVariant == wkbVariantIso)
    1812       10229 :         nGType = getIsoGeometryType();
    1813             : 
    1814       10697 :     if (psOptions->eByteOrder == wkbNDR)
    1815             :     {
    1816       10684 :         CPL_LSBPTR32(&nGType);
    1817             :     }
    1818             :     else
    1819             :     {
    1820          13 :         CPL_MSBPTR32(&nGType);
    1821             :     }
    1822             : 
    1823       10697 :     memcpy(pabyData + 1, &nGType, 4);
    1824             : 
    1825             :     /* -------------------------------------------------------------------- */
    1826             :     /*      Copy in the data count.                                         */
    1827             :     /* -------------------------------------------------------------------- */
    1828       10697 :     memcpy(pabyData + 5, &nPointCount, 4);
    1829             : 
    1830             :     /* -------------------------------------------------------------------- */
    1831             :     /*      Copy in the raw data.                                           */
    1832             :     /* -------------------------------------------------------------------- */
    1833       10697 :     if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
    1834             :     {
    1835        6367 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
    1836             :         {
    1837        4532 :             memcpy(pabyData + 9 + 32 * i, paoPoints + i, 16);
    1838        4532 :             memcpy(pabyData + 9 + 16 + 32 * i, padfZ + i, 8);
    1839        4532 :             memcpy(pabyData + 9 + 24 + 32 * i, padfM + i, 8);
    1840             :         }
    1841        1835 :         OGRRoundCoordinatesIEEE754XYValues<32>(
    1842        1835 :             psOptions->sPrecision.nXYBitPrecision, pabyData + 9, nPointCount);
    1843        1835 :         OGRRoundCoordinatesIEEE754<32>(psOptions->sPrecision.nZBitPrecision,
    1844             :                                        pabyData + 9 + 2 * sizeof(uint64_t),
    1845        1835 :                                        nPointCount);
    1846        1835 :         OGRRoundCoordinatesIEEE754<32>(psOptions->sPrecision.nMBitPrecision,
    1847             :                                        pabyData + 9 + 3 * sizeof(uint64_t),
    1848        1835 :                                        nPointCount);
    1849             :     }
    1850        8862 :     else if (flags & OGR_G_MEASURED)
    1851             :     {
    1852         234 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
    1853             :         {
    1854         164 :             memcpy(pabyData + 9 + 24 * i, paoPoints + i, 16);
    1855         164 :             memcpy(pabyData + 9 + 16 + 24 * i, padfM + i, 8);
    1856             :         }
    1857          70 :         OGRRoundCoordinatesIEEE754XYValues<24>(
    1858          70 :             psOptions->sPrecision.nXYBitPrecision, pabyData + 9, nPointCount);
    1859          70 :         OGRRoundCoordinatesIEEE754<24>(psOptions->sPrecision.nMBitPrecision,
    1860             :                                        pabyData + 9 + 2 * sizeof(uint64_t),
    1861          70 :                                        nPointCount);
    1862             :     }
    1863        8792 :     else if (flags & OGR_G_3D)
    1864             :     {
    1865       61147 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
    1866             :         {
    1867       57610 :             memcpy(pabyData + 9 + 24 * i, paoPoints + i, 16);
    1868       57610 :             memcpy(pabyData + 9 + 16 + 24 * i, padfZ + i, 8);
    1869             :         }
    1870        3537 :         OGRRoundCoordinatesIEEE754XYValues<24>(
    1871        3537 :             psOptions->sPrecision.nXYBitPrecision, pabyData + 9, nPointCount);
    1872        3537 :         OGRRoundCoordinatesIEEE754<24>(psOptions->sPrecision.nZBitPrecision,
    1873             :                                        pabyData + 9 + 2 * sizeof(uint64_t),
    1874        3537 :                                        nPointCount);
    1875             :     }
    1876        5255 :     else if (nPointCount)
    1877             :     {
    1878        5182 :         memcpy(pabyData + 9, paoPoints, 16 * static_cast<size_t>(nPointCount));
    1879        5182 :         OGRRoundCoordinatesIEEE754XYValues<16>(
    1880        5182 :             psOptions->sPrecision.nXYBitPrecision, pabyData + 9, nPointCount);
    1881             :     }
    1882             : 
    1883             :     /* -------------------------------------------------------------------- */
    1884             :     /*      Swap if needed.                                                 */
    1885             :     /* -------------------------------------------------------------------- */
    1886       10697 :     if (OGR_SWAP(psOptions->eByteOrder))
    1887             :     {
    1888          13 :         const int nCount = CPL_SWAP32(nPointCount);
    1889          13 :         memcpy(pabyData + 5, &nCount, 4);
    1890             : 
    1891             :         const size_t nCoords =
    1892          13 :             CoordinateDimension() * static_cast<size_t>(nPointCount);
    1893         175 :         for (size_t i = 0; i < nCoords; i++)
    1894             :         {
    1895         162 :             CPL_SWAP64PTR(pabyData + 9 + 8 * i);
    1896             :         }
    1897             :     }
    1898             : 
    1899       10697 :     return OGRERR_NONE;
    1900             : }
    1901             : 
    1902             : /************************************************************************/
    1903             : /*                           importFromWkt()                            */
    1904             : /*                                                                      */
    1905             : /*      Instantiate from well known text format.  Currently this is     */
    1906             : /*      `LINESTRING ( x y, x y, ...)',                                  */
    1907             : /************************************************************************/
    1908             : 
    1909        5177 : OGRErr OGRSimpleCurve::importFromWkt(const char **ppszInput)
    1910             : 
    1911             : {
    1912        5177 :     int bHasZ = FALSE;
    1913        5177 :     int bHasM = FALSE;
    1914        5177 :     bool bIsEmpty = false;
    1915             :     const OGRErr eErr =
    1916        5177 :         importPreambleFromWkt(ppszInput, &bHasZ, &bHasM, &bIsEmpty);
    1917        5177 :     flags = 0;
    1918        5177 :     if (eErr != OGRERR_NONE)
    1919           5 :         return eErr;
    1920        5172 :     if (bHasZ)
    1921         303 :         flags |= OGR_G_3D;
    1922        5172 :     if (bHasM)
    1923         135 :         flags |= OGR_G_MEASURED;
    1924        5172 :     if (bIsEmpty)
    1925             :     {
    1926          86 :         return OGRERR_NONE;
    1927             :     }
    1928             : 
    1929        5086 :     const char *pszInput = *ppszInput;
    1930             : 
    1931             :     /* -------------------------------------------------------------------- */
    1932             :     /*      Read the point list.                                            */
    1933             :     /* -------------------------------------------------------------------- */
    1934        5086 :     int flagsFromInput = flags;
    1935        5086 :     nPointCount = 0;
    1936             : 
    1937             :     pszInput =
    1938        5086 :         OGRWktReadPointsM(pszInput, &paoPoints, &padfZ, &padfM, &flagsFromInput,
    1939             :                           &m_nPointCapacity, &nPointCount);
    1940        5086 :     if (pszInput == nullptr)
    1941          15 :         return OGRERR_CORRUPT_DATA;
    1942             : 
    1943        5071 :     if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
    1944             :     {
    1945         246 :         if (!set3D(TRUE))
    1946           0 :             return OGRERR_NOT_ENOUGH_MEMORY;
    1947             :     }
    1948        5071 :     if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
    1949             :     {
    1950           0 :         if (!setMeasured(TRUE))
    1951           0 :             return OGRERR_NOT_ENOUGH_MEMORY;
    1952             :     }
    1953             : 
    1954        5071 :     *ppszInput = pszInput;
    1955             : 
    1956        5071 :     return OGRERR_NONE;
    1957             : }
    1958             : 
    1959             : //! @cond Doxygen_Suppress
    1960             : /************************************************************************/
    1961             : /*                        importFromWKTListOnly()                       */
    1962             : /*                                                                      */
    1963             : /*      Instantiate from "(x y, x y, ...)"                              */
    1964             : /************************************************************************/
    1965             : 
    1966        1362 : OGRErr OGRSimpleCurve::importFromWKTListOnly(const char **ppszInput, int bHasZ,
    1967             :                                              int bHasM,
    1968             :                                              OGRRawPoint *&paoPointsIn,
    1969             :                                              int &nMaxPointsIn,
    1970             :                                              double *&padfZIn)
    1971             : 
    1972             : {
    1973        1362 :     const char *pszInput = *ppszInput;
    1974             : 
    1975             :     /* -------------------------------------------------------------------- */
    1976             :     /*      Read the point list.                                            */
    1977             :     /* -------------------------------------------------------------------- */
    1978        1362 :     int flagsFromInput = flags;
    1979        1362 :     int nPointCountRead = 0;
    1980        1362 :     double *padfMIn = nullptr;
    1981        1362 :     if (flagsFromInput == 0)  // Flags was not set, this is not called by us.
    1982             :     {
    1983        1362 :         if (bHasM)
    1984         124 :             flagsFromInput |= OGR_G_MEASURED;
    1985        1362 :         if (bHasZ)
    1986         197 :             flagsFromInput |= OGR_G_3D;
    1987             :     }
    1988             : 
    1989             :     pszInput =
    1990        1362 :         OGRWktReadPointsM(pszInput, &paoPointsIn, &padfZIn, &padfMIn,
    1991             :                           &flagsFromInput, &nMaxPointsIn, &nPointCountRead);
    1992             : 
    1993        1362 :     if (pszInput == nullptr)
    1994             :     {
    1995           6 :         CPLFree(padfMIn);
    1996           6 :         return OGRERR_CORRUPT_DATA;
    1997             :     }
    1998        1356 :     if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
    1999             :     {
    2000         341 :         flags |= OGR_G_3D;
    2001         341 :         bHasZ = TRUE;
    2002             :     }
    2003        1356 :     if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
    2004             :     {
    2005         124 :         flags |= OGR_G_MEASURED;
    2006         124 :         bHasM = TRUE;
    2007             :     }
    2008             : 
    2009        1356 :     *ppszInput = pszInput;
    2010             : 
    2011        1356 :     if (bHasM && bHasZ)
    2012          72 :         setPoints(nPointCountRead, paoPointsIn, padfZIn, padfMIn);
    2013        1284 :     else if (bHasM && !bHasZ)
    2014          52 :         setPointsM(nPointCountRead, paoPointsIn, padfMIn);
    2015             :     else
    2016        1232 :         setPoints(nPointCountRead, paoPointsIn, padfZIn);
    2017             : 
    2018        1356 :     CPLFree(padfMIn);
    2019             : 
    2020        1356 :     return OGRERR_NONE;
    2021             : }
    2022             : 
    2023             : //! @endcond
    2024             : 
    2025             : /************************************************************************/
    2026             : /*                            exportToWkt()                             */
    2027             : /*                                                                      */
    2028             : /*      Translate this structure into its well known text format       */
    2029             : /*      equivalent.  This could be made a lot more CPU efficient.       */
    2030             : /************************************************************************/
    2031             : 
    2032        3731 : std::string OGRSimpleCurve::exportToWkt(const OGRWktOptions &opts,
    2033             :                                         OGRErr *err) const
    2034             : {
    2035             :     // LINEARRING or LINESTRING or CIRCULARSTRING
    2036        7462 :     std::string wkt = getGeometryName();
    2037        3731 :     wkt += wktTypeString(opts.variant);
    2038        3731 :     if (IsEmpty())
    2039             :     {
    2040          90 :         wkt += "EMPTY";
    2041             :     }
    2042             :     else
    2043             :     {
    2044        3641 :         wkt += '(';
    2045             : 
    2046        3641 :         OGRBoolean hasZ = Is3D();
    2047             :         OGRBoolean hasM =
    2048        3641 :             (opts.variant != wkbVariantIso ? FALSE : IsMeasured());
    2049             : 
    2050             :         try
    2051             :         {
    2052        3641 :             const int nOrdinatesPerVertex =
    2053        3641 :                 2 + ((hasZ) ? 1 : 0) + ((hasM) ? 1 : 0);
    2054             :             // At least 2 bytes per ordinate: one for the value,
    2055             :             // and one for the separator...
    2056        3641 :             wkt.reserve(wkt.size() + 2 * static_cast<size_t>(nPointCount) *
    2057        3641 :                                          nOrdinatesPerVertex);
    2058             : 
    2059       35809 :             for (int i = 0; i < nPointCount; i++)
    2060             :             {
    2061       32168 :                 if (i > 0)
    2062       28527 :                     wkt += ',';
    2063             : 
    2064       91508 :                 wkt += OGRMakeWktCoordinateM(
    2065       60918 :                     paoPoints[i].x, paoPoints[i].y, padfZ ? padfZ[i] : 0.0,
    2066       64336 :                     padfM ? padfM[i] : 0.0, hasZ, hasM, opts);
    2067             :             }
    2068        3641 :             wkt += ')';
    2069             :         }
    2070           0 :         catch (const std::bad_alloc &e)
    2071             :         {
    2072           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
    2073           0 :             if (err)
    2074           0 :                 *err = OGRERR_FAILURE;
    2075           0 :             return std::string();
    2076             :         }
    2077             :     }
    2078        3731 :     if (err)
    2079        3722 :         *err = OGRERR_NONE;
    2080        3731 :     return wkt;
    2081             : }
    2082             : 
    2083             : /************************************************************************/
    2084             : /*                             get_Length()                             */
    2085             : /*                                                                      */
    2086             : /*      For now we return a simple euclidean 2D distance.               */
    2087             : /************************************************************************/
    2088             : 
    2089        1143 : double OGRSimpleCurve::get_Length() const
    2090             : 
    2091             : {
    2092        1143 :     double dfLength = 0.0;
    2093             : 
    2094        3285 :     for (int i = 0; i < nPointCount - 1; i++)
    2095             :     {
    2096             : 
    2097        2142 :         const double dfDeltaX = paoPoints[i + 1].x - paoPoints[i].x;
    2098        2142 :         const double dfDeltaY = paoPoints[i + 1].y - paoPoints[i].y;
    2099        2142 :         dfLength += sqrt(dfDeltaX * dfDeltaX + dfDeltaY * dfDeltaY);
    2100             :     }
    2101             : 
    2102        1143 :     return dfLength;
    2103             : }
    2104             : 
    2105             : /************************************************************************/
    2106             : /*                             StartPoint()                             */
    2107             : /************************************************************************/
    2108             : 
    2109      288055 : void OGRSimpleCurve::StartPoint(OGRPoint *poPoint) const
    2110             : 
    2111             : {
    2112      288055 :     getPoint(0, poPoint);
    2113      288055 : }
    2114             : 
    2115             : /************************************************************************/
    2116             : /*                              EndPoint()                              */
    2117             : /************************************************************************/
    2118             : 
    2119      227815 : void OGRSimpleCurve::EndPoint(OGRPoint *poPoint) const
    2120             : 
    2121             : {
    2122      227815 :     getPoint(nPointCount - 1, poPoint);
    2123      227815 : }
    2124             : 
    2125             : /************************************************************************/
    2126             : /*                               Value()                                */
    2127             : /*                                                                      */
    2128             : /*      Get an interpolated point at some distance along the curve.     */
    2129             : /************************************************************************/
    2130             : 
    2131          52 : void OGRSimpleCurve::Value(double dfDistance, OGRPoint *poPoint) const
    2132             : 
    2133             : {
    2134          52 :     if (dfDistance < 0)
    2135             :     {
    2136           1 :         StartPoint(poPoint);
    2137           1 :         return;
    2138             :     }
    2139             : 
    2140          51 :     double dfLength = 0.0;
    2141             : 
    2142         192 :     for (int i = 0; i < nPointCount - 1; i++)
    2143             :     {
    2144         191 :         const double dfDeltaX = paoPoints[i + 1].x - paoPoints[i].x;
    2145         191 :         const double dfDeltaY = paoPoints[i + 1].y - paoPoints[i].y;
    2146             :         const double dfSegLength =
    2147         191 :             sqrt(dfDeltaX * dfDeltaX + dfDeltaY * dfDeltaY);
    2148             : 
    2149         191 :         if (dfSegLength > 0)
    2150             :         {
    2151         171 :             if ((dfLength <= dfDistance) &&
    2152         171 :                 ((dfLength + dfSegLength) >= dfDistance))
    2153             :             {
    2154          50 :                 double dfRatio = (dfDistance - dfLength) / dfSegLength;
    2155             : 
    2156          50 :                 poPoint->setX(paoPoints[i].x * (1 - dfRatio) +
    2157          50 :                               paoPoints[i + 1].x * dfRatio);
    2158          50 :                 poPoint->setY(paoPoints[i].y * (1 - dfRatio) +
    2159          50 :                               paoPoints[i + 1].y * dfRatio);
    2160             : 
    2161          50 :                 if (getCoordinateDimension() == 3)
    2162           1 :                     poPoint->setZ(padfZ[i] * (1 - dfRatio) +
    2163           1 :                                   padfZ[i + 1] * dfRatio);
    2164             : 
    2165          50 :                 return;
    2166             :             }
    2167             : 
    2168         121 :             dfLength += dfSegLength;
    2169             :         }
    2170             :     }
    2171             : 
    2172           1 :     EndPoint(poPoint);
    2173             : }
    2174             : 
    2175             : /************************************************************************/
    2176             : /*                              Project()                               */
    2177             : /*                                                                      */
    2178             : /* Return distance of point projected on line from origin of this line. */
    2179             : /************************************************************************/
    2180             : 
    2181             : /**
    2182             :  * \brief Project point on linestring.
    2183             :  *
    2184             :  * The input point projected on linestring. This is the shortest distance
    2185             :  * from point to the linestring. The distance from begin of linestring to
    2186             :  * the point projection returned.
    2187             :  *
    2188             :  * This method is built on the GEOS library. Check it for the
    2189             :  * definition of the geometry operation.
    2190             :  * If OGR is built without the GEOS library, this method will always return -1,
    2191             :  * issuing a CPLE_NotSupported error.
    2192             :  *
    2193             :  * @return a distance from the begin of the linestring to the projected point.
    2194             :  */
    2195             : 
    2196          62 : double OGRSimpleCurve::Project(const OGRPoint *poPoint) const
    2197             : 
    2198             : {
    2199          62 :     double dfResult = -1;
    2200             : #ifndef HAVE_GEOS
    2201             :     CPL_IGNORE_RET_VAL(poPoint);
    2202             :     CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
    2203             :     return dfResult;
    2204             : #else
    2205          62 :     GEOSGeom hThisGeosGeom = nullptr;
    2206          62 :     GEOSGeom hPointGeosGeom = nullptr;
    2207             : 
    2208          62 :     GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
    2209          62 :     hThisGeosGeom = exportToGEOS(hGEOSCtxt);
    2210          62 :     hPointGeosGeom = poPoint->exportToGEOS(hGEOSCtxt);
    2211          62 :     if (hThisGeosGeom != nullptr && hPointGeosGeom != nullptr)
    2212             :     {
    2213          62 :         dfResult = GEOSProject_r(hGEOSCtxt, hThisGeosGeom, hPointGeosGeom);
    2214             :     }
    2215          62 :     GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
    2216          62 :     GEOSGeom_destroy_r(hGEOSCtxt, hPointGeosGeom);
    2217          62 :     freeGEOSContext(hGEOSCtxt);
    2218             : 
    2219          62 :     return dfResult;
    2220             : 
    2221             : #endif  // HAVE_GEOS
    2222             : }
    2223             : 
    2224             : /************************************************************************/
    2225             : /*                            getSubLine()                              */
    2226             : /*                                                                      */
    2227             : /*  Extracts a portion of this OGRLineString into a new OGRLineString.  */
    2228             : /************************************************************************/
    2229             : 
    2230             : /**
    2231             :  * \brief Get the portion of linestring.
    2232             :  *
    2233             :  * The portion of the linestring extracted to new one. The input distances
    2234             :  * (maybe present as ratio of length of linestring) set begin and end of
    2235             :  * extracted portion.
    2236             :  *
    2237             :  * @param dfDistanceFrom The distance from the origin of linestring, where the
    2238             :  * subline should begins
    2239             :  * @param dfDistanceTo The distance from the origin of linestring, where the
    2240             :  * subline should ends
    2241             :  * @param bAsRatio The flag indicating that distances are the ratio of the
    2242             :  * linestring length.
    2243             :  *
    2244             :  * @return a newly allocated linestring now owned by the caller, or NULL on
    2245             :  * failure.
    2246             :  *
    2247             :  * @since OGR 1.11.0
    2248             :  */
    2249             : 
    2250          53 : OGRLineString *OGRSimpleCurve::getSubLine(double dfDistanceFrom,
    2251             :                                           double dfDistanceTo,
    2252             :                                           int bAsRatio) const
    2253             : 
    2254             : {
    2255         106 :     auto poNewLineString = std::make_unique<OGRLineString>();
    2256             : 
    2257          53 :     poNewLineString->assignSpatialReference(getSpatialReference());
    2258          53 :     poNewLineString->setCoordinateDimension(getCoordinateDimension());
    2259             : 
    2260          53 :     const double dfLen = get_Length();
    2261          53 :     if (bAsRatio == TRUE)
    2262             :     {
    2263             :         // Convert to real distance.
    2264           0 :         dfDistanceFrom *= dfLen;
    2265           0 :         dfDistanceTo *= dfLen;
    2266             :     }
    2267             : 
    2268          53 :     if (dfDistanceFrom < 0)
    2269           0 :         dfDistanceFrom = 0;
    2270          53 :     if (dfDistanceTo > dfLen)
    2271           0 :         dfDistanceTo = dfLen;
    2272             : 
    2273          53 :     if (dfDistanceFrom > dfDistanceTo || dfDistanceFrom >= dfLen)
    2274             :     {
    2275           0 :         CPLError(CE_Failure, CPLE_IllegalArg, "Input distances are invalid.");
    2276             : 
    2277           0 :         return nullptr;
    2278             :     }
    2279             : 
    2280          53 :     double dfLength = 0.0;
    2281             : 
    2282             :     // Get first point.
    2283             : 
    2284          53 :     int i = 0;  // Used after if blocks.
    2285          53 :     if (dfDistanceFrom == 0)
    2286             :     {
    2287             :         bool bRet;
    2288           5 :         if (getCoordinateDimension() == 3)
    2289           0 :             bRet = poNewLineString->addPoint(paoPoints[0].x, paoPoints[0].y,
    2290           0 :                                              padfZ[0]);
    2291             :         else
    2292           5 :             bRet = poNewLineString->addPoint(paoPoints[0].x, paoPoints[0].y);
    2293           5 :         if (!bRet)
    2294           0 :             return nullptr;
    2295             :     }
    2296             :     else
    2297             :     {
    2298         367 :         for (i = 0; i < nPointCount - 1; i++)
    2299             :         {
    2300         367 :             const double dfDeltaX = paoPoints[i + 1].x - paoPoints[i].x;
    2301         367 :             const double dfDeltaY = paoPoints[i + 1].y - paoPoints[i].y;
    2302             :             const double dfSegLength =
    2303         367 :                 sqrt(dfDeltaX * dfDeltaX + dfDeltaY * dfDeltaY);
    2304             : 
    2305         367 :             if (dfSegLength > 0)
    2306             :             {
    2307         367 :                 if ((dfLength <= dfDistanceFrom) &&
    2308         367 :                     ((dfLength + dfSegLength) >= dfDistanceFrom))
    2309             :                 {
    2310          48 :                     double dfRatio = (dfDistanceFrom - dfLength) / dfSegLength;
    2311             : 
    2312          48 :                     double dfX = paoPoints[i].x * (1 - dfRatio) +
    2313          48 :                                  paoPoints[i + 1].x * dfRatio;
    2314          48 :                     double dfY = paoPoints[i].y * (1 - dfRatio) +
    2315          48 :                                  paoPoints[i + 1].y * dfRatio;
    2316             : 
    2317             :                     bool bRet;
    2318          48 :                     if (getCoordinateDimension() == 3)
    2319             :                     {
    2320           0 :                         bRet = poNewLineString->addPoint(
    2321             :                             dfX, dfY,
    2322           0 :                             padfZ[i] * (1 - dfRatio) + padfZ[i + 1] * dfRatio);
    2323             :                     }
    2324             :                     else
    2325             :                     {
    2326          48 :                         bRet = poNewLineString->addPoint(dfX, dfY);
    2327             :                     }
    2328          48 :                     if (!bRet)
    2329           0 :                         return nullptr;
    2330             : 
    2331             :                     // Check if dfDistanceTo is in same segment.
    2332          48 :                     if (dfLength <= dfDistanceTo &&
    2333          48 :                         (dfLength + dfSegLength) >= dfDistanceTo)
    2334             :                     {
    2335          27 :                         dfRatio = (dfDistanceTo - dfLength) / dfSegLength;
    2336             : 
    2337          27 :                         dfX = paoPoints[i].x * (1 - dfRatio) +
    2338          27 :                               paoPoints[i + 1].x * dfRatio;
    2339          27 :                         dfY = paoPoints[i].y * (1 - dfRatio) +
    2340          27 :                               paoPoints[i + 1].y * dfRatio;
    2341             : 
    2342          27 :                         if (getCoordinateDimension() == 3)
    2343             :                         {
    2344           0 :                             bRet = poNewLineString->addPoint(
    2345             :                                 dfX, dfY,
    2346           0 :                                 padfZ[i] * (1 - dfRatio) +
    2347           0 :                                     padfZ[i + 1] * dfRatio);
    2348             :                         }
    2349             :                         else
    2350             :                         {
    2351          27 :                             bRet = poNewLineString->addPoint(dfX, dfY);
    2352             :                         }
    2353             : 
    2354          27 :                         if (!bRet || poNewLineString->getNumPoints() < 2)
    2355             :                         {
    2356           0 :                             return nullptr;
    2357             :                         }
    2358             : 
    2359          27 :                         return poNewLineString.release();
    2360             :                     }
    2361          21 :                     i++;
    2362          21 :                     dfLength += dfSegLength;
    2363          21 :                     break;
    2364             :                 }
    2365             : 
    2366         319 :                 dfLength += dfSegLength;
    2367             :             }
    2368             :         }
    2369             :     }
    2370             : 
    2371             :     // Add points.
    2372          55 :     for (; i < nPointCount - 1; i++)
    2373             :     {
    2374             :         bool bRet;
    2375          55 :         if (getCoordinateDimension() == 3)
    2376           0 :             bRet = poNewLineString->addPoint(paoPoints[i].x, paoPoints[i].y,
    2377           0 :                                              padfZ[i]);
    2378             :         else
    2379          55 :             bRet = poNewLineString->addPoint(paoPoints[i].x, paoPoints[i].y);
    2380          55 :         if (!bRet)
    2381           0 :             return nullptr;
    2382             : 
    2383          55 :         const double dfDeltaX = paoPoints[i + 1].x - paoPoints[i].x;
    2384          55 :         const double dfDeltaY = paoPoints[i + 1].y - paoPoints[i].y;
    2385             :         const double dfSegLength =
    2386          55 :             sqrt(dfDeltaX * dfDeltaX + dfDeltaY * dfDeltaY);
    2387             : 
    2388          55 :         if (dfSegLength > 0)
    2389             :         {
    2390          55 :             if ((dfLength <= dfDistanceTo) &&
    2391          55 :                 ((dfLength + dfSegLength) >= dfDistanceTo))
    2392             :             {
    2393          26 :                 const double dfRatio = (dfDistanceTo - dfLength) / dfSegLength;
    2394             : 
    2395          26 :                 const double dfX = paoPoints[i].x * (1 - dfRatio) +
    2396          26 :                                    paoPoints[i + 1].x * dfRatio;
    2397          26 :                 const double dfY = paoPoints[i].y * (1 - dfRatio) +
    2398          26 :                                    paoPoints[i + 1].y * dfRatio;
    2399             : 
    2400          26 :                 if (getCoordinateDimension() == 3)
    2401           0 :                     bRet = poNewLineString->addPoint(
    2402             :                         dfX, dfY,
    2403           0 :                         padfZ[i] * (1 - dfRatio) + padfZ[i + 1] * dfRatio);
    2404             :                 else
    2405          26 :                     bRet = poNewLineString->addPoint(dfX, dfY);
    2406          26 :                 if (!bRet)
    2407           0 :                     return nullptr;
    2408             : 
    2409          26 :                 return poNewLineString.release();
    2410             :             }
    2411             : 
    2412          29 :             dfLength += dfSegLength;
    2413             :         }
    2414             :     }
    2415             : 
    2416             :     bool bRet;
    2417           0 :     if (getCoordinateDimension() == 3)
    2418           0 :         bRet = poNewLineString->addPoint(paoPoints[nPointCount - 1].x,
    2419           0 :                                          paoPoints[nPointCount - 1].y,
    2420           0 :                                          padfZ[nPointCount - 1]);
    2421             :     else
    2422           0 :         bRet = poNewLineString->addPoint(paoPoints[nPointCount - 1].x,
    2423           0 :                                          paoPoints[nPointCount - 1].y);
    2424             : 
    2425           0 :     if (!bRet || poNewLineString->getNumPoints() < 2)
    2426             :     {
    2427           0 :         return nullptr;
    2428             :     }
    2429             : 
    2430           0 :     return poNewLineString.release();
    2431             : }
    2432             : 
    2433             : /************************************************************************/
    2434             : /*                            getEnvelope()                             */
    2435             : /************************************************************************/
    2436             : 
    2437     5670440 : void OGRSimpleCurve::getEnvelope(OGREnvelope *psEnvelope) const
    2438             : 
    2439             : {
    2440     5670440 :     if (IsEmpty())
    2441             :     {
    2442           3 :         psEnvelope->MinX = 0.0;
    2443           3 :         psEnvelope->MaxX = 0.0;
    2444           3 :         psEnvelope->MinY = 0.0;
    2445           3 :         psEnvelope->MaxY = 0.0;
    2446           3 :         return;
    2447             :     }
    2448             : 
    2449     5670430 :     double dfMinX = paoPoints[0].x;
    2450     5670430 :     double dfMaxX = paoPoints[0].x;
    2451     5670430 :     double dfMinY = paoPoints[0].y;
    2452     5670430 :     double dfMaxY = paoPoints[0].y;
    2453             : 
    2454    32115300 :     for (int iPoint = 1; iPoint < nPointCount; iPoint++)
    2455             :     {
    2456    26444900 :         if (dfMaxX < paoPoints[iPoint].x)
    2457     7541960 :             dfMaxX = paoPoints[iPoint].x;
    2458    26444900 :         if (dfMaxY < paoPoints[iPoint].y)
    2459     7492680 :             dfMaxY = paoPoints[iPoint].y;
    2460    26444900 :         if (dfMinX > paoPoints[iPoint].x)
    2461     4783170 :             dfMinX = paoPoints[iPoint].x;
    2462    26444900 :         if (dfMinY > paoPoints[iPoint].y)
    2463     5603920 :             dfMinY = paoPoints[iPoint].y;
    2464             :     }
    2465             : 
    2466     5670430 :     psEnvelope->MinX = dfMinX;
    2467     5670430 :     psEnvelope->MaxX = dfMaxX;
    2468     5670430 :     psEnvelope->MinY = dfMinY;
    2469     5670430 :     psEnvelope->MaxY = dfMaxY;
    2470             : }
    2471             : 
    2472             : /************************************************************************/
    2473             : /*                            getEnvelope()                             */
    2474             : /************************************************************************/
    2475             : 
    2476      641143 : void OGRSimpleCurve::getEnvelope(OGREnvelope3D *psEnvelope) const
    2477             : 
    2478             : {
    2479      641143 :     getEnvelope(static_cast<OGREnvelope *>(psEnvelope));
    2480             : 
    2481      641143 :     if (IsEmpty() || padfZ == nullptr)
    2482             :     {
    2483      264078 :         psEnvelope->MinZ = 0.0;
    2484      264078 :         psEnvelope->MaxZ = 0.0;
    2485      264078 :         return;
    2486             :     }
    2487             : 
    2488      377064 :     double dfMinZ = padfZ[0];
    2489      377064 :     double dfMaxZ = padfZ[0];
    2490             : 
    2491     1548030 :     for (int iPoint = 1; iPoint < nPointCount; iPoint++)
    2492             :     {
    2493     1170970 :         if (dfMinZ > padfZ[iPoint])
    2494      369959 :             dfMinZ = padfZ[iPoint];
    2495     1170970 :         if (dfMaxZ < padfZ[iPoint])
    2496      230791 :             dfMaxZ = padfZ[iPoint];
    2497             :     }
    2498             : 
    2499      377064 :     psEnvelope->MinZ = dfMinZ;
    2500      377064 :     psEnvelope->MaxZ = dfMaxZ;
    2501             : }
    2502             : 
    2503             : /************************************************************************/
    2504             : /*                               Equals()                               */
    2505             : /************************************************************************/
    2506             : 
    2507       48056 : OGRBoolean OGRSimpleCurve::Equals(const OGRGeometry *poOther) const
    2508             : 
    2509             : {
    2510       48056 :     if (poOther == this)
    2511           1 :         return TRUE;
    2512             : 
    2513       48055 :     if (poOther->getGeometryType() != getGeometryType())
    2514           1 :         return FALSE;
    2515             : 
    2516       48054 :     if (IsEmpty() && poOther->IsEmpty())
    2517           1 :         return TRUE;
    2518             : 
    2519             :     // TODO(schwehr): Test the SRS.
    2520             : 
    2521       48053 :     auto poOLine = poOther->toSimpleCurve();
    2522       48053 :     if (getNumPoints() != poOLine->getNumPoints())
    2523           8 :         return FALSE;
    2524             : 
    2525      250190 :     for (int iPoint = 0; iPoint < getNumPoints(); iPoint++)
    2526             :     {
    2527      428589 :         if (getX(iPoint) != poOLine->getX(iPoint) ||
    2528      428589 :             getY(iPoint) != poOLine->getY(iPoint) ||
    2529      202145 :             getZ(iPoint) != poOLine->getZ(iPoint))
    2530       13993 :             return FALSE;
    2531             :     }
    2532             : 
    2533       34052 :     return TRUE;
    2534             : }
    2535             : 
    2536             : /************************************************************************/
    2537             : /*                             transform()                              */
    2538             : /************************************************************************/
    2539             : 
    2540        7658 : OGRErr OGRSimpleCurve::transform(OGRCoordinateTransformation *poCT)
    2541             : 
    2542             : {
    2543             :     /* -------------------------------------------------------------------- */
    2544             :     /*   Make a copy of the points to operate on, so as to be able to       */
    2545             :     /*   keep only valid reprojected points if partial reprojection enabled */
    2546             :     /*   or keeping intact the original geometry if only full reprojection  */
    2547             :     /*   allowed.                                                           */
    2548             :     /* -------------------------------------------------------------------- */
    2549             :     double *xyz = static_cast<double *>(
    2550        7658 :         VSI_MALLOC_VERBOSE(sizeof(double) * nPointCount * 3));
    2551             :     int *pabSuccess =
    2552        7658 :         static_cast<int *>(VSI_CALLOC_VERBOSE(sizeof(int), nPointCount));
    2553        7658 :     if (xyz == nullptr || pabSuccess == nullptr)
    2554             :     {
    2555           0 :         VSIFree(xyz);
    2556           0 :         VSIFree(pabSuccess);
    2557           0 :         return OGRERR_NOT_ENOUGH_MEMORY;
    2558             :     }
    2559             : 
    2560       70197 :     for (int i = 0; i < nPointCount; i++)
    2561             :     {
    2562       62539 :         xyz[i] = paoPoints[i].x;
    2563       62539 :         xyz[i + nPointCount] = paoPoints[i].y;
    2564       62539 :         if (padfZ)
    2565       34517 :             xyz[i + nPointCount * 2] = padfZ[i];
    2566             :         else
    2567       28022 :             xyz[i + nPointCount * 2] = 0.0;
    2568             :     }
    2569             : 
    2570             :     /* -------------------------------------------------------------------- */
    2571             :     /*      Transform and reapply.                                          */
    2572             :     /* -------------------------------------------------------------------- */
    2573        7658 :     poCT->Transform(nPointCount, xyz, xyz + nPointCount, xyz + nPointCount * 2,
    2574        7658 :                     nullptr, pabSuccess);
    2575             : 
    2576        7658 :     const char *pszEnablePartialReprojection = nullptr;
    2577             : 
    2578        7658 :     int j = 0;  // Used after for.
    2579       70197 :     for (int i = 0; i < nPointCount; i++)
    2580             :     {
    2581       62539 :         if (pabSuccess[i])
    2582             :         {
    2583       62539 :             xyz[j] = xyz[i];
    2584       62539 :             xyz[j + nPointCount] = xyz[i + nPointCount];
    2585       62539 :             xyz[j + 2 * nPointCount] = xyz[i + 2 * nPointCount];
    2586       62539 :             j++;
    2587             :         }
    2588             :         else
    2589             :         {
    2590           0 :             if (pszEnablePartialReprojection == nullptr)
    2591           0 :                 pszEnablePartialReprojection = CPLGetConfigOption(
    2592             :                     "OGR_ENABLE_PARTIAL_REPROJECTION", nullptr);
    2593           0 :             if (pszEnablePartialReprojection == nullptr)
    2594             :             {
    2595             :                 static bool bHasWarned = false;
    2596           0 :                 if (!bHasWarned)
    2597             :                 {
    2598             :                     // Check that there is at least one valid reprojected point
    2599             :                     // and issue an error giving an hint to use
    2600             :                     // OGR_ENABLE_PARTIAL_REPROJECTION.
    2601           0 :                     bool bHasOneValidPoint = j != 0;
    2602           0 :                     for (; i < nPointCount && !bHasOneValidPoint; i++)
    2603             :                     {
    2604           0 :                         if (pabSuccess[i])
    2605           0 :                             bHasOneValidPoint = true;
    2606             :                     }
    2607           0 :                     if (bHasOneValidPoint)
    2608             :                     {
    2609           0 :                         bHasWarned = true;
    2610           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
    2611             :                                  "Full reprojection failed, but partial is "
    2612             :                                  "possible if you define "
    2613             :                                  "OGR_ENABLE_PARTIAL_REPROJECTION "
    2614             :                                  "configuration option to TRUE");
    2615             :                     }
    2616             :                 }
    2617             : 
    2618           0 :                 CPLFree(xyz);
    2619           0 :                 CPLFree(pabSuccess);
    2620           0 :                 return OGRERR_FAILURE;
    2621             :             }
    2622           0 :             else if (!CPLTestBool(pszEnablePartialReprojection))
    2623             :             {
    2624           0 :                 CPLFree(xyz);
    2625           0 :                 CPLFree(pabSuccess);
    2626           0 :                 return OGRERR_FAILURE;
    2627             :             }
    2628             :         }
    2629             :     }
    2630             : 
    2631        7658 :     if (j == 0 && nPointCount != 0)
    2632             :     {
    2633           0 :         CPLFree(xyz);
    2634           0 :         CPLFree(pabSuccess);
    2635           0 :         return OGRERR_FAILURE;
    2636             :     }
    2637             : 
    2638        7658 :     setPoints(j, xyz, xyz + nPointCount,
    2639        7658 :               (padfZ) ? xyz + nPointCount * 2 : nullptr);
    2640        7658 :     CPLFree(xyz);
    2641        7658 :     CPLFree(pabSuccess);
    2642             : 
    2643        7658 :     assignSpatialReference(poCT->GetTargetCS());
    2644             : 
    2645        7658 :     return OGRERR_NONE;
    2646             : }
    2647             : 
    2648             : /************************************************************************/
    2649             : /*                               IsEmpty()                              */
    2650             : /************************************************************************/
    2651             : 
    2652     7819830 : OGRBoolean OGRSimpleCurve::IsEmpty() const
    2653             : {
    2654     7819830 :     return (nPointCount == 0);
    2655             : }
    2656             : 
    2657             : /************************************************************************/
    2658             : /*                     OGRSimpleCurve::segmentize()                     */
    2659             : /************************************************************************/
    2660             : 
    2661          75 : bool OGRSimpleCurve::segmentize(double dfMaxLength)
    2662             : {
    2663          75 :     if (dfMaxLength <= 0)
    2664             :     {
    2665           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2666             :                  "dfMaxLength must be strictly positive");
    2667           0 :         return false;
    2668             :     }
    2669          75 :     if (nPointCount < 2)
    2670           0 :         return true;
    2671             : 
    2672             :     // So as to make sure that the same line followed in both directions
    2673             :     // result in the same segmentized line.
    2674          75 :     if (paoPoints[0].x < paoPoints[nPointCount - 1].x ||
    2675          68 :         (paoPoints[0].x == paoPoints[nPointCount - 1].x &&
    2676          60 :          paoPoints[0].y < paoPoints[nPointCount - 1].y))
    2677             :     {
    2678          16 :         reversePoints();
    2679          16 :         bool bRet = segmentize(dfMaxLength);
    2680          16 :         reversePoints();
    2681          16 :         return bRet;
    2682             :     }
    2683             : 
    2684          59 :     int nNewPointCount = 0;
    2685          59 :     const double dfSquareMaxLength = dfMaxLength * dfMaxLength;
    2686             : 
    2687             :     // First pass to compute new number of points
    2688          59 :     constexpr double REL_EPSILON_LENGTH_SQUARE = 1e-5;
    2689          59 :     constexpr double REL_EPSILON_ROUND = 1e-2;
    2690         740 :     for (int i = 0; i < nPointCount; i++)
    2691             :     {
    2692         740 :         nNewPointCount++;
    2693             : 
    2694         740 :         if (i == nPointCount - 1)
    2695          58 :             break;
    2696             : 
    2697             :         // Must be kept in sync with the second pass loop
    2698         682 :         const double dfX = paoPoints[i + 1].x - paoPoints[i].x;
    2699         682 :         const double dfY = paoPoints[i + 1].y - paoPoints[i].y;
    2700         682 :         const double dfSquareDist = dfX * dfX + dfY * dfY;
    2701         682 :         if (dfSquareDist - dfSquareMaxLength >
    2702         682 :             REL_EPSILON_LENGTH_SQUARE * dfSquareMaxLength)
    2703             :         {
    2704         307 :             const double dfIntermediatePoints = floor(
    2705         307 :                 sqrt(dfSquareDist / dfSquareMaxLength) - REL_EPSILON_ROUND);
    2706             :             const int nIntermediatePoints =
    2707         307 :                 DoubleToIntClamp(dfIntermediatePoints);
    2708             : 
    2709             :             // TODO(schwehr): Can these be tighter?
    2710             :             // Limit allocation of paoNewPoints to a few GB of memory.
    2711             :             // An OGRRawPoint is 2 doubles.
    2712             :             // kMax is a guess of what a reasonable max might be.
    2713         307 :             constexpr int kMax = 2 << 26;
    2714         307 :             if (nNewPointCount > kMax || nIntermediatePoints > kMax)
    2715             :             {
    2716           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2717             :                          "Too many points in a segment: %d or %d",
    2718             :                          nNewPointCount, nIntermediatePoints);
    2719           1 :                 return false;
    2720             :             }
    2721             : 
    2722         306 :             nNewPointCount += nIntermediatePoints;
    2723             :         }
    2724             :     }
    2725             : 
    2726          58 :     if (nPointCount == nNewPointCount)
    2727           8 :         return true;
    2728             : 
    2729             :     // Allocate new arrays
    2730             :     OGRRawPoint *paoNewPoints = static_cast<OGRRawPoint *>(
    2731          50 :         VSI_MALLOC_VERBOSE(sizeof(OGRRawPoint) * nNewPointCount));
    2732          50 :     if (paoNewPoints == nullptr)
    2733           0 :         return false;
    2734          50 :     double *padfNewZ = nullptr;
    2735          50 :     double *padfNewM = nullptr;
    2736          50 :     if (padfZ != nullptr)
    2737             :     {
    2738             :         padfNewZ = static_cast<double *>(
    2739           2 :             VSI_MALLOC_VERBOSE(sizeof(double) * nNewPointCount));
    2740           2 :         if (padfNewZ == nullptr)
    2741             :         {
    2742           0 :             VSIFree(paoNewPoints);
    2743           0 :             return false;
    2744             :         }
    2745             :     }
    2746          50 :     if (padfM != nullptr)
    2747             :     {
    2748             :         padfNewM = static_cast<double *>(
    2749           2 :             VSI_MALLOC_VERBOSE(sizeof(double) * nNewPointCount));
    2750           2 :         if (padfNewM == nullptr)
    2751             :         {
    2752           0 :             VSIFree(paoNewPoints);
    2753           0 :             VSIFree(padfNewZ);
    2754           0 :             return false;
    2755             :         }
    2756             :     }
    2757             : 
    2758             :     // Second pass to fill new arrays
    2759             :     // Must be kept in sync with the first pass loop
    2760          50 :     nNewPointCount = 0;
    2761         639 :     for (int i = 0; i < nPointCount; i++)
    2762             :     {
    2763         639 :         paoNewPoints[nNewPointCount] = paoPoints[i];
    2764             : 
    2765         639 :         if (padfZ != nullptr)
    2766             :         {
    2767           4 :             padfNewZ[nNewPointCount] = padfZ[i];
    2768             :         }
    2769             : 
    2770         639 :         if (padfM != nullptr)
    2771             :         {
    2772           4 :             padfNewM[nNewPointCount] = padfM[i];
    2773             :         }
    2774             : 
    2775         639 :         nNewPointCount++;
    2776             : 
    2777         639 :         if (i == nPointCount - 1)
    2778          50 :             break;
    2779             : 
    2780         589 :         const double dfX = paoPoints[i + 1].x - paoPoints[i].x;
    2781         589 :         const double dfY = paoPoints[i + 1].y - paoPoints[i].y;
    2782         589 :         const double dfSquareDist = dfX * dfX + dfY * dfY;
    2783             : 
    2784             :         // Must be kept in sync with the initial pass loop
    2785         589 :         if (dfSquareDist - dfSquareMaxLength >
    2786         589 :             REL_EPSILON_LENGTH_SQUARE * dfSquareMaxLength)
    2787             :         {
    2788         304 :             const double dfIntermediatePoints = floor(
    2789         304 :                 sqrt(dfSquareDist / dfSquareMaxLength) - REL_EPSILON_ROUND);
    2790             :             const int nIntermediatePoints =
    2791         304 :                 DoubleToIntClamp(dfIntermediatePoints);
    2792         304 :             const double dfRatioX =
    2793         304 :                 dfX / (static_cast<double>(nIntermediatePoints) + 1);
    2794         304 :             const double dfRatioY =
    2795         304 :                 dfY / (static_cast<double>(nIntermediatePoints) + 1);
    2796             : 
    2797       21606 :             for (int j = 1; j <= nIntermediatePoints; j++)
    2798             :             {
    2799             :                 // coverity[overflow_const]
    2800       21302 :                 const int newI = nNewPointCount + j - 1;
    2801       21302 :                 paoNewPoints[newI].x = paoPoints[i].x + j * dfRatioX;
    2802       21302 :                 paoNewPoints[newI].y = paoPoints[i].y + j * dfRatioY;
    2803       21302 :                 if (padfZ != nullptr)
    2804             :                 {
    2805             :                     // No interpolation.
    2806          10 :                     padfNewZ[newI] = padfZ[i];
    2807             :                 }
    2808       21302 :                 if (padfM != nullptr)
    2809             :                 {
    2810             :                     // No interpolation.
    2811           2 :                     padfNewM[newI] = padfM[i];
    2812             :                 }
    2813             :             }
    2814             : 
    2815         304 :             nNewPointCount += nIntermediatePoints;
    2816             :         }
    2817             :     }
    2818             : 
    2819          50 :     CPLFree(paoPoints);
    2820          50 :     paoPoints = paoNewPoints;
    2821          50 :     nPointCount = nNewPointCount;
    2822          50 :     m_nPointCapacity = nNewPointCount;
    2823             : 
    2824          50 :     if (padfZ != nullptr)
    2825             :     {
    2826           2 :         CPLFree(padfZ);
    2827           2 :         padfZ = padfNewZ;
    2828             :     }
    2829          50 :     if (padfM != nullptr)
    2830             :     {
    2831           2 :         CPLFree(padfM);
    2832           2 :         padfM = padfNewM;
    2833             :     }
    2834          50 :     return true;
    2835             : }
    2836             : 
    2837             : /************************************************************************/
    2838             : /*                               swapXY()                               */
    2839             : /************************************************************************/
    2840             : 
    2841         102 : void OGRSimpleCurve::swapXY()
    2842             : {
    2843         656 :     for (int i = 0; i < nPointCount; i++)
    2844             :     {
    2845         554 :         std::swap(paoPoints[i].x, paoPoints[i].y);
    2846             :     }
    2847         102 : }
    2848             : 
    2849             : /************************************************************************/
    2850             : /*                       OGRSimpleCurvePointIterator                    */
    2851             : /************************************************************************/
    2852             : 
    2853             : class OGRSimpleCurvePointIterator final : public OGRPointIterator
    2854             : {
    2855             :     CPL_DISALLOW_COPY_ASSIGN(OGRSimpleCurvePointIterator)
    2856             : 
    2857             :     const OGRSimpleCurve *poSC = nullptr;
    2858             :     int iCurPoint = 0;
    2859             : 
    2860             :   public:
    2861         169 :     explicit OGRSimpleCurvePointIterator(const OGRSimpleCurve *poSCIn)
    2862         169 :         : poSC(poSCIn)
    2863             :     {
    2864         169 :     }
    2865             : 
    2866             :     OGRBoolean getNextPoint(OGRPoint *p) override;
    2867             : };
    2868             : 
    2869             : /************************************************************************/
    2870             : /*                            getNextPoint()                            */
    2871             : /************************************************************************/
    2872             : 
    2873         697 : OGRBoolean OGRSimpleCurvePointIterator::getNextPoint(OGRPoint *p)
    2874             : {
    2875         697 :     if (iCurPoint >= poSC->getNumPoints())
    2876         133 :         return FALSE;
    2877         564 :     poSC->getPoint(iCurPoint, p);
    2878         564 :     iCurPoint++;
    2879         564 :     return TRUE;
    2880             : }
    2881             : 
    2882             : /************************************************************************/
    2883             : /*                         getPointIterator()                           */
    2884             : /************************************************************************/
    2885             : 
    2886         169 : OGRPointIterator *OGRSimpleCurve::getPointIterator() const
    2887             : {
    2888         169 :     return new OGRSimpleCurvePointIterator(this);
    2889             : }
    2890             : 
    2891             : /************************************************************************/
    2892             : /*                  OGRLineString( const OGRLineString& )               */
    2893             : /************************************************************************/
    2894             : 
    2895             : /**
    2896             :  * \brief Copy constructor.
    2897             :  *
    2898             :  * Note: before GDAL 2.1, only the default implementation of the constructor
    2899             :  * existed, which could be unsafe to use.
    2900             :  *
    2901             :  * @since GDAL 2.1
    2902             :  */
    2903             : 
    2904             : OGRLineString::OGRLineString(const OGRLineString &) = default;
    2905             : 
    2906             : /************************************************************************/
    2907             : /*                  OGRLineString( OGRLineString&& )                    */
    2908             : /************************************************************************/
    2909             : 
    2910             : /**
    2911             :  * \brief Move constructor.
    2912             :  *
    2913             :  * @since GDAL 3.11
    2914             :  */
    2915             : 
    2916             : OGRLineString::OGRLineString(OGRLineString &&) = default;
    2917             : 
    2918             : /************************************************************************/
    2919             : /*                    operator=( const OGRLineString& )                 */
    2920             : /************************************************************************/
    2921             : 
    2922             : /**
    2923             :  * \brief Assignment operator.
    2924             :  *
    2925             :  * Note: before GDAL 2.1, only the default implementation of the operator
    2926             :  * existed, which could be unsafe to use.
    2927             :  *
    2928             :  * @since GDAL 2.1
    2929             :  */
    2930             : 
    2931           9 : OGRLineString &OGRLineString::operator=(const OGRLineString &other)
    2932             : {
    2933           9 :     if (this != &other)
    2934             :     {
    2935           8 :         OGRSimpleCurve::operator=(other);
    2936             :     }
    2937           9 :     return *this;
    2938             : }
    2939             : 
    2940             : /************************************************************************/
    2941             : /*                    operator=( OGRLineString&& )                      */
    2942             : /************************************************************************/
    2943             : 
    2944             : /**
    2945             :  * \brief Move assignment operator.
    2946             :  *
    2947             :  * @since GDAL 3.11
    2948             :  */
    2949             : 
    2950           4 : OGRLineString &OGRLineString::operator=(OGRLineString &&other)
    2951             : {
    2952           4 :     if (this != &other)
    2953             :     {
    2954           4 :         OGRSimpleCurve::operator=(std::move(other));
    2955             :     }
    2956           4 :     return *this;
    2957             : }
    2958             : 
    2959             : /************************************************************************/
    2960             : /*                          getGeometryType()                           */
    2961             : /************************************************************************/
    2962             : 
    2963      891786 : OGRwkbGeometryType OGRLineString::getGeometryType() const
    2964             : 
    2965             : {
    2966      891786 :     if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
    2967       44253 :         return wkbLineStringZM;
    2968      847533 :     else if (flags & OGR_G_MEASURED)
    2969        1262 :         return wkbLineStringM;
    2970      846271 :     else if (flags & OGR_G_3D)
    2971      149443 :         return wkbLineString25D;
    2972             :     else
    2973      696828 :         return wkbLineString;
    2974             : }
    2975             : 
    2976             : /************************************************************************/
    2977             : /*                          getGeometryName()                           */
    2978             : /************************************************************************/
    2979             : 
    2980       10524 : const char *OGRLineString::getGeometryName() const
    2981             : 
    2982             : {
    2983       10524 :     return "LINESTRING";
    2984             : }
    2985             : 
    2986             : /************************************************************************/
    2987             : /*                          curveToLine()                               */
    2988             : /************************************************************************/
    2989             : 
    2990         932 : OGRLineString *OGRLineString::CurveToLine(
    2991             :     CPL_UNUSED double /* dfMaxAngleStepSizeDegrees */,
    2992             :     CPL_UNUSED const char *const * /* papszOptions */) const
    2993             : {
    2994         932 :     return clone();
    2995             : }
    2996             : 
    2997             : /************************************************************************/
    2998             : /*                          get_LinearArea()                            */
    2999             : /************************************************************************/
    3000             : 
    3001             : /**
    3002             :  * \brief Compute area of ring / closed linestring.
    3003             :  *
    3004             :  * The area is computed according to Green's Theorem:
    3005             :  *
    3006             :  * Area is "Sum(x(i)*(y(i+1) - y(i-1)))/2" for i = 0 to pointCount-1,
    3007             :  * assuming the last point is a duplicate of the first.
    3008             :  *
    3009             :  * @return computed area.
    3010             :  */
    3011             : 
    3012       61898 : double OGRSimpleCurve::get_LinearArea() const
    3013             : 
    3014             : {
    3015      123795 :     if (nPointCount < 2 ||
    3016       61897 :         (WkbSize() != 0 && /* if not a linearring, check it is closed */
    3017          60 :          (paoPoints[0].x != paoPoints[nPointCount - 1].x ||
    3018          59 :           paoPoints[0].y != paoPoints[nPointCount - 1].y)))
    3019             :     {
    3020           2 :         return 0;
    3021             :     }
    3022             : 
    3023       61896 :     double dfAreaSum =
    3024       61896 :         paoPoints[0].x * (paoPoints[1].y - paoPoints[nPointCount - 1].y);
    3025             : 
    3026     3373180 :     for (int i = 1; i < nPointCount - 1; i++)
    3027             :     {
    3028     3311280 :         dfAreaSum += paoPoints[i].x * (paoPoints[i + 1].y - paoPoints[i - 1].y);
    3029             :     }
    3030             : 
    3031       61896 :     dfAreaSum += paoPoints[nPointCount - 1].x *
    3032       61896 :                  (paoPoints[0].y - paoPoints[nPointCount - 2].y);
    3033             : 
    3034       61896 :     return 0.5 * fabs(dfAreaSum);
    3035             : }
    3036             : 
    3037             : /************************************************************************/
    3038             : /*                             getCurveGeometry()                       */
    3039             : /************************************************************************/
    3040             : 
    3041             : OGRGeometry *
    3042        3197 : OGRLineString::getCurveGeometry(const char *const *papszOptions) const
    3043             : {
    3044        3197 :     return OGRGeometryFactory::curveFromLineString(this, papszOptions);
    3045             : }
    3046             : 
    3047             : /************************************************************************/
    3048             : /*                      TransferMembersAndDestroy()                     */
    3049             : /************************************************************************/
    3050             : //! @cond Doxygen_Suppress
    3051         570 : OGRLineString *OGRLineString::TransferMembersAndDestroy(OGRLineString *poSrc,
    3052             :                                                         OGRLineString *poDst)
    3053             : {
    3054         570 :     if (poSrc->Is3D())
    3055         101 :         poDst->flags |= OGR_G_3D;
    3056         570 :     if (poSrc->IsMeasured())
    3057          47 :         poDst->flags |= OGR_G_MEASURED;
    3058         570 :     poDst->assignSpatialReference(poSrc->getSpatialReference());
    3059         570 :     poDst->nPointCount = poSrc->nPointCount;
    3060         570 :     poDst->m_nPointCapacity = poSrc->m_nPointCapacity;
    3061         570 :     poDst->paoPoints = poSrc->paoPoints;
    3062         570 :     poDst->padfZ = poSrc->padfZ;
    3063         570 :     poDst->padfM = poSrc->padfM;
    3064         570 :     poSrc->nPointCount = 0;
    3065         570 :     poSrc->m_nPointCapacity = 0;
    3066         570 :     poSrc->paoPoints = nullptr;
    3067         570 :     poSrc->padfZ = nullptr;
    3068         570 :     poSrc->padfM = nullptr;
    3069         570 :     delete poSrc;
    3070         570 :     return poDst;
    3071             : }
    3072             : 
    3073             : //! @endcond
    3074             : /************************************************************************/
    3075             : /*                         CastToLinearRing()                           */
    3076             : /************************************************************************/
    3077             : 
    3078             : /**
    3079             :  * \brief Cast to linear ring.
    3080             :  *
    3081             :  * The passed in geometry is consumed and a new one returned (or NULL in case
    3082             :  * of failure)
    3083             :  *
    3084             :  * @param poLS the input geometry - ownership is passed to the method.
    3085             :  * @return new geometry.
    3086             :  */
    3087             : 
    3088         505 : OGRLinearRing *OGRLineString::CastToLinearRing(OGRLineString *poLS)
    3089             : {
    3090         505 :     if (poLS->nPointCount < 2 || !poLS->get_IsClosed())
    3091             :     {
    3092           2 :         CPLError(CE_Failure, CPLE_AppDefined,
    3093             :                  "Cannot convert non-closed linestring to linearring");
    3094           2 :         delete poLS;
    3095           2 :         return nullptr;
    3096             :     }
    3097         503 :     OGRLinearRing *poLR = new OGRLinearRing();
    3098         503 :     TransferMembersAndDestroy(poLS, poLR);
    3099         503 :     return poLR;
    3100             : }
    3101             : 
    3102             : /************************************************************************/
    3103             : /*                               clone()                                */
    3104             : /************************************************************************/
    3105             : 
    3106      301927 : OGRLineString *OGRLineString::clone() const
    3107             : {
    3108      301927 :     auto ret = new (std::nothrow) OGRLineString(*this);
    3109      301927 :     if (ret)
    3110             :     {
    3111      301927 :         if (ret->getNumPoints() != getNumPoints())
    3112             :         {
    3113           0 :             delete ret;
    3114           0 :             ret = nullptr;
    3115             :         }
    3116             :     }
    3117      301927 :     return ret;
    3118             : }
    3119             : 
    3120             : //! @cond Doxygen_Suppress
    3121             : 
    3122             : /************************************************************************/
    3123             : /*                     GetCasterToLineString()                          */
    3124             : /************************************************************************/
    3125             : 
    3126         159 : static OGRLineString *CasterToLineString(OGRCurve *poCurve)
    3127             : {
    3128         159 :     return poCurve->toLineString();
    3129             : }
    3130             : 
    3131         159 : OGRCurveCasterToLineString OGRLineString::GetCasterToLineString() const
    3132             : {
    3133         159 :     return ::CasterToLineString;
    3134             : }
    3135             : 
    3136             : /************************************************************************/
    3137             : /*                        GetCasterToLinearRing()                       */
    3138             : /************************************************************************/
    3139             : 
    3140         505 : OGRLinearRing *OGRLineString::CasterToLinearRing(OGRCurve *poCurve)
    3141             : {
    3142         505 :     return OGRLineString::CastToLinearRing(poCurve->toLineString());
    3143             : }
    3144             : 
    3145         505 : OGRCurveCasterToLinearRing OGRLineString::GetCasterToLinearRing() const
    3146             : {
    3147         505 :     return OGRLineString::CasterToLinearRing;
    3148             : }
    3149             : 
    3150             : /************************************************************************/
    3151             : /*                            get_Area()                                */
    3152             : /************************************************************************/
    3153             : 
    3154       61896 : double OGRLineString::get_Area() const
    3155             : {
    3156       61896 :     return get_LinearArea();
    3157             : }
    3158             : 
    3159             : /************************************************************************/
    3160             : /*                           GetGeodesicInputs()                        */
    3161             : /************************************************************************/
    3162             : 
    3163          47 : static bool GetGeodesicInputs(const OGRLineString *poLS,
    3164             :                               const OGRSpatialReference *poSRSOverride,
    3165             :                               const char *pszComputationType, geod_geodesic &g,
    3166             :                               std::vector<double> &adfLat,
    3167             :                               std::vector<double> &adfLon)
    3168             : {
    3169          47 :     if (!poSRSOverride)
    3170          14 :         poSRSOverride = poLS->getSpatialReference();
    3171             : 
    3172          47 :     if (!poSRSOverride)
    3173             :     {
    3174           2 :         CPLError(CE_Failure, CPLE_AppDefined,
    3175             :                  "Cannot compute %s on ellipsoid due to missing SRS",
    3176             :                  pszComputationType);
    3177           2 :         return false;
    3178             :     }
    3179             : 
    3180          45 :     OGRErr eErr = OGRERR_NONE;
    3181          45 :     double dfSemiMajor = poSRSOverride->GetSemiMajor(&eErr);
    3182          45 :     if (eErr != OGRERR_NONE)
    3183           2 :         return false;
    3184          43 :     const double dfInvFlattening = poSRSOverride->GetInvFlattening(&eErr);
    3185          43 :     if (eErr != OGRERR_NONE)
    3186           0 :         return false;
    3187             : 
    3188          43 :     geod_init(&g, dfSemiMajor,
    3189             :               dfInvFlattening != 0 ? 1.0 / dfInvFlattening : 0.0);
    3190             : 
    3191          43 :     const int nPointCount = poLS->getNumPoints();
    3192          43 :     adfLat.reserve(nPointCount);
    3193          43 :     adfLon.reserve(nPointCount);
    3194             : 
    3195          86 :     OGRSpatialReference oGeogCRS;
    3196          43 :     if (oGeogCRS.CopyGeogCSFrom(poSRSOverride) != OGRERR_NONE)
    3197             :     {
    3198           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3199             :                  "Cannot reproject geometry to geographic CRS");
    3200           0 :         return false;
    3201             :     }
    3202          43 :     oGeogCRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    3203             :     auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
    3204          86 :         OGRCreateCoordinateTransformation(poSRSOverride, &oGeogCRS));
    3205          43 :     if (!poCT)
    3206             :     {
    3207           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3208             :                  "Cannot reproject geometry to geographic CRS");
    3209           0 :         return false;
    3210             :     }
    3211         905 :     for (int i = 0; i < nPointCount; ++i)
    3212             :     {
    3213         862 :         adfLon.push_back(poLS->getX(i));
    3214         862 :         adfLat.push_back(poLS->getY(i));
    3215             :     }
    3216             : #ifdef __GNUC__
    3217             : #pragma GCC diagnostic push
    3218             : #pragma GCC diagnostic ignored "-Wnull-dereference"
    3219             : #endif
    3220          86 :     std::vector<int> anSuccess;
    3221          43 :     anSuccess.resize(adfLon.size());
    3222             : #ifdef __GNUC__
    3223             : #pragma GCC diagnostic pop
    3224             : #endif
    3225          43 :     poCT->Transform(adfLon.size(), adfLon.data(), adfLat.data(), nullptr,
    3226             :                     anSuccess.data());
    3227             :     double dfToDegrees =
    3228          43 :         oGeogCRS.GetAngularUnits(nullptr) / CPLAtof(SRS_UA_DEGREE_CONV);
    3229          43 :     if (std::fabs(dfToDegrees - 1) <= 1e-10)
    3230          43 :         dfToDegrees = 1.0;
    3231         905 :     for (int i = 0; i < nPointCount; ++i)
    3232             :     {
    3233         862 :         if (!anSuccess[i])
    3234             :         {
    3235           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    3236             :                      "Cannot reproject geometry to geographic CRS");
    3237           0 :             return false;
    3238             :         }
    3239         862 :         adfLon[i] *= dfToDegrees;
    3240         862 :         adfLat[i] *= dfToDegrees;
    3241             :     }
    3242             : 
    3243          43 :     return true;
    3244             : }
    3245             : 
    3246             : /************************************************************************/
    3247             : /*                        get_GeodesicArea()                            */
    3248             : /************************************************************************/
    3249             : 
    3250             : double
    3251          22 : OGRLineString::get_GeodesicArea(const OGRSpatialReference *poSRSOverride) const
    3252             : {
    3253             :     geod_geodesic g;
    3254          44 :     std::vector<double> adfLat;
    3255          44 :     std::vector<double> adfLon;
    3256          22 :     if (!GetGeodesicInputs(this, poSRSOverride, "area", g, adfLat, adfLon))
    3257           2 :         return -1.0;
    3258          20 :     double dfArea = -1.0;
    3259          20 :     geod_polygonarea(&g, adfLat.data(), adfLon.data(),
    3260          20 :                      static_cast<int>(adfLat.size()), &dfArea, nullptr);
    3261          20 :     return std::fabs(dfArea);
    3262             : }
    3263             : 
    3264             : /************************************************************************/
    3265             : /*                        get_GeodesicLength()                          */
    3266             : /************************************************************************/
    3267             : 
    3268          25 : double OGRLineString::get_GeodesicLength(
    3269             :     const OGRSpatialReference *poSRSOverride) const
    3270             : {
    3271             :     geod_geodesic g;
    3272          50 :     std::vector<double> adfLat;
    3273          50 :     std::vector<double> adfLon;
    3274          25 :     if (!GetGeodesicInputs(this, poSRSOverride, "length", g, adfLat, adfLon))
    3275           2 :         return -1.0;
    3276          23 :     double dfLength = 0;
    3277         434 :     for (size_t i = 0; i + 1 < adfLon.size(); ++i)
    3278             :     {
    3279         411 :         double dfSegmentLength = 0;
    3280         411 :         geod_inverse(&g, adfLat[i], adfLon[i], adfLat[i + 1], adfLon[i + 1],
    3281             :                      &dfSegmentLength, nullptr, nullptr);
    3282         411 :         dfLength += dfSegmentLength;
    3283             :     }
    3284          23 :     return dfLength;
    3285             : }
    3286             : 
    3287             : /************************************************************************/
    3288             : /*                       get_AreaOfCurveSegments()                      */
    3289             : /************************************************************************/
    3290             : 
    3291          31 : double OGRLineString::get_AreaOfCurveSegments() const
    3292             : {
    3293          31 :     return 0;
    3294             : }
    3295             : 
    3296             : /************************************************************************/
    3297             : /*                            isClockwise()                             */
    3298             : /************************************************************************/
    3299             : 
    3300             : /**
    3301             :  * \brief Returns TRUE if the ring has clockwise winding (or less than 2 points)
    3302             :  *
    3303             :  * Assumes that the line is closed.
    3304             :  *
    3305             :  * @return TRUE if clockwise otherwise FALSE.
    3306             :  */
    3307             : 
    3308       80959 : int OGRLineString::isClockwise() const
    3309             : 
    3310             : {
    3311             :     // WARNING: keep in sync OGRLineString::isClockwise(),
    3312             :     // OGRCurve::isClockwise() and OGRWKBIsClockwiseRing()
    3313             : 
    3314       80959 :     if (nPointCount < 2)
    3315           1 :         return TRUE;
    3316             : 
    3317       80958 :     bool bUseFallback = false;
    3318             : 
    3319             :     // Find the lowest rightmost vertex.
    3320       80958 :     int v = 0;  // Used after for.
    3321     3817720 :     for (int i = 1; i < nPointCount - 1; i++)
    3322             :     {
    3323             :         // => v < end.
    3324     3736770 :         if (paoPoints[i].y < paoPoints[v].y ||
    3325     3247540 :             (paoPoints[i].y == paoPoints[v].y &&
    3326       56976 :              paoPoints[i].x > paoPoints[v].x))
    3327             :         {
    3328      519327 :             v = i;
    3329      519327 :             bUseFallback = false;
    3330             :         }
    3331     3217440 :         else if (paoPoints[i].y == paoPoints[v].y &&
    3332       26860 :                  paoPoints[i].x == paoPoints[v].x)
    3333             :         {
    3334             :             // Two vertex with same coordinates are the lowest rightmost
    3335             :             // vertex.  Cannot use that point as the pivot (#5342).
    3336          96 :             bUseFallback = true;
    3337             :         }
    3338             :     }
    3339             : 
    3340             :     // Previous.
    3341       80958 :     int next = v - 1;
    3342       80958 :     if (next < 0)
    3343             :     {
    3344       28243 :         next = nPointCount - 1 - 1;
    3345             :     }
    3346             : 
    3347       80958 :     constexpr double EPSILON = 1.0E-5;
    3348      180865 :     const auto epsilonEqual = [](double a, double b, double eps)
    3349      180865 :     { return ::fabs(a - b) < eps; };
    3350             : 
    3351       97241 :     if (epsilonEqual(paoPoints[next].x, paoPoints[v].x, EPSILON) &&
    3352       16281 :         epsilonEqual(paoPoints[next].y, paoPoints[v].y, EPSILON))
    3353             :     {
    3354             :         // Don't try to be too clever by retrying with a next point.
    3355             :         // This can lead to false results as in the case of #3356.
    3356         247 :         bUseFallback = true;
    3357             :     }
    3358             : 
    3359       80940 :     const double dx0 = paoPoints[next].x - paoPoints[v].x;
    3360       80940 :     const double dy0 = paoPoints[next].y - paoPoints[v].y;
    3361             : 
    3362             :     // Following.
    3363       80940 :     next = v + 1;
    3364       80940 :     if (next >= nPointCount - 1)
    3365             :     {
    3366       17972 :         next = 0;
    3367             :     }
    3368             : 
    3369       83632 :     if (epsilonEqual(paoPoints[next].x, paoPoints[v].x, EPSILON) &&
    3370        2678 :         epsilonEqual(paoPoints[next].y, paoPoints[v].y, EPSILON))
    3371             :     {
    3372             :         // Don't try to be too clever by retrying with a next point.
    3373             :         // This can lead to false results as in the case of #3356.
    3374         288 :         bUseFallback = true;
    3375             :     }
    3376             : 
    3377       80959 :     const double dx1 = paoPoints[next].x - paoPoints[v].x;
    3378       80959 :     const double dy1 = paoPoints[next].y - paoPoints[v].y;
    3379             : 
    3380       80959 :     const double crossproduct = dx1 * dy0 - dx0 * dy1;
    3381             : 
    3382       80959 :     if (!bUseFallback)
    3383             :     {
    3384       80545 :         if (crossproduct > 0)  // CCW
    3385       45710 :             return FALSE;
    3386       34835 :         else if (crossproduct < 0)  // CW
    3387       34807 :             return TRUE;
    3388             :     }
    3389             : 
    3390             :     // This is a degenerate case: the extent of the polygon is less than EPSILON
    3391             :     // or 2 nearly identical points were found.
    3392             :     // Try with Green Formula as a fallback, but this is not a guarantee
    3393             :     // as we'll probably be affected by numerical instabilities.
    3394             : 
    3395         442 :     double dfSum =
    3396         442 :         paoPoints[0].x * (paoPoints[1].y - paoPoints[nPointCount - 1].y);
    3397             : 
    3398       46396 :     for (int i = 1; i < nPointCount - 1; i++)
    3399             :     {
    3400       45954 :         dfSum += paoPoints[i].x * (paoPoints[i + 1].y - paoPoints[i - 1].y);
    3401             :     }
    3402             : 
    3403         442 :     dfSum += paoPoints[nPointCount - 1].x *
    3404         442 :              (paoPoints[0].y - paoPoints[nPointCount - 2].y);
    3405             : 
    3406         442 :     return dfSum < 0;
    3407             : }
    3408             : 
    3409             : //! @endcond

Generated by: LCOV version 1.14