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

Generated by: LCOV version 1.14