LCOV - code coverage report
Current view: top level - ogr - ogrcurve.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 235 243 96.7 %
Date: 2025-10-21 22:35:35 Functions: 39 41 95.1 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  The OGRCurve geometry class.
       5             :  * Author:   Frank Warmerdam, warmerda@home.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999, Frank Warmerdam
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "ogr_geometry.h"
      14             : #include "ogr_p.h"
      15             : 
      16             : //! @cond Doxygen_Suppress
      17             : 
      18             : /************************************************************************/
      19             : /*                       operator=( const OGRCurve& )                   */
      20             : /************************************************************************/
      21             : 
      22          16 : OGRCurve &OGRCurve::operator=(const OGRCurve &other)
      23             : {
      24          16 :     if (this != &other)
      25             :     {
      26          16 :         OGRGeometry::operator=(other);
      27             :     }
      28          16 :     return *this;
      29             : }
      30             : 
      31             : //! @endcond
      32             : 
      33             : /************************************************************************/
      34             : /*                            getDimension()                            */
      35             : /************************************************************************/
      36             : 
      37         278 : int OGRCurve::getDimension() const
      38             : 
      39             : {
      40         278 :     return 1;
      41             : }
      42             : 
      43             : /************************************************************************/
      44             : /*                            get_IsClosed()                            */
      45             : /************************************************************************/
      46             : 
      47             : /**
      48             :  * \brief Return TRUE if curve is closed.
      49             :  *
      50             :  * Tests if a curve is closed. A curve is closed if its start point is
      51             :  * equal to its end point.
      52             :  *
      53             :  * For equality tests, the M dimension is ignored.
      54             :  *
      55             :  * This method relates to the SFCOM ICurve::get_IsClosed() method.
      56             :  *
      57             :  * @return TRUE if closed, else FALSE.
      58             :  */
      59             : 
      60      228046 : int OGRCurve::get_IsClosed() const
      61             : 
      62             : {
      63      456092 :     OGRPoint oStartPoint;
      64      228046 :     StartPoint(&oStartPoint);
      65             : 
      66      456091 :     OGRPoint oEndPoint;
      67      228046 :     EndPoint(&oEndPoint);
      68             : 
      69      228046 :     if (oStartPoint.Is3D() && oEndPoint.Is3D())
      70             :     {
      71             :         // XYZ type
      72       40788 :         if (oStartPoint.getX() == oEndPoint.getX() &&
      73       40788 :             oStartPoint.getY() == oEndPoint.getY() &&
      74       19522 :             oStartPoint.getZ() == oEndPoint.getZ())
      75             :         {
      76       18923 :             return TRUE;
      77             :         }
      78             :         else
      79        1769 :             return FALSE;
      80             :     }
      81             : 
      82             :     // one of the points is 3D
      83      414706 :     else if (((oStartPoint.Is3D() & oEndPoint.Is3D()) == 0) &&
      84      207354 :              ((oStartPoint.Is3D() | oEndPoint.Is3D()) == 1))
      85             :     {
      86           0 :         return FALSE;
      87             :     }
      88             : 
      89             :     else
      90             :     {
      91             :         // XY type
      92      411670 :         if (oStartPoint.getX() == oEndPoint.getX() &&
      93      204318 :             oStartPoint.getY() == oEndPoint.getY())
      94      203440 :             return TRUE;
      95             :         else
      96        3913 :             return FALSE;
      97             :     }
      98             : }
      99             : 
     100             : /**
     101             :  * \fn double OGRCurve::get_Length() const;
     102             :  *
     103             :  * \brief Returns the length of the curve.
     104             :  *
     105             :  * This method relates to the SFCOM ICurve::get_Length() method.
     106             :  *
     107             :  * @return the length of the curve, zero if the curve hasn't been
     108             :  * initialized.
     109             :  *
     110             :  * @see get_GeodesicLength() for an alternative method returning lengths
     111             :  * computed on the ellipsoid, and in meters.
     112             :  */
     113             : 
     114             : /**
     115             :  * \fn double OGRCurve::get_GeodesicLength(const OGRSpatialReference* poSRSOverride = nullptr) const;
     116             :  *
     117             :  * \brief Get the length of the curve, considered as a geodesic line on the
     118             :  * underlying ellipsoid of the SRS attached to the geometry.
     119             :  *
     120             :  * The returned length will always be in meters.
     121             :  *
     122             :  * <a href="https://geographiclib.sourceforge.io/html/python/geodesics.html">Geodesics</a>
     123             :  * follow the shortest route on the surface of the ellipsoid.
     124             :  *
     125             :  * If the geometry' SRS is not a geographic one, geometries are reprojected to
     126             :  * the underlying geographic SRS of the geometry' SRS.
     127             :  * OGRSpatialReference::GetDataAxisToSRSAxisMapping() is honored.
     128             :  *
     129             :  * Note that geometries with circular arcs will be linearized in their original
     130             :  * coordinate space first, so the resulting geodesic length will be an
     131             :  * approximation.
     132             :  *
     133             :  * @param poSRSOverride If not null, overrides OGRGeometry::getSpatialReference()
     134             :  * @return the length of the geometry in meters, or a negative value in case
     135             :  * of error.
     136             :  *
     137             :  * @see get_Length() for an alternative method returning areas computed in
     138             :  * 2D Cartesian space.
     139             :  *
     140             :  * @since GDAL 3.10
     141             :  */
     142             : 
     143             : /**
     144             :  * \fn void OGRCurve::StartPoint( OGRPoint * poPoint ) const;
     145             :  *
     146             :  * \brief Return the curve start point.
     147             :  *
     148             :  * This method relates to the SF COM ICurve::get_StartPoint() method.
     149             :  *
     150             :  * @param poPoint the point to be assigned the start location.
     151             :  */
     152             : 
     153             : /**
     154             :  * \fn void OGRCurve::EndPoint( OGRPoint * poPoint ) const;
     155             :  *
     156             :  * \brief Return the curve end point.
     157             :  *
     158             :  * This method relates to the SF COM ICurve::get_EndPoint() method.
     159             :  *
     160             :  * @param poPoint the point to be assigned the end location.
     161             :  */
     162             : 
     163             : /**
     164             :  * \fn void OGRCurve::Value( double dfDistance, OGRPoint * poPoint ) const;
     165             :  *
     166             :  * \brief Fetch point at given distance along curve.
     167             :  *
     168             :  * This method relates to the SF COM ICurve::get_Value() method.
     169             :  *
     170             :  * This function is the same as the C function OGR_G_Value().
     171             :  *
     172             :  * @param dfDistance distance along the curve at which to sample position.
     173             :  *                   This distance should be between zero and get_Length()
     174             :  *                   for this curve.
     175             :  * @param poPoint the point to be assigned the curve position.
     176             :  */
     177             : 
     178             : /**
     179             :  * \fn OGRLineString* OGRCurve::CurveToLine( double dfMaxAngleStepSizeDegrees,
     180             :  *     const char* const* papszOptions ) const;
     181             :  *
     182             :  * \brief Return a linestring from a curve geometry.
     183             :  *
     184             :  * The returned geometry is a new instance whose ownership belongs to the
     185             :  * caller.
     186             :  *
     187             :  * If the dfMaxAngleStepSizeDegrees is zero, then a default value will be
     188             :  * used.  This is currently 4 degrees unless the user has overridden the
     189             :  * value with the OGR_ARC_STEPSIZE configuration variable.
     190             :  *
     191             :  * This method relates to the ISO SQL/MM Part 3 ICurve::CurveToLine() method.
     192             :  *
     193             :  * This function is the same as C function OGR_G_CurveToLine().
     194             :  *
     195             :  * @param dfMaxAngleStepSizeDegrees the largest step in degrees along the
     196             :  * arc, zero to use the default setting.
     197             :  * @param papszOptions options as a null-terminated list of strings or NULL.
     198             :  *                     See OGRGeometryFactory::curveToLineString() for valid
     199             :  *                     options.
     200             :  *
     201             :  * @return a line string approximating the curve
     202             :  *
     203             :  */
     204             : 
     205             : /**
     206             :  * \fn int OGRCurve::getNumPoints() const;
     207             :  *
     208             :  * \brief Return the number of points of a curve geometry.
     209             :  *
     210             :  *
     211             :  * This method, as a method of OGRCurve, does not relate to a standard.
     212             :  * For circular strings or linestrings, it returns the number of points,
     213             :  * conforming to SF COM NumPoints().
     214             :  * For compound curves, it returns the sum of the number of points of each
     215             :  * of its components (non including intermediate starting/ending points of
     216             :  * the different parts).
     217             :  *
     218             :  * @return the number of points of the curve.
     219             :  *
     220             :  */
     221             : 
     222             : /**
     223             :  * \fn OGRPointIterator* OGRCurve::getPointIterator() const;
     224             :  *
     225             :  * \brief Returns a point iterator over the curve.
     226             :  *
     227             :  * The curve must not be modified while an iterator exists on it.
     228             :  *
     229             :  * The iterator must be destroyed with OGRPointIterator::destroy().
     230             :  *
     231             :  * @return a point iterator over the curve.
     232             :  *
     233             :  */
     234             : 
     235             : /**
     236             :  * \fn double OGRCurve::get_Area() const;
     237             :  *
     238             :  * \brief Get the area of the (closed) curve.
     239             :  *
     240             :  * This method is designed to be used by OGRCurvePolygon::get_Area().
     241             :  *
     242             :  * @return the area of the geometry in square units of the spatial reference
     243             :  * system in use.
     244             :  *
     245             :  * @see get_GeodesicArea() for an alternative method returning areas
     246             :  * computed on the ellipsoid, and in square meters.
     247             :  *
     248             :  */
     249             : 
     250             : /**
     251             :  * \fn double OGRCurve::get_GeodesicArea(const OGRSpatialReference* poSRSOverride = nullptr) const;
     252             :  *
     253             :  * \brief Get the area of the (closed) curve, considered as a surface on the
     254             :  * underlying ellipsoid of the SRS attached to the geometry.
     255             :  *
     256             :  * This method is designed to be used by OGRCurvePolygon::get_GeodesicArea().
     257             :  *
     258             :  * The returned area will always be in square meters, and assumes that
     259             :  * polygon edges describe geodesic lines on the ellipsoid.
     260             :  *
     261             :  * <a href="https://geographiclib.sourceforge.io/html/python/geodesics.html">Geodesics</a>
     262             :  * follow the shortest route on the surface of the ellipsoid.
     263             :  *
     264             :  * If the geometry' SRS is not a geographic one, geometries are reprojected to
     265             :  * the underlying geographic SRS of the geometry' SRS.
     266             :  * OGRSpatialReference::GetDataAxisToSRSAxisMapping() is honored.
     267             :  *
     268             :  * Note that geometries with circular arcs will be linearized in their original
     269             :  * coordinate space first, so the resulting geodesic area will be an
     270             :  * approximation.
     271             :  *
     272             :  * @param poSRSOverride If not null, overrides OGRGeometry::getSpatialReference()
     273             :  * @return the area of the geometry in square meters, or a negative value in case
     274             :  * of error.
     275             :  *
     276             :  * @see get_Area() for an alternative method returning areas computed in
     277             :  * 2D Cartesian space.
     278             :  *
     279             :  * @since GDAL 3.9
     280             :  */
     281             : 
     282             : /**
     283             :  * \fn double OGRCurve::get_AreaOfCurveSegments() const;
     284             :  *
     285             :  * \brief Get the area of the purely curve portions of a (closed) curve.
     286             :  *
     287             :  * This method is designed to be used on a closed convex curve.
     288             :  *
     289             :  * @return the area of the feature in square units of the spatial reference
     290             :  * system in use.
     291             :  *
     292             :  */
     293             : 
     294             : /************************************************************************/
     295             : /*                              IsConvex()                              */
     296             : /************************************************************************/
     297             : 
     298             : /**
     299             :  * \brief Returns if a (closed) curve forms a convex shape.
     300             :  *
     301             :  * @return TRUE if the curve forms a convex shape.
     302             :  *
     303             :  */
     304             : 
     305          42 : OGRBoolean OGRCurve::IsConvex() const
     306             : {
     307          42 :     bool bRet = true;
     308          42 :     OGRPointIterator *poPointIter = getPointIterator();
     309          84 :     OGRPoint p1;
     310          42 :     OGRPoint p2;
     311          42 :     if (poPointIter->getNextPoint(&p1) && poPointIter->getNextPoint(&p2))
     312             :     {
     313          84 :         OGRPoint p3;
     314         168 :         while (poPointIter->getNextPoint(&p3))
     315             :         {
     316             :             const double crossproduct =
     317         140 :                 (p2.getX() - p1.getX()) * (p3.getY() - p2.getY()) -
     318         140 :                 (p2.getY() - p1.getY()) * (p3.getX() - p2.getX());
     319         140 :             if (crossproduct > 0)
     320             :             {
     321          14 :                 bRet = false;
     322          14 :                 break;
     323             :             }
     324         126 :             p1.setX(p2.getX());
     325         126 :             p1.setY(p2.getY());
     326         126 :             p2.setX(p3.getX());
     327         126 :             p2.setY(p3.getY());
     328             :         }
     329             :     }
     330          42 :     delete poPointIter;
     331          84 :     return bRet;
     332             : }
     333             : 
     334             : /************************************************************************/
     335             : /*                          CastToCompoundCurve()                       */
     336             : /************************************************************************/
     337             : 
     338             : /**
     339             :  * \brief Cast to compound curve
     340             :  *
     341             :  * The passed in geometry is consumed and a new one returned (or NULL in case
     342             :  * of failure)
     343             :  *
     344             :  * @param poCurve the input geometry - ownership is passed to the method.
     345             :  * @return new geometry
     346             :  *
     347             :  */
     348             : 
     349          32 : OGRCompoundCurve *OGRCurve::CastToCompoundCurve(OGRCurve *poCurve)
     350             : {
     351          32 :     OGRCompoundCurve *poCC = new OGRCompoundCurve();
     352          32 :     if (wkbFlatten(poCurve->getGeometryType()) == wkbLineString)
     353          23 :         poCurve = CastToLineString(poCurve);
     354          32 :     if (!poCurve->IsEmpty() && poCC->addCurveDirectly(poCurve) != OGRERR_NONE)
     355             :     {
     356           2 :         delete poCC;
     357           2 :         delete poCurve;
     358           2 :         return nullptr;
     359             :     }
     360          30 :     poCC->assignSpatialReference(poCurve->getSpatialReference());
     361          30 :     return poCC;
     362             : }
     363             : 
     364             : /************************************************************************/
     365             : /*                          CastToLineString()                          */
     366             : /************************************************************************/
     367             : 
     368             : /**
     369             :  * \brief Cast to linestring
     370             :  *
     371             :  * The passed in geometry is consumed and a new one returned (or NULL in case
     372             :  * of failure)
     373             :  *
     374             :  * @param poCurve the input geometry - ownership is passed to the method.
     375             :  * @return new geometry.
     376             :  *
     377             :  */
     378             : 
     379         224 : OGRLineString *OGRCurve::CastToLineString(OGRCurve *poCurve)
     380             : {
     381         224 :     OGRCurveCasterToLineString pfn = poCurve->GetCasterToLineString();
     382         224 :     return pfn(poCurve);
     383             : }
     384             : 
     385             : /************************************************************************/
     386             : /*                          CastToLinearRing()                          */
     387             : /************************************************************************/
     388             : 
     389             : /**
     390             :  * \brief Cast to linear ring
     391             :  *
     392             :  * The passed in geometry is consumed and a new one returned (or NULL in case
     393             :  * of failure)
     394             :  *
     395             :  * @param poCurve the input geometry - ownership is passed to the method.
     396             :  * @return new geometry.
     397             :  *
     398             :  */
     399             : 
     400         551 : OGRLinearRing *OGRCurve::CastToLinearRing(OGRCurve *poCurve)
     401             : {
     402         551 :     OGRCurveCasterToLinearRing pfn = poCurve->GetCasterToLinearRing();
     403         551 :     return pfn(poCurve);
     404             : }
     405             : 
     406             : /************************************************************************/
     407             : /*                           ContainsPoint()                            */
     408             : /************************************************************************/
     409             : 
     410             : /**
     411             :  * \brief Returns if a point is contained in a (closed) curve.
     412             :  *
     413             :  * Final users should use OGRGeometry::Contains() instead.
     414             :  *
     415             :  * @param p the point to test
     416             :  * @return TRUE if it is inside the curve, FALSE otherwise or -1 if unknown.
     417             :  *
     418             :  */
     419             : 
     420          17 : int OGRCurve::ContainsPoint(CPL_UNUSED const OGRPoint *p) const
     421             : {
     422          17 :     return -1;
     423             : }
     424             : 
     425             : /************************************************************************/
     426             : /*                         IntersectsPoint()                            */
     427             : /************************************************************************/
     428             : 
     429             : /**
     430             :  * \brief Returns if a point intersects a (closed) curve.
     431             :  *
     432             :  * Final users should use OGRGeometry::Intersects() instead.
     433             :  *
     434             :  * @param p the point to test
     435             :  * @return TRUE if it intersects the curve, FALSE otherwise or -1 if unknown.
     436             :  *
     437             :  */
     438             : 
     439           1 : int OGRCurve::IntersectsPoint(CPL_UNUSED const OGRPoint *p) const
     440             : {
     441           1 :     return -1;
     442             : }
     443             : 
     444             : /************************************************************************/
     445             : /*                          ~OGRPointIterator()                         */
     446             : /************************************************************************/
     447             : 
     448             : OGRPointIterator::~OGRPointIterator() = default;
     449             : 
     450             : /**
     451             :  * \fn OGRBoolean OGRPointIterator::getNextPoint(OGRPoint* p);
     452             :  *
     453             :  * \brief Returns the next point followed by the iterator.
     454             :  *
     455             :  * @param p point to fill.
     456             :  *
     457             :  * @return TRUE in case of success, or FALSE if the end of the curve is reached.
     458             :  *
     459             :  */
     460             : 
     461             : /************************************************************************/
     462             : /*                              destroy()                               */
     463             : /************************************************************************/
     464             : 
     465             : /**
     466             :  * \brief Destroys a point iterator.
     467             :  *
     468             :  */
     469           0 : void OGRPointIterator::destroy(OGRPointIterator *poIter)
     470             : {
     471           0 :     delete poIter;
     472           0 : }
     473             : 
     474             : /************************************************************************/
     475             : /*                     OGRSimpleCurve::Iterator                         */
     476             : /************************************************************************/
     477             : 
     478             : OGRIteratedPoint::~OGRIteratedPoint() = default;
     479             : 
     480           2 : void OGRIteratedPoint::setX(double xIn)
     481             : {
     482           2 :     OGRPoint::setX(xIn);
     483           2 :     m_poCurve->setPoint(m_nPos, xIn, getY());
     484           2 : }
     485             : 
     486           2 : void OGRIteratedPoint::setY(double yIn)
     487             : {
     488           2 :     OGRPoint::setY(yIn);
     489           2 :     m_poCurve->setPoint(m_nPos, getX(), yIn);
     490           2 : }
     491             : 
     492           2 : void OGRIteratedPoint::setZ(double zIn)
     493             : {
     494           2 :     OGRPoint::setZ(zIn);
     495           2 :     m_poCurve->setZ(m_nPos, zIn);
     496           2 : }
     497             : 
     498           2 : void OGRIteratedPoint::setM(double mIn)
     499             : {
     500           2 :     OGRPoint::setM(mIn);
     501           2 :     m_poCurve->setM(m_nPos, mIn);
     502           2 : }
     503             : 
     504             : struct OGRSimpleCurve::Iterator::Private
     505             : {
     506             :     CPL_DISALLOW_COPY_ASSIGN(Private)
     507         228 :     Private() = default;
     508             : 
     509             :     bool m_bUpdateChecked = true;
     510             :     OGRIteratedPoint m_oPoint{};
     511             : };
     512             : 
     513        2528 : void OGRSimpleCurve::Iterator::update()
     514             : {
     515        2528 :     if (!m_poPrivate->m_bUpdateChecked)
     516             :     {
     517        1149 :         OGRPoint oPointBefore;
     518        1149 :         m_poPrivate->m_oPoint.m_poCurve->getPoint(m_poPrivate->m_oPoint.m_nPos,
     519             :                                                   &oPointBefore);
     520        1149 :         if (oPointBefore != m_poPrivate->m_oPoint)
     521             :         {
     522         899 :             if (m_poPrivate->m_oPoint.Is3D())
     523         739 :                 m_poPrivate->m_oPoint.m_poCurve->set3D(true);
     524         899 :             if (m_poPrivate->m_oPoint.IsMeasured())
     525           4 :                 m_poPrivate->m_oPoint.m_poCurve->setMeasured(true);
     526        1798 :             m_poPrivate->m_oPoint.m_poCurve->setPoint(
     527         899 :                 m_poPrivate->m_oPoint.m_nPos, &m_poPrivate->m_oPoint);
     528             :         }
     529        1149 :         m_poPrivate->m_bUpdateChecked = true;
     530             :     }
     531        2528 : }
     532             : 
     533         228 : OGRSimpleCurve::Iterator::Iterator(OGRSimpleCurve *poSelf, int nPos)
     534         228 :     : m_poPrivate(new Private())
     535             : {
     536         228 :     m_poPrivate->m_oPoint.m_poCurve = poSelf;
     537         228 :     m_poPrivate->m_oPoint.m_nPos = nPos;
     538         228 : }
     539             : 
     540         228 : OGRSimpleCurve::Iterator::~Iterator()
     541             : {
     542         228 :     update();
     543         228 : }
     544             : 
     545        1149 : OGRIteratedPoint &OGRSimpleCurve::Iterator::operator*()
     546             : {
     547        1149 :     update();
     548        2298 :     m_poPrivate->m_oPoint.m_poCurve->getPoint(m_poPrivate->m_oPoint.m_nPos,
     549        1149 :                                               &m_poPrivate->m_oPoint);
     550        1149 :     m_poPrivate->m_bUpdateChecked = false;
     551        1149 :     return m_poPrivate->m_oPoint;
     552             : }
     553             : 
     554        1151 : OGRSimpleCurve::Iterator &OGRSimpleCurve::Iterator::operator++()
     555             : {
     556        1151 :     update();
     557        1151 :     ++m_poPrivate->m_oPoint.m_nPos;
     558        1151 :     return *this;
     559             : }
     560             : 
     561        1266 : bool OGRSimpleCurve::Iterator::operator!=(const Iterator &it) const
     562             : {
     563        1266 :     return m_poPrivate->m_oPoint.m_nPos != it.m_poPrivate->m_oPoint.m_nPos;
     564             : }
     565             : 
     566         115 : OGRSimpleCurve::Iterator OGRSimpleCurve::begin()
     567             : {
     568         115 :     return {this, 0};
     569             : }
     570             : 
     571         113 : OGRSimpleCurve::Iterator OGRSimpleCurve::end()
     572             : {
     573         113 :     return {this, nPointCount};
     574             : }
     575             : 
     576             : /************************************************************************/
     577             : /*                  OGRSimpleCurve::ConstIterator                       */
     578             : /************************************************************************/
     579             : 
     580             : struct OGRSimpleCurve::ConstIterator::Private
     581             : {
     582             :     CPL_DISALLOW_COPY_ASSIGN(Private)
     583         250 :     Private() = default;
     584             : 
     585             :     mutable OGRIteratedPoint m_oPoint{};
     586             :     const OGRSimpleCurve *m_poSelf = nullptr;
     587             :     int m_nPos = 0;
     588             : };
     589             : 
     590         250 : OGRSimpleCurve::ConstIterator::ConstIterator(const OGRSimpleCurve *poSelf,
     591         250 :                                              int nPos)
     592         250 :     : m_poPrivate(new Private())
     593             : {
     594         250 :     m_poPrivate->m_poSelf = poSelf;
     595         250 :     m_poPrivate->m_nPos = nPos;
     596         250 : }
     597             : 
     598             : OGRSimpleCurve::ConstIterator::~ConstIterator() = default;
     599             : 
     600        2623 : const OGRPoint &OGRSimpleCurve::ConstIterator::operator*() const
     601             : {
     602        5246 :     m_poPrivate->m_poSelf->getPoint(m_poPrivate->m_nPos,
     603        2623 :                                     &m_poPrivate->m_oPoint);
     604        2623 :     return m_poPrivate->m_oPoint;
     605             : }
     606             : 
     607        2623 : OGRSimpleCurve::ConstIterator &OGRSimpleCurve::ConstIterator::operator++()
     608             : {
     609        2623 :     ++m_poPrivate->m_nPos;
     610        2623 :     return *this;
     611             : }
     612             : 
     613        2748 : bool OGRSimpleCurve::ConstIterator::operator!=(const ConstIterator &it) const
     614             : {
     615        2748 :     return m_poPrivate->m_nPos != it.m_poPrivate->m_nPos;
     616             : }
     617             : 
     618         125 : OGRSimpleCurve::ConstIterator OGRSimpleCurve::begin() const
     619             : {
     620         125 :     return {this, 0};
     621             : }
     622             : 
     623         125 : OGRSimpleCurve::ConstIterator OGRSimpleCurve::end() const
     624             : {
     625         125 :     return {this, nPointCount};
     626             : }
     627             : 
     628             : /************************************************************************/
     629             : /*                     OGRCurve::ConstIterator                          */
     630             : /************************************************************************/
     631             : 
     632             : struct OGRCurve::ConstIterator::Private
     633             : {
     634             :     CPL_DISALLOW_COPY_ASSIGN(Private)
     635          38 :     Private() = default;
     636             :     Private(Private &&) = delete;
     637             :     Private &operator=(Private &&) = default;
     638             : 
     639             :     OGRPoint m_oPoint{};
     640             :     const OGRCurve *m_poCurve{};
     641             :     int m_nStep = 0;
     642             :     std::unique_ptr<OGRPointIterator> m_poIterator{};
     643             : };
     644             : 
     645          38 : OGRCurve::ConstIterator::ConstIterator(const OGRCurve *poSelf, bool bStart)
     646          38 :     : m_poPrivate(new Private())
     647             : {
     648          38 :     m_poPrivate->m_poCurve = poSelf;
     649          38 :     if (bStart)
     650             :     {
     651          30 :         m_poPrivate->m_poIterator.reset(poSelf->getPointIterator());
     652          30 :         if (!m_poPrivate->m_poIterator->getNextPoint(&m_poPrivate->m_oPoint))
     653             :         {
     654           2 :             m_poPrivate->m_nStep = -1;
     655           2 :             m_poPrivate->m_poIterator.reset();
     656             :         }
     657             :     }
     658             :     else
     659             :     {
     660           8 :         m_poPrivate->m_nStep = -1;
     661             :     }
     662          38 : }
     663             : 
     664           0 : OGRCurve::ConstIterator::ConstIterator(ConstIterator &&oOther) noexcept
     665           0 :     : m_poPrivate(std::move(oOther.m_poPrivate))
     666             : {
     667           0 : }
     668             : 
     669             : OGRCurve::ConstIterator &
     670           4 : OGRCurve::ConstIterator::operator=(ConstIterator &&oOther)
     671             : {
     672           4 :     m_poPrivate = std::move(oOther.m_poPrivate);
     673           4 :     return *this;
     674             : }
     675             : 
     676             : OGRCurve::ConstIterator::~ConstIterator() = default;
     677             : 
     678         119 : const OGRPoint &OGRCurve::ConstIterator::operator*() const
     679             : {
     680         119 :     return m_poPrivate->m_oPoint;
     681             : }
     682             : 
     683          83 : OGRCurve::ConstIterator &OGRCurve::ConstIterator::operator++()
     684             : {
     685          83 :     CPLAssert(m_poPrivate->m_nStep >= 0);
     686          83 :     ++m_poPrivate->m_nStep;
     687          83 :     if (!m_poPrivate->m_poIterator->getNextPoint(&m_poPrivate->m_oPoint))
     688             :     {
     689           6 :         m_poPrivate->m_nStep = -1;
     690           6 :         m_poPrivate->m_poIterator.reset();
     691             :     }
     692          83 :     return *this;
     693             : }
     694             : 
     695          24 : bool OGRCurve::ConstIterator::operator!=(const ConstIterator &it) const
     696             : {
     697          48 :     return m_poPrivate->m_poCurve != it.m_poPrivate->m_poCurve ||
     698          48 :            m_poPrivate->m_nStep != it.m_poPrivate->m_nStep;
     699             : }
     700             : 
     701          30 : OGRCurve::ConstIterator OGRCurve::begin() const
     702             : {
     703          30 :     return {this, true};
     704             : }
     705             : 
     706           8 : OGRCurve::ConstIterator OGRCurve::end() const
     707             : {
     708           8 :     return {this, false};
     709             : }
     710             : 
     711             : /************************************************************************/
     712             : /*                            isClockwise()                             */
     713             : /************************************************************************/
     714             : 
     715             : /**
     716             :  * \brief Returns TRUE if the ring has clockwise winding (or less than 2 points)
     717             :  *
     718             :  * Assumes that the line is closed.
     719             :  *
     720             :  * @return TRUE if clockwise otherwise FALSE.
     721             :  */
     722             : 
     723          18 : int OGRCurve::isClockwise() const
     724             : 
     725             : {
     726             :     // WARNING: keep in sync OGRLineString::isClockwise(),
     727             :     // OGRCurve::isClockwise() and OGRWKBIsClockwiseRing()
     728             : 
     729          18 :     const int nPointCount = getNumPoints();
     730          18 :     if (nPointCount < 3)
     731           0 :         return TRUE;
     732             : 
     733          18 :     bool bUseFallback = false;
     734             : 
     735             :     // Find the lowest rightmost vertex.
     736          36 :     auto oIter = begin();
     737          36 :     const OGRPoint oStartPoint = *oIter;
     738          36 :     OGRPoint oPointBefore = oStartPoint;
     739          36 :     OGRPoint oPointBeforeSel;
     740          36 :     OGRPoint oPointSel = oStartPoint;
     741          36 :     OGRPoint oPointNextSel;
     742          18 :     bool bNextPointIsNextSel = true;
     743          18 :     int v = 0;
     744             : 
     745          69 :     for (int i = 1; i < nPointCount - 1; i++)
     746             :     {
     747          51 :         ++oIter;
     748         102 :         const OGRPoint oPointCur = *oIter;
     749          51 :         if (bNextPointIsNextSel)
     750             :         {
     751          28 :             oPointNextSel = oPointCur;
     752          28 :             bNextPointIsNextSel = false;
     753             :         }
     754         102 :         if (oPointCur.getY() < oPointSel.getY() ||
     755          51 :             (oPointCur.getY() == oPointSel.getY() &&
     756          11 :              oPointCur.getX() > oPointSel.getX()))
     757             :         {
     758          18 :             v = i;
     759          18 :             oPointBeforeSel = oPointBefore;
     760          18 :             oPointSel = oPointCur;
     761          18 :             bUseFallback = false;
     762          18 :             bNextPointIsNextSel = true;
     763             :         }
     764          37 :         else if (oPointCur.getY() == oPointSel.getY() &&
     765           4 :                  oPointCur.getX() == oPointSel.getX())
     766             :         {
     767             :             // Two vertex with same coordinates are the lowest rightmost
     768             :             // vertex.  Cannot use that point as the pivot (#5342).
     769           4 :             bUseFallback = true;
     770             :         }
     771          51 :         oPointBefore = oPointCur;
     772             :     }
     773          36 :     const OGRPoint oPointN_m2 = *oIter;
     774             : 
     775          18 :     if (bNextPointIsNextSel)
     776             :     {
     777           8 :         oPointNextSel = oPointN_m2;
     778             :     }
     779             : 
     780             :     // Previous.
     781          18 :     if (v == 0)
     782             :     {
     783           5 :         oPointBeforeSel = oPointN_m2;
     784             :     }
     785             : 
     786          18 :     constexpr double EPSILON = 1.0E-5;
     787          40 :     const auto epsilonEqual = [](double a, double b, double eps)
     788          40 :     { return ::fabs(a - b) < eps; };
     789             : 
     790          20 :     if (epsilonEqual(oPointBeforeSel.getX(), oPointSel.getX(), EPSILON) &&
     791           2 :         epsilonEqual(oPointBeforeSel.getY(), oPointSel.getY(), EPSILON))
     792             :     {
     793             :         // Don't try to be too clever by retrying with a next point.
     794             :         // This can lead to false results as in the case of #3356.
     795           2 :         bUseFallback = true;
     796             :     }
     797             : 
     798          18 :     const double dx0 = oPointBeforeSel.getX() - oPointSel.getX();
     799          18 :     const double dy0 = oPointBeforeSel.getY() - oPointSel.getY();
     800             : 
     801             :     // Following.
     802          18 :     if (v + 1 >= nPointCount - 1)
     803             :     {
     804           8 :         oPointNextSel = oStartPoint;
     805             :     }
     806             : 
     807          20 :     if (epsilonEqual(oPointNextSel.getX(), oPointSel.getX(), EPSILON) &&
     808           2 :         epsilonEqual(oPointNextSel.getY(), oPointSel.getY(), EPSILON))
     809             :     {
     810             :         // Don't try to be too clever by retrying with a next point.
     811             :         // This can lead to false results as in the case of #3356.
     812           2 :         bUseFallback = true;
     813             :     }
     814             : 
     815          18 :     const double dx1 = oPointNextSel.getX() - oPointSel.getX();
     816          18 :     const double dy1 = oPointNextSel.getY() - oPointSel.getY();
     817             : 
     818          18 :     const double crossproduct = dx1 * dy0 - dx0 * dy1;
     819             : 
     820          18 :     if (!bUseFallback)
     821             :     {
     822          14 :         if (crossproduct > 0)  // CCW
     823           5 :             return FALSE;
     824           9 :         else if (crossproduct < 0)  // CW
     825           9 :             return TRUE;
     826             :     }
     827             : 
     828             :     // This is a degenerate case: the extent of the polygon is less than EPSILON
     829             :     // or 2 nearly identical points were found.
     830             :     // Try with Green Formula as a fallback, but this is not a guarantee
     831             :     // as we'll probably be affected by numerical instabilities.
     832           4 :     oIter = begin();
     833           4 :     oPointBefore = oStartPoint;
     834           4 :     ++oIter;
     835           4 :     auto oPointCur = *oIter;
     836           4 :     double dfSum = oStartPoint.getX() * (oPointCur.getY() - oStartPoint.getY());
     837             : 
     838          16 :     for (int i = 1; i < nPointCount - 1; i++)
     839             :     {
     840          12 :         ++oIter;
     841          12 :         const auto &oPointNext = *oIter;
     842          12 :         dfSum += oPointCur.getX() * (oPointNext.getY() - oPointBefore.getY());
     843          12 :         oPointBefore = oPointCur;
     844          12 :         oPointCur = oPointNext;
     845             :     }
     846             : 
     847           4 :     dfSum += oPointCur.getX() * (oStartPoint.getY() - oPointBefore.getY());
     848             : 
     849           4 :     return dfSum < 0;
     850             : }
     851             : 
     852             : /**
     853             :  * \fn void OGRCurve::reversePoints();
     854             :  *
     855             :  * \brief Reverse point order.
     856             :  *
     857             :  * This method updates the points in this curve in place
     858             :  * reversing the point ordering (first for last, etc) and component ordering
     859             :  * for a compound curve.
     860             :  *
     861             :  * @since 3.10
     862             :  */

Generated by: LCOV version 1.14