LCOV - code coverage report
Current view: top level - ogr - ogrcompoundcurve.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 300 312 96.2 %
Date: 2025-01-18 12:42:00 Functions: 59 59 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  The OGRCompoundCurve geometry class.
       5             :  * Author:   Even Rouault, even dot rouault at spatialys dot com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_port.h"
      14             : #include "ogr_geometry.h"
      15             : 
      16             : #include <cmath>
      17             : #include <cstddef>
      18             : 
      19             : #include "cpl_error.h"
      20             : #include "ogr_core.h"
      21             : #include "ogr_geometry.h"
      22             : #include "ogr_p.h"
      23             : #include "ogr_spatialref.h"
      24             : 
      25             : /************************************************************************/
      26             : /*             OGRCompoundCurve( const OGRCompoundCurve& )              */
      27             : /************************************************************************/
      28             : 
      29             : /**
      30             :  * \brief Copy constructor.
      31             :  *
      32             :  * Note: before GDAL 2.1, only the default implementation of the constructor
      33             :  * existed, which could be unsafe to use.
      34             :  *
      35             :  * @since GDAL 2.1
      36             :  */
      37             : 
      38             : OGRCompoundCurve::OGRCompoundCurve(const OGRCompoundCurve &) = default;
      39             : 
      40             : /************************************************************************/
      41             : /*                 operator=( const OGRCompoundCurve&)                  */
      42             : /************************************************************************/
      43             : 
      44             : /**
      45             :  * \brief Assignment operator.
      46             :  *
      47             :  * Note: before GDAL 2.1, only the default implementation of the operator
      48             :  * existed, which could be unsafe to use.
      49             :  *
      50             :  * @since GDAL 2.1
      51             :  */
      52             : 
      53           5 : OGRCompoundCurve &OGRCompoundCurve::operator=(const OGRCompoundCurve &other)
      54             : {
      55           5 :     if (this != &other)
      56             :     {
      57           4 :         OGRCurve::operator=(other);
      58             : 
      59           4 :         oCC = other.oCC;
      60             :     }
      61           5 :     return *this;
      62             : }
      63             : 
      64             : /************************************************************************/
      65             : /*                               clone()                                */
      66             : /************************************************************************/
      67             : 
      68         260 : OGRCompoundCurve *OGRCompoundCurve::clone() const
      69             : 
      70             : {
      71         260 :     auto ret = new (std::nothrow) OGRCompoundCurve(*this);
      72         260 :     if (ret)
      73             :     {
      74         260 :         if (ret->WkbSize() != WkbSize())
      75             :         {
      76           0 :             delete ret;
      77           0 :             ret = nullptr;
      78             :         }
      79             :     }
      80         260 :     return ret;
      81             : }
      82             : 
      83             : /************************************************************************/
      84             : /*                          getGeometryType()                           */
      85             : /************************************************************************/
      86             : 
      87        6283 : OGRwkbGeometryType OGRCompoundCurve::getGeometryType() const
      88             : 
      89             : {
      90        6283 :     if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
      91        4659 :         return wkbCompoundCurveZM;
      92        1624 :     else if (flags & OGR_G_MEASURED)
      93          11 :         return wkbCompoundCurveM;
      94        1613 :     else if (flags & OGR_G_3D)
      95         166 :         return wkbCompoundCurveZ;
      96             :     else
      97        1447 :         return wkbCompoundCurve;
      98             : }
      99             : 
     100             : /************************************************************************/
     101             : /*                          getGeometryName()                           */
     102             : /************************************************************************/
     103             : 
     104         951 : const char *OGRCompoundCurve::getGeometryName() const
     105             : 
     106             : {
     107         951 :     return "COMPOUNDCURVE";
     108             : }
     109             : 
     110             : /************************************************************************/
     111             : /*                              WkbSize()                               */
     112             : /************************************************************************/
     113        1517 : size_t OGRCompoundCurve::WkbSize() const
     114             : {
     115        1517 :     return oCC.WkbSize();
     116             : }
     117             : 
     118             : /************************************************************************/
     119             : /*                       addCurveDirectlyFromWkt()                      */
     120             : /************************************************************************/
     121             : 
     122        1725 : OGRErr OGRCompoundCurve::addCurveDirectlyFromWkb(OGRGeometry *poSelf,
     123             :                                                  OGRCurve *poCurve)
     124             : {
     125        1725 :     OGRCompoundCurve *poCC = poSelf->toCompoundCurve();
     126        1725 :     return poCC->addCurveDirectlyInternal(poCurve, DEFAULT_TOLERANCE_EPSILON,
     127        1725 :                                           FALSE);
     128             : }
     129             : 
     130             : /************************************************************************/
     131             : /*                           importFromWkb()                            */
     132             : /************************************************************************/
     133             : 
     134        1956 : OGRErr OGRCompoundCurve::importFromWkb(const unsigned char *pabyData,
     135             :                                        size_t nSize, OGRwkbVariant eWkbVariant,
     136             :                                        size_t &nBytesConsumedOut)
     137             : {
     138        1956 :     OGRwkbByteOrder eByteOrder = wkbNDR;
     139        1956 :     size_t nDataOffset = 0;
     140             :     // coverity[tainted_data]
     141        1956 :     OGRErr eErr = oCC.importPreambleFromWkb(this, pabyData, nSize, nDataOffset,
     142             :                                             eByteOrder, 9, eWkbVariant);
     143        1956 :     if (eErr != OGRERR_NONE)
     144          56 :         return eErr;
     145             : 
     146        1900 :     eErr = oCC.importBodyFromWkb(this, pabyData + nDataOffset, nSize,
     147             :                                  false,  // bAcceptCompoundCurve
     148             :                                  addCurveDirectlyFromWkb, eWkbVariant,
     149             :                                  nBytesConsumedOut);
     150        1900 :     if (eErr == OGRERR_NONE)
     151        1720 :         nBytesConsumedOut += nDataOffset;
     152        1900 :     return eErr;
     153             : }
     154             : 
     155             : /************************************************************************/
     156             : /*                            exportToWkb()                             */
     157             : /************************************************************************/
     158             : 
     159         880 : OGRErr OGRCompoundCurve::exportToWkb(unsigned char *pabyData,
     160             :                                      const OGRwkbExportOptions *psOptions) const
     161             : {
     162             :     OGRwkbExportOptions sOptions(psOptions ? *psOptions
     163         880 :                                            : OGRwkbExportOptions());
     164             : 
     165             :     // Does not make sense for new geometries, so patch it.
     166         880 :     if (sOptions.eWkbVariant == wkbVariantOldOgc)
     167          14 :         sOptions.eWkbVariant = wkbVariantIso;
     168        1760 :     return oCC.exportToWkb(this, pabyData, &sOptions);
     169             : }
     170             : 
     171             : /************************************************************************/
     172             : /*                       addCurveDirectlyFromWkt()                      */
     173             : /************************************************************************/
     174             : 
     175         472 : OGRErr OGRCompoundCurve::addCurveDirectlyFromWkt(OGRGeometry *poSelf,
     176             :                                                  OGRCurve *poCurve)
     177             : {
     178         472 :     return poSelf->toCompoundCurve()->addCurveDirectly(poCurve);
     179             : }
     180             : 
     181             : /************************************************************************/
     182             : /*                           importFromWkt()                            */
     183             : /************************************************************************/
     184             : 
     185         299 : OGRErr OGRCompoundCurve::importFromWkt(const char **ppszInput)
     186             : {
     187         299 :     return importCurveCollectionFromWkt(ppszInput,
     188             :                                         FALSE,  // bAllowEmptyComponent
     189             :                                         TRUE,   // bAllowLineString
     190             :                                         TRUE,   // bAllowCurve
     191             :                                         FALSE,  // bAllowCompoundCurve
     192         299 :                                         addCurveDirectlyFromWkt);
     193             : }
     194             : 
     195             : /************************************************************************/
     196             : /*                            exportToWkt()                             */
     197             : /************************************************************************/
     198         104 : std::string OGRCompoundCurve::exportToWkt(const OGRWktOptions &opts,
     199             :                                           OGRErr *err) const
     200             : {
     201         104 :     return oCC.exportToWkt(this, opts, err);
     202             : }
     203             : 
     204             : /************************************************************************/
     205             : /*                               empty()                                */
     206             : /************************************************************************/
     207             : 
     208        2259 : void OGRCompoundCurve::empty()
     209             : {
     210        2259 :     oCC.empty(this);
     211        2259 : }
     212             : 
     213             : /************************************************************************/
     214             : /*                            getEnvelope()                             */
     215             : /************************************************************************/
     216             : 
     217          18 : void OGRCompoundCurve::getEnvelope(OGREnvelope *psEnvelope) const
     218             : {
     219          18 :     oCC.getEnvelope(psEnvelope);
     220          18 : }
     221             : 
     222             : /************************************************************************/
     223             : /*                            getEnvelope()                             */
     224             : /************************************************************************/
     225             : 
     226          40 : void OGRCompoundCurve::getEnvelope(OGREnvelope3D *psEnvelope) const
     227             : {
     228          40 :     oCC.getEnvelope(psEnvelope);
     229          40 : }
     230             : 
     231             : /************************************************************************/
     232             : /*                               IsEmpty()                              */
     233             : /************************************************************************/
     234             : 
     235         739 : OGRBoolean OGRCompoundCurve::IsEmpty() const
     236             : {
     237         739 :     return oCC.IsEmpty();
     238             : }
     239             : 
     240             : /************************************************************************/
     241             : /*                             get_Length()                             */
     242             : /*                                                                      */
     243             : /*      For now we return a simple euclidean 2D distance.               */
     244             : /************************************************************************/
     245             : 
     246           5 : double OGRCompoundCurve::get_Length() const
     247             : {
     248           5 :     double dfLength = 0.0;
     249           9 :     for (int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++)
     250           4 :         dfLength += oCC.papoCurves[iGeom]->get_Length();
     251           5 :     return dfLength;
     252             : }
     253             : 
     254             : /************************************************************************/
     255             : /*                             StartPoint()                             */
     256             : /************************************************************************/
     257             : 
     258         402 : void OGRCompoundCurve::StartPoint(OGRPoint *p) const
     259             : {
     260         402 :     CPLAssert(oCC.nCurveCount > 0);
     261         402 :     oCC.papoCurves[0]->StartPoint(p);
     262         402 : }
     263             : 
     264             : /************************************************************************/
     265             : /*                              EndPoint()                              */
     266             : /************************************************************************/
     267             : 
     268         392 : void OGRCompoundCurve::EndPoint(OGRPoint *p) const
     269             : {
     270         392 :     CPLAssert(oCC.nCurveCount > 0);
     271         392 :     oCC.papoCurves[oCC.nCurveCount - 1]->EndPoint(p);
     272         392 : }
     273             : 
     274             : /************************************************************************/
     275             : /*                               Value()                                */
     276             : /************************************************************************/
     277             : 
     278           5 : void OGRCompoundCurve::Value(double dfDistance, OGRPoint *poPoint) const
     279             : {
     280             : 
     281           5 :     if (dfDistance < 0)
     282             :     {
     283           1 :         StartPoint(poPoint);
     284           1 :         return;
     285             :     }
     286             : 
     287           4 :     double dfLength = 0.0;
     288           7 :     for (int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++)
     289             :     {
     290           6 :         const double dfSegLength = oCC.papoCurves[iGeom]->get_Length();
     291           6 :         if (dfSegLength > 0)
     292             :         {
     293           6 :             if ((dfLength <= dfDistance) &&
     294           6 :                 ((dfLength + dfSegLength) >= dfDistance))
     295             :             {
     296           3 :                 oCC.papoCurves[iGeom]->Value(dfDistance - dfLength, poPoint);
     297             : 
     298           3 :                 return;
     299             :             }
     300             : 
     301           3 :             dfLength += dfSegLength;
     302             :         }
     303             :     }
     304             : 
     305           1 :     EndPoint(poPoint);
     306             : }
     307             : 
     308             : /************************************************************************/
     309             : /*                         CurveToLineInternal()                        */
     310             : /************************************************************************/
     311             : 
     312             : OGRLineString *
     313         681 : OGRCompoundCurve::CurveToLineInternal(double dfMaxAngleStepSizeDegrees,
     314             :                                       const char *const *papszOptions,
     315             :                                       int bIsLinearRing) const
     316             : {
     317             :     OGRLineString *const poLine =
     318         681 :         bIsLinearRing ? new OGRLinearRing() : new OGRLineString();
     319         681 :     poLine->assignSpatialReference(getSpatialReference());
     320        2096 :     for (int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++)
     321             :     {
     322        2830 :         OGRLineString *poSubLS = oCC.papoCurves[iGeom]->CurveToLine(
     323        1415 :             dfMaxAngleStepSizeDegrees, papszOptions);
     324        1415 :         poLine->addSubLineString(poSubLS, (iGeom == 0) ? 0 : 1);
     325        1415 :         delete poSubLS;
     326             :     }
     327         681 :     return poLine;
     328             : }
     329             : 
     330             : /************************************************************************/
     331             : /*                          CurveToLine()                               */
     332             : /************************************************************************/
     333             : 
     334             : OGRLineString *
     335         667 : OGRCompoundCurve::CurveToLine(double dfMaxAngleStepSizeDegrees,
     336             :                               const char *const *papszOptions) const
     337             : {
     338         667 :     return CurveToLineInternal(dfMaxAngleStepSizeDegrees, papszOptions, FALSE);
     339             : }
     340             : 
     341             : /************************************************************************/
     342             : /*                               Equals()                                */
     343             : /************************************************************************/
     344             : 
     345         882 : OGRBoolean OGRCompoundCurve::Equals(const OGRGeometry *poOther) const
     346             : {
     347         882 :     if (poOther == this)
     348           1 :         return TRUE;
     349             : 
     350         881 :     if (poOther->getGeometryType() != getGeometryType())
     351           1 :         return FALSE;
     352             : 
     353         880 :     return oCC.Equals(&(poOther->toCompoundCurve()->oCC));
     354             : }
     355             : 
     356             : /************************************************************************/
     357             : /*                       setCoordinateDimension()                       */
     358             : /************************************************************************/
     359             : 
     360        2265 : bool OGRCompoundCurve::setCoordinateDimension(int nNewDimension)
     361             : {
     362        2265 :     return oCC.setCoordinateDimension(this, nNewDimension);
     363             : }
     364             : 
     365        4097 : bool OGRCompoundCurve::set3D(OGRBoolean bIs3D)
     366             : {
     367        4097 :     return oCC.set3D(this, bIs3D);
     368             : }
     369             : 
     370        6259 : bool OGRCompoundCurve::setMeasured(OGRBoolean bIsMeasured)
     371             : {
     372        6259 :     return oCC.setMeasured(this, bIsMeasured);
     373             : }
     374             : 
     375             : /************************************************************************/
     376             : /*                       assignSpatialReference()                       */
     377             : /************************************************************************/
     378             : 
     379        2455 : void OGRCompoundCurve::assignSpatialReference(const OGRSpatialReference *poSR)
     380             : {
     381        2455 :     oCC.assignSpatialReference(this, poSR);
     382        2455 : }
     383             : 
     384             : /************************************************************************/
     385             : /*                          getNumCurves()                              */
     386             : /************************************************************************/
     387             : 
     388             : /**
     389             :  * \brief Return the number of curves.
     390             :  *
     391             :  * Note that the number of curves making this compound curve.
     392             :  *
     393             :  * Relates to the ISO SQL/MM ST_NumCurves() function.
     394             :  *
     395             :  * @return number of curves.
     396             :  */
     397             : 
     398         989 : int OGRCompoundCurve::getNumCurves() const
     399             : {
     400         989 :     return oCC.nCurveCount;
     401             : }
     402             : 
     403             : /************************************************************************/
     404             : /*                           getCurve()                                 */
     405             : /************************************************************************/
     406             : 
     407             : /**
     408             :  * \brief Fetch reference to indicated internal ring.
     409             :  *
     410             :  * Note that the returned curve pointer is to an internal data object of the
     411             :  * OGRCompoundCurve.  It should not be modified or deleted by the application,
     412             :  * and the pointer is only valid till the polygon is next modified.  Use the
     413             :  * OGRGeometry::clone() method to make a separate copy within the application.
     414             :  *
     415             :  * Relates to the ISO SQL/MM ST_CurveN() function.
     416             :  *
     417             :  * @param iRing curve index from 0 to getNumCurves() - 1.
     418             :  *
     419             :  * @return pointer to curve.  May be NULL.
     420             :  */
     421             : 
     422         245 : OGRCurve *OGRCompoundCurve::getCurve(int iRing)
     423             : {
     424         245 :     return oCC.getCurve(iRing);
     425             : }
     426             : 
     427             : /************************************************************************/
     428             : /*                           getCurve()                                 */
     429             : /************************************************************************/
     430             : 
     431             : /**
     432             :  * \brief Fetch reference to indicated internal ring.
     433             :  *
     434             :  * Note that the returned curve pointer is to an internal data object of the
     435             :  * OGRCompoundCurve.  It should not be modified or deleted by the application,
     436             :  * and the pointer is only valid till the polygon is next modified.  Use the
     437             :  * OGRGeometry::clone() method to make a separate copy within the application.
     438             :  *
     439             :  * Relates to the ISO SQL/MM ST_CurveN() function.
     440             :  *
     441             :  * @param iCurve curve index from 0 to getNumCurves() - 1.
     442             :  *
     443             :  * @return pointer to curve.  May be NULL.
     444             :  */
     445             : 
     446         229 : const OGRCurve *OGRCompoundCurve::getCurve(int iCurve) const
     447             : {
     448         229 :     return oCC.getCurve(iCurve);
     449             : }
     450             : 
     451             : /************************************************************************/
     452             : /*                           stealCurve()                               */
     453             : /************************************************************************/
     454             : 
     455             : /**
     456             :  * \brief "Steal" reference to curve.
     457             :  *
     458             :  * @param iCurve curve index from 0 to getNumCurves() - 1.
     459             :  *
     460             :  * @return pointer to curve.  May be NULL.
     461             :  */
     462             : 
     463           5 : OGRCurve *OGRCompoundCurve::stealCurve(int iCurve)
     464             : {
     465           5 :     return oCC.stealCurve(iCurve);
     466             : }
     467             : 
     468             : /************************************************************************/
     469             : /*                            addCurve()                                */
     470             : /************************************************************************/
     471             : 
     472             : /**
     473             :  * \brief Add a curve to the container.
     474             :  *
     475             :  * The passed geometry is cloned to make an internal copy.
     476             :  *
     477             :  * There is no ISO SQL/MM analog to this method.
     478             :  *
     479             :  * This method is the same as the C function OGR_G_AddGeometry().
     480             :  *
     481             :  * @param poCurve geometry to add to the container.
     482             :  * @param dfToleranceEps relative tolerance when checking that the first point
     483             :  * of a segment matches then end point of the previous one. Default value:
     484             :  * OGRCompoundCurve::DEFAULT_TOLERANCE_EPSILON.
     485             :  *
     486             :  * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
     487             :  * (for example if curves are not contiguous)
     488             :  */
     489             : 
     490          23 : OGRErr OGRCompoundCurve::addCurve(const OGRCurve *poCurve,
     491             :                                   double dfToleranceEps)
     492             : {
     493          23 :     OGRCurve *poClonedCurve = poCurve->clone();
     494          23 :     const OGRErr eErr = addCurveDirectly(poClonedCurve, dfToleranceEps);
     495          23 :     if (eErr != OGRERR_NONE)
     496           0 :         delete poClonedCurve;
     497          23 :     return eErr;
     498             : }
     499             : 
     500             : /************************************************************************/
     501             : /*                          addCurveDirectly()                          */
     502             : /************************************************************************/
     503             : 
     504             : /**
     505             :  * \brief Add a curve directly to the container.
     506             :  *
     507             :  * Ownership of the passed geometry is taken by the container rather than
     508             :  * cloning as addCurve() does, but only if the method is successful.
     509             :  * If the method fails, ownership still belongs to the caller.
     510             :  *
     511             :  * There is no ISO SQL/MM analog to this method.
     512             :  *
     513             :  * This method is the same as the C function OGR_G_AddGeometryDirectly().
     514             :  *
     515             :  * @param poCurve geometry to add to the container.
     516             :  * @param dfToleranceEps relative tolerance when checking that the first point
     517             :  * of a segment matches then end point of the previous one. Default value:
     518             :  * OGRCompoundCurve::DEFAULT_TOLERANCE_EPSILON.
     519             :  *
     520             :  * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
     521             :  * (for example if curves are not contiguous)
     522             :  */
     523        1124 : OGRErr OGRCompoundCurve::addCurveDirectly(OGRCurve *poCurve,
     524             :                                           double dfToleranceEps)
     525             : {
     526        1124 :     return addCurveDirectlyInternal(poCurve, dfToleranceEps, TRUE);
     527             : }
     528             : 
     529        2940 : OGRErr OGRCompoundCurve::addCurveDirectlyInternal(OGRCurve *poCurve,
     530             :                                                   double dfToleranceEps,
     531             :                                                   int bNeedRealloc)
     532             : {
     533        2940 :     if (poCurve->getNumPoints() == 1)
     534             :     {
     535           5 :         CPLError(CE_Failure, CPLE_AppDefined,
     536             :                  "Invalid curve: not enough points");
     537           5 :         return OGRERR_FAILURE;
     538             :     }
     539             : 
     540             :     const OGRwkbGeometryType eCurveType =
     541        2935 :         wkbFlatten(poCurve->getGeometryType());
     542        2935 :     if (EQUAL(poCurve->getGeometryName(), "LINEARRING"))
     543             :     {
     544           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Linearring not allowed.");
     545           0 :         return OGRERR_FAILURE;
     546             :     }
     547        2935 :     else if (eCurveType == wkbCompoundCurve)
     548             :     {
     549           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     550             :                  "Cannot add a compound curve inside a compound curve");
     551           1 :         return OGRERR_FAILURE;
     552             :     }
     553             : 
     554        2934 :     if (oCC.nCurveCount > 0)
     555             :     {
     556         982 :         if (oCC.papoCurves[oCC.nCurveCount - 1]->IsEmpty() ||
     557         491 :             poCurve->IsEmpty())
     558             :         {
     559           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves");
     560           3 :             return OGRERR_FAILURE;
     561             :         }
     562             : 
     563         491 :         OGRPoint oEnd;
     564         491 :         OGRPoint start;
     565         491 :         oCC.papoCurves[oCC.nCurveCount - 1]->EndPoint(&oEnd);
     566         491 :         poCurve->StartPoint(&start);
     567         491 :         if (fabs(oEnd.getX() - start.getX()) >
     568         491 :                 dfToleranceEps * fabs(start.getX()) ||
     569         485 :             fabs(oEnd.getY() - start.getY()) >
     570        1460 :                 dfToleranceEps * fabs(start.getY()) ||
     571         484 :             fabs(oEnd.getZ() - start.getZ()) >
     572         484 :                 dfToleranceEps * fabs(start.getZ()))
     573             :         {
     574           7 :             poCurve->EndPoint(&start);
     575           7 :             if (fabs(oEnd.getX() - start.getX()) >
     576           7 :                     dfToleranceEps * fabs(start.getX()) ||
     577           4 :                 fabs(oEnd.getY() - start.getY()) >
     578          15 :                     dfToleranceEps * fabs(start.getY()) ||
     579           4 :                 fabs(oEnd.getZ() - start.getZ()) >
     580           4 :                     dfToleranceEps * fabs(start.getZ()))
     581             :             {
     582           3 :                 CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves");
     583           3 :                 return OGRERR_FAILURE;
     584             :             }
     585             : 
     586           4 :             CPLDebug("GML", "reversing curve");
     587           4 :             poCurve->toSimpleCurve()->reversePoints();
     588             :         }
     589             :         // Patch so that it matches exactly.
     590         488 :         poCurve->toSimpleCurve()->setPoint(0, &oEnd);
     591             :     }
     592             : 
     593        2931 :     return oCC.addCurveDirectly(this, poCurve, bNeedRealloc);
     594             : }
     595             : 
     596             : /************************************************************************/
     597             : /*                          addCurve()                                  */
     598             : /************************************************************************/
     599             : 
     600             : /**
     601             :  * \brief Add a curve directly to the container.
     602             :  *
     603             :  * There is no ISO SQL/MM analog to this method.
     604             :  *
     605             :  * This method is the same as the C function OGR_G_AddGeometryDirectly().
     606             :  *
     607             :  * @param poCurve geometry to add to the container.
     608             :  * @param dfToleranceEps relative tolerance when checking that the first point
     609             :  * of a segment matches then end point of the previous one. Default value:
     610             :  * OGRCompoundCurve::DEFAULT_TOLERANCE_EPSILON.
     611             :  *
     612             :  * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
     613             :  * (for example if curves are not contiguous)
     614             :  */
     615          91 : OGRErr OGRCompoundCurve::addCurve(std::unique_ptr<OGRCurve> poCurve,
     616             :                                   double dfToleranceEps)
     617             : {
     618          91 :     OGRCurve *poCurvePtr = poCurve.release();
     619          91 :     OGRErr eErr = addCurveDirectlyInternal(poCurvePtr, dfToleranceEps, TRUE);
     620          91 :     if (eErr != OGRERR_NONE)
     621           1 :         delete poCurvePtr;
     622          91 :     return eErr;
     623             : }
     624             : 
     625             : /************************************************************************/
     626             : /*                             transform()                              */
     627             : /************************************************************************/
     628             : 
     629           3 : OGRErr OGRCompoundCurve::transform(OGRCoordinateTransformation *poCT)
     630             : {
     631           3 :     return oCC.transform(this, poCT);
     632             : }
     633             : 
     634             : /************************************************************************/
     635             : /*                            flattenTo2D()                             */
     636             : /************************************************************************/
     637             : 
     638           2 : void OGRCompoundCurve::flattenTo2D()
     639             : {
     640           2 :     oCC.flattenTo2D(this);
     641           2 : }
     642             : 
     643             : /************************************************************************/
     644             : /*                              segmentize()                            */
     645             : /************************************************************************/
     646             : 
     647           1 : bool OGRCompoundCurve::segmentize(double dfMaxLength)
     648             : {
     649           1 :     return oCC.segmentize(dfMaxLength);
     650             : }
     651             : 
     652             : /************************************************************************/
     653             : /*                               swapXY()                               */
     654             : /************************************************************************/
     655             : 
     656           1 : void OGRCompoundCurve::swapXY()
     657             : {
     658           1 :     oCC.swapXY();
     659           1 : }
     660             : 
     661             : /************************************************************************/
     662             : /*                         hasCurveGeometry()                           */
     663             : /************************************************************************/
     664             : 
     665        2200 : OGRBoolean OGRCompoundCurve::hasCurveGeometry(int bLookForNonLinear) const
     666             : {
     667        2200 :     if (bLookForNonLinear)
     668             :     {
     669          37 :         return oCC.hasCurveGeometry(bLookForNonLinear);
     670             :     }
     671             : 
     672        2163 :     return TRUE;
     673             : }
     674             : 
     675             : /************************************************************************/
     676             : /*                         getLinearGeometry()                        */
     677             : /************************************************************************/
     678             : 
     679             : OGRGeometry *
     680         309 : OGRCompoundCurve::getLinearGeometry(double dfMaxAngleStepSizeDegrees,
     681             :                                     const char *const *papszOptions) const
     682             : {
     683         309 :     return CurveToLine(dfMaxAngleStepSizeDegrees, papszOptions);
     684             : }
     685             : 
     686             : /************************************************************************/
     687             : /*                           getNumPoints()                             */
     688             : /************************************************************************/
     689             : 
     690         236 : int OGRCompoundCurve::getNumPoints() const
     691             : {
     692         236 :     int nPoints = 0;
     693         699 :     for (int i = 0; i < oCC.nCurveCount; i++)
     694             :     {
     695         463 :         nPoints += oCC.papoCurves[i]->getNumPoints();
     696         463 :         if (i != 0)
     697         234 :             nPoints--;
     698             :     }
     699         236 :     return nPoints;
     700             : }
     701             : 
     702             : /************************************************************************/
     703             : /*                      OGRCompoundCurvePointIterator                   */
     704             : /************************************************************************/
     705             : 
     706             : class OGRCompoundCurvePointIterator final : public OGRPointIterator
     707             : {
     708             :     CPL_DISALLOW_COPY_ASSIGN(OGRCompoundCurvePointIterator)
     709             : 
     710             :     const OGRCompoundCurve *poCC = nullptr;
     711             :     int iCurCurve = 0;
     712             :     OGRPointIterator *poCurveIter = nullptr;
     713             : 
     714             :   public:
     715          87 :     explicit OGRCompoundCurvePointIterator(const OGRCompoundCurve *poCCIn)
     716          87 :         : poCC(poCCIn)
     717             :     {
     718          87 :     }
     719             : 
     720         174 :     ~OGRCompoundCurvePointIterator() override
     721          87 :     {
     722          87 :         delete poCurveIter;
     723         174 :     }
     724             : 
     725             :     OGRBoolean getNextPoint(OGRPoint *p) override;
     726             : };
     727             : 
     728             : /************************************************************************/
     729             : /*                            getNextPoint()                            */
     730             : /************************************************************************/
     731             : 
     732         513 : OGRBoolean OGRCompoundCurvePointIterator::getNextPoint(OGRPoint *p)
     733             : {
     734         513 :     if (iCurCurve == poCC->getNumCurves())
     735           0 :         return FALSE;
     736         513 :     if (poCurveIter == nullptr)
     737          87 :         poCurveIter = poCC->getCurve(0)->getPointIterator();
     738         513 :     if (!poCurveIter->getNextPoint(p))
     739             :     {
     740         126 :         iCurCurve++;
     741         126 :         if (iCurCurve == poCC->getNumCurves())
     742          56 :             return FALSE;
     743          70 :         delete poCurveIter;
     744          70 :         poCurveIter = poCC->getCurve(iCurCurve)->getPointIterator();
     745             :         // Skip first point.
     746          70 :         return poCurveIter->getNextPoint(p) && poCurveIter->getNextPoint(p);
     747             :     }
     748         387 :     return TRUE;
     749             : }
     750             : 
     751             : /************************************************************************/
     752             : /*                         getPointIterator()                           */
     753             : /************************************************************************/
     754             : 
     755          87 : OGRPointIterator *OGRCompoundCurve::getPointIterator() const
     756             : {
     757          87 :     return new OGRCompoundCurvePointIterator(this);
     758             : }
     759             : 
     760             : /************************************************************************/
     761             : /*                         CastToLineString()                        */
     762             : /************************************************************************/
     763             : 
     764             : //! @cond Doxygen_Suppress
     765           9 : OGRLineString *OGRCompoundCurve::CastToLineString(OGRCompoundCurve *poCC)
     766             : {
     767          30 :     for (int i = 0; i < poCC->oCC.nCurveCount; i++)
     768             :     {
     769          42 :         poCC->oCC.papoCurves[i] =
     770          21 :             OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]);
     771          21 :         if (poCC->oCC.papoCurves[i] == nullptr)
     772             :         {
     773           0 :             delete poCC;
     774           0 :             return nullptr;
     775             :         }
     776             :     }
     777             : 
     778           9 :     if (poCC->oCC.nCurveCount == 1)
     779             :     {
     780           2 :         OGRLineString *poLS = poCC->oCC.papoCurves[0]->toLineString();
     781           2 :         poLS->assignSpatialReference(poCC->getSpatialReference());
     782           2 :         poCC->oCC.papoCurves[0] = nullptr;
     783           2 :         delete poCC;
     784           2 :         return poLS;
     785             :     }
     786             : 
     787           7 :     OGRLineString *poLS = poCC->CurveToLineInternal(0, nullptr, FALSE);
     788           7 :     delete poCC;
     789           7 :     return poLS;
     790             : }
     791             : 
     792             : /************************************************************************/
     793             : /*                           CastToLinearRing()                         */
     794             : /************************************************************************/
     795             : 
     796             : /**
     797             :  * \brief Cast to linear ring.
     798             :  *
     799             :  * The passed in geometry is consumed and a new one returned (or NULL in case
     800             :  * of failure)
     801             :  *
     802             :  * @param poCC the input geometry - ownership is passed to the method.
     803             :  * @return new geometry.
     804             :  */
     805             : 
     806          21 : OGRLinearRing *OGRCompoundCurve::CastToLinearRing(OGRCompoundCurve *poCC)
     807             : {
     808          66 :     for (int i = 0; i < poCC->oCC.nCurveCount; i++)
     809             :     {
     810          90 :         poCC->oCC.papoCurves[i] =
     811          45 :             OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]);
     812          45 :         if (poCC->oCC.papoCurves[i] == nullptr)
     813             :         {
     814           0 :             delete poCC;
     815           0 :             return nullptr;
     816             :         }
     817             :     }
     818             : 
     819          21 :     if (poCC->oCC.nCurveCount == 1)
     820             :     {
     821             :         OGRLinearRing *poLR =
     822          14 :             OGRCurve::CastToLinearRing(poCC->oCC.papoCurves[0]);
     823          14 :         if (poLR != nullptr)
     824             :         {
     825          14 :             poLR->assignSpatialReference(poCC->getSpatialReference());
     826             :         }
     827          14 :         poCC->oCC.papoCurves[0] = nullptr;
     828          14 :         delete poCC;
     829          14 :         return poLR;
     830             :     }
     831             : 
     832             :     OGRLinearRing *poLR =
     833           7 :         poCC->CurveToLineInternal(0, nullptr, TRUE)->toLinearRing();
     834           7 :     delete poCC;
     835           7 :     return poLR;
     836             : }
     837             : 
     838             : /************************************************************************/
     839             : /*                     GetCasterToLineString()                          */
     840             : /************************************************************************/
     841             : 
     842           9 : OGRLineString *OGRCompoundCurve::CasterToLineString(OGRCurve *poCurve)
     843             : {
     844           9 :     OGRCompoundCurve *poCC = poCurve->toCompoundCurve();
     845           9 :     return OGRCompoundCurve::CastToLineString(poCC);
     846             : }
     847             : 
     848           9 : OGRCurveCasterToLineString OGRCompoundCurve::GetCasterToLineString() const
     849             : {
     850           9 :     return OGRCompoundCurve::CasterToLineString;
     851             : }
     852             : 
     853             : /************************************************************************/
     854             : /*                        GetCasterToLinearRing()                       */
     855             : /************************************************************************/
     856             : 
     857          21 : OGRLinearRing *OGRCompoundCurve::CasterToLinearRing(OGRCurve *poCurve)
     858             : {
     859          21 :     OGRCompoundCurve *poCC = poCurve->toCompoundCurve();
     860          21 :     return OGRCompoundCurve::CastToLinearRing(poCC);
     861             : }
     862             : 
     863          21 : OGRCurveCasterToLinearRing OGRCompoundCurve::GetCasterToLinearRing() const
     864             : {
     865          21 :     return OGRCompoundCurve::CasterToLinearRing;
     866             : }
     867             : 
     868             : //! @endcond
     869             : 
     870             : /************************************************************************/
     871             : /*                           get_Area()                                 */
     872             : /************************************************************************/
     873             : 
     874          41 : double OGRCompoundCurve::get_Area() const
     875             : {
     876          41 :     if (IsEmpty() || !get_IsClosed())
     877           0 :         return 0;
     878             : 
     879             :     // Optimization for convex rings.
     880          41 :     if (IsConvex())
     881             :     {
     882             :         // Compute area of shape without the circular segments.
     883          27 :         OGRPointIterator *poIter = getPointIterator();
     884          54 :         OGRLineString oLS;
     885          27 :         oLS.setNumPoints(getNumPoints());
     886          27 :         OGRPoint p;
     887         192 :         for (int i = 0; poIter->getNextPoint(&p); i++)
     888             :         {
     889         165 :             oLS.setPoint(i, p.getX(), p.getY());
     890             :         }
     891          27 :         double dfArea = oLS.get_Area();
     892          27 :         delete poIter;
     893             : 
     894             :         // Add the area of the spherical segments.
     895          27 :         dfArea += get_AreaOfCurveSegments();
     896             : 
     897          27 :         return dfArea;
     898             :     }
     899             : 
     900          14 :     OGRLineString *poLS = CurveToLine();
     901          14 :     double dfArea = poLS->get_Area();
     902          14 :     delete poLS;
     903             : 
     904          14 :     return dfArea;
     905             : }
     906             : 
     907             : /************************************************************************/
     908             : /*                        get_GeodesicArea()                            */
     909             : /************************************************************************/
     910             : 
     911           3 : double OGRCompoundCurve::get_GeodesicArea(
     912             :     const OGRSpatialReference *poSRSOverride) const
     913             : {
     914           3 :     if (IsEmpty())
     915           1 :         return 0;
     916             : 
     917           2 :     if (!get_IsClosed())
     918             :     {
     919           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Non-closed geometry");
     920           1 :         return -1;
     921             :     }
     922             : 
     923           1 :     if (!poSRSOverride)
     924           1 :         poSRSOverride = getSpatialReference();
     925             : 
     926           2 :     auto poLS = std::unique_ptr<OGRLineString>(CurveToLine());
     927           1 :     return poLS->get_GeodesicArea(poSRSOverride);
     928             : }
     929             : 
     930             : /************************************************************************/
     931             : /*                        get_GeodesicLength()                          */
     932             : /************************************************************************/
     933             : 
     934           2 : double OGRCompoundCurve::get_GeodesicLength(
     935             :     const OGRSpatialReference *poSRSOverride) const
     936             : {
     937           2 :     if (IsEmpty())
     938           1 :         return 0;
     939             : 
     940           1 :     if (!poSRSOverride)
     941           1 :         poSRSOverride = getSpatialReference();
     942             : 
     943           2 :     auto poLS = std::unique_ptr<OGRLineString>(CurveToLine());
     944           1 :     return poLS->get_GeodesicLength(poSRSOverride);
     945             : }
     946             : 
     947             : /************************************************************************/
     948             : /*                       get_AreaOfCurveSegments()                      */
     949             : /************************************************************************/
     950             : 
     951             : /** Return area of curve segments
     952             :  * @return area.
     953             :  */
     954          27 : double OGRCompoundCurve::get_AreaOfCurveSegments() const
     955             : {
     956          27 :     double dfArea = 0;
     957          82 :     for (int i = 0; i < getNumCurves(); i++)
     958             :     {
     959          55 :         const OGRCurve *poPart = getCurve(i);
     960          55 :         dfArea += poPart->get_AreaOfCurveSegments();
     961             :     }
     962          27 :     return dfArea;
     963             : }
     964             : 
     965             : /************************************************************************/
     966             : /*                           hasEmptyParts()                            */
     967             : /************************************************************************/
     968             : 
     969           3 : bool OGRCompoundCurve::hasEmptyParts() const
     970             : {
     971           3 :     return oCC.hasEmptyParts();
     972             : }
     973             : 
     974             : /************************************************************************/
     975             : /*                          removeEmptyParts()                          */
     976             : /************************************************************************/
     977             : 
     978           2 : void OGRCompoundCurve::removeEmptyParts()
     979             : {
     980           2 :     oCC.removeEmptyParts();
     981           2 : }
     982             : 
     983             : /************************************************************************/
     984             : /*                           reversePoints()                            */
     985             : /************************************************************************/
     986             : 
     987             : /**
     988             :  * \brief Reverse point order.
     989             :  *
     990             :  * This method updates the points in this curve in place
     991             :  * reversing the point ordering (first for last, etc) and component ordering.
     992             :  *
     993             :  * @since 3.10
     994             :  */
     995           1 : void OGRCompoundCurve::reversePoints()
     996             : 
     997             : {
     998           1 :     oCC.reversePoints();
     999           1 : }

Generated by: LCOV version 1.14