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

Generated by: LCOV version 1.14