LCOV - code coverage report
Current view: top level - ogr - ogrcurvecollection.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 274 308 89.0 %
Date: 2025-11-07 02:20:00 Functions: 33 33 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  The OGRCurveCollection 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 <cstddef>
      17             : #include <cstring>
      18             : #include <limits>
      19             : #include <new>
      20             : 
      21             : #include "ogr_core.h"
      22             : #include "ogr_p.h"
      23             : #include "ogr_spatialref.h"
      24             : #include "cpl_conv.h"
      25             : #include "cpl_error.h"
      26             : #include "cpl_string.h"
      27             : #include "cpl_vsi.h"
      28             : 
      29             : //! @cond Doxygen_Suppress
      30             : 
      31             : /************************************************************************/
      32             : /*             OGRCurveCollection( const OGRCurveCollection& )          */
      33             : /************************************************************************/
      34             : 
      35             : /**
      36             :  * \brief Copy constructor.
      37             :  */
      38             : 
      39     1585540 : OGRCurveCollection::OGRCurveCollection(const OGRCurveCollection &other)
      40             : {
      41     1585540 :     if (other.nCurveCount > 0)
      42             :     {
      43     1585260 :         nCurveCount = other.nCurveCount;
      44     1585260 :         papoCurves = static_cast<OGRCurve **>(
      45     1585260 :             VSI_CALLOC_VERBOSE(sizeof(void *), nCurveCount));
      46             : 
      47     1585260 :         if (papoCurves)
      48             :         {
      49     3171990 :             for (int i = 0; i < nCurveCount; i++)
      50             :             {
      51     1586730 :                 papoCurves[i] = other.papoCurves[i]->clone();
      52             :             }
      53             :         }
      54             :     }
      55     1585540 : }
      56             : 
      57             : /************************************************************************/
      58             : /*             OGRCurveCollection( OGRCurveCollection&& )               */
      59             : /************************************************************************/
      60             : 
      61             : /**
      62             :  * \brief Move constructor.
      63             :  *
      64             :  * @since GDAL 3.11
      65             :  */
      66             : 
      67           4 : OGRCurveCollection::OGRCurveCollection(OGRCurveCollection &&other)
      68           4 :     : nCurveCount(other.nCurveCount), papoCurves(other.papoCurves)
      69             : {
      70           4 :     other.nCurveCount = 0;
      71           4 :     other.papoCurves = nullptr;
      72           4 : }
      73             : 
      74             : /************************************************************************/
      75             : /*                         ~OGRCurveCollection()                        */
      76             : /************************************************************************/
      77             : 
      78     6276650 : OGRCurveCollection::~OGRCurveCollection()
      79             : 
      80             : {
      81     3138320 :     empty(nullptr);
      82     3138330 : }
      83             : 
      84             : /************************************************************************/
      85             : /*                 operator=( const OGRCurveCollection& )               */
      86             : /************************************************************************/
      87             : 
      88             : /**
      89             :  * \brief Assignment operator.
      90             :  */
      91             : 
      92             : OGRCurveCollection &
      93          16 : OGRCurveCollection::operator=(const OGRCurveCollection &other)
      94             : {
      95          16 :     if (this != &other)
      96             :     {
      97          16 :         empty(nullptr);
      98             : 
      99          16 :         if (other.nCurveCount > 0)
     100             :         {
     101           8 :             nCurveCount = other.nCurveCount;
     102           8 :             papoCurves = static_cast<OGRCurve **>(
     103           8 :                 VSI_MALLOC2_VERBOSE(sizeof(void *), nCurveCount));
     104             : 
     105           8 :             if (papoCurves)
     106             :             {
     107          22 :                 for (int i = 0; i < nCurveCount; i++)
     108             :                 {
     109          14 :                     papoCurves[i] = other.papoCurves[i]->clone();
     110             :                 }
     111             :             }
     112             :         }
     113             :     }
     114          16 :     return *this;
     115             : }
     116             : 
     117             : /************************************************************************/
     118             : /*                    operator=( OGRCurveCollection&& )                 */
     119             : /************************************************************************/
     120             : 
     121             : /**
     122             :  * \brief Move assignment operator.
     123             :  *
     124             :  * @since GDAL 3.11
     125             :  */
     126             : 
     127           8 : OGRCurveCollection &OGRCurveCollection::operator=(OGRCurveCollection &&other)
     128             : {
     129           8 :     if (this != &other)
     130             :     {
     131           8 :         empty(nullptr);
     132           8 :         std::swap(nCurveCount, other.nCurveCount);
     133           8 :         std::swap(papoCurves, other.papoCurves);
     134             :     }
     135           8 :     return *this;
     136             : }
     137             : 
     138             : /************************************************************************/
     139             : /*                              WkbSize()                               */
     140             : /************************************************************************/
     141             : 
     142        1868 : size_t OGRCurveCollection::WkbSize() const
     143             : {
     144        1868 :     size_t nSize = 9;
     145             : 
     146        4098 :     for (auto &&poSubGeom : *this)
     147             :     {
     148        2230 :         nSize += poSubGeom->WkbSize();
     149             :     }
     150             : 
     151        1868 :     return nSize;
     152             : }
     153             : 
     154             : /************************************************************************/
     155             : /*                          addCurveDirectly()                          */
     156             : /************************************************************************/
     157             : 
     158     1492780 : OGRErr OGRCurveCollection::addCurveDirectly(OGRGeometry *poGeom,
     159             :                                             OGRCurve *poCurve, int bNeedRealloc)
     160             : {
     161     1492780 :     poGeom->HomogenizeDimensionalityWith(poCurve);
     162             : 
     163     1492790 :     if (bNeedRealloc)
     164             :     {
     165             : #if SIZEOF_VOIDP < 8
     166             :         if (nCurveCount == std::numeric_limits<int>::max() /
     167             :                                static_cast<int>(sizeof(OGRCurve *)))
     168             :         {
     169             :             CPLError(CE_Failure, CPLE_OutOfMemory, "Too many subgeometries");
     170             :             return OGRERR_FAILURE;
     171             :         }
     172             : #else
     173     1491040 :         if (nCurveCount == std::numeric_limits<int>::max())
     174             :         {
     175           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Too many subgeometries");
     176           0 :             return OGRERR_FAILURE;
     177             :         }
     178             : #endif
     179             : 
     180     1491040 :         OGRCurve **papoNewCurves = static_cast<OGRCurve **>(VSI_REALLOC_VERBOSE(
     181             :             papoCurves, sizeof(OGRCurve *) * (nCurveCount + 1)));
     182     1491040 :         if (papoNewCurves == nullptr)
     183           0 :             return OGRERR_FAILURE;
     184     1491040 :         papoCurves = papoNewCurves;
     185             :     }
     186             : 
     187     1492790 :     papoCurves[nCurveCount] = poCurve;
     188             : 
     189     1492790 :     nCurveCount++;
     190             : 
     191     1492790 :     return OGRERR_NONE;
     192             : }
     193             : 
     194             : /************************************************************************/
     195             : /*                        importPreambleFromWkb()                      */
     196             : /************************************************************************/
     197             : 
     198       45411 : OGRErr OGRCurveCollection::importPreambleFromWkb(
     199             :     OGRGeometry *poGeom, const unsigned char *pabyData, size_t &nSize,
     200             :     size_t &nDataOffset, OGRwkbByteOrder &eByteOrder, size_t nMinSubGeomSize,
     201             :     OGRwkbVariant eWkbVariant)
     202             : {
     203       45411 :     int nCurveCountNew = 0;
     204             : 
     205       45411 :     OGRErr eErr = poGeom->importPreambleOfCollectionFromWkb(
     206             :         pabyData, nSize, nDataOffset, eByteOrder, nMinSubGeomSize,
     207             :         nCurveCountNew, eWkbVariant);
     208       45410 :     if (eErr != OGRERR_NONE)
     209         391 :         return eErr;
     210             : 
     211       45019 :     CPLAssert(nCurveCount == 0);
     212       45019 :     nCurveCount = nCurveCountNew;
     213             : 
     214             :     // coverity[tainted_data]
     215       45019 :     papoCurves = static_cast<OGRCurve **>(
     216       45019 :         VSI_CALLOC_VERBOSE(sizeof(void *), nCurveCount));
     217       45019 :     if (nCurveCount != 0 && papoCurves == nullptr)
     218             :     {
     219           0 :         nCurveCount = 0;
     220           0 :         return OGRERR_NOT_ENOUGH_MEMORY;
     221             :     }
     222             : 
     223       45019 :     return OGRERR_NONE;
     224             : }
     225             : 
     226             : /************************************************************************/
     227             : /*                       importBodyFromWkb()                            */
     228             : /************************************************************************/
     229             : 
     230        1924 : OGRErr OGRCurveCollection::importBodyFromWkb(
     231             :     OGRGeometry *poGeom, const unsigned char *pabyData, size_t nSize,
     232             :     bool bAcceptCompoundCurve,
     233             :     OGRErr (*pfnAddCurveDirectlyFromWkb)(OGRGeometry *poGeom,
     234             :                                          OGRCurve *poCurve),
     235             :     OGRwkbVariant eWkbVariant, size_t &nBytesConsumedOut)
     236             : {
     237        1924 :     nBytesConsumedOut = 0;
     238             :     /* -------------------------------------------------------------------- */
     239             :     /*      Get the Geoms.                                                  */
     240             :     /* -------------------------------------------------------------------- */
     241        1924 :     const int nIter = nCurveCount;
     242        1924 :     nCurveCount = 0;
     243        1924 :     size_t nDataOffset = 0;
     244        3669 :     for (int iGeom = 0; iGeom < nIter; iGeom++)
     245             :     {
     246        1925 :         OGRGeometry *poSubGeom = nullptr;
     247             : 
     248             :         // Parses sub-geometry.
     249        1925 :         const unsigned char *pabySubData = pabyData + nDataOffset;
     250        1925 :         if (nSize < 9 && nSize != static_cast<size_t>(-1))
     251         180 :             return OGRERR_NOT_ENOUGH_DATA;
     252             : 
     253        1923 :         OGRwkbGeometryType eFlattenSubGeomType = wkbUnknown;
     254        1923 :         if (OGRReadWKBGeometryType(pabySubData, eWkbVariant,
     255        1923 :                                    &eFlattenSubGeomType) != OGRERR_NONE)
     256          63 :             return OGRERR_FAILURE;
     257        1860 :         eFlattenSubGeomType = wkbFlatten(eFlattenSubGeomType);
     258             : 
     259        1860 :         OGRErr eErr = OGRERR_NONE;
     260        1860 :         size_t nSubGeomBytesConsumedOut = 0;
     261        5576 :         if ((eFlattenSubGeomType != wkbCompoundCurve &&
     262        1863 :              OGR_GT_IsCurve(eFlattenSubGeomType)) ||
     263           3 :             (bAcceptCompoundCurve && eFlattenSubGeomType == wkbCompoundCurve))
     264             :         {
     265        1858 :             eErr = OGRGeometryFactory::createFromWkb(
     266             :                 pabySubData, nullptr, &poSubGeom, nSize, eWkbVariant,
     267             :                 nSubGeomBytesConsumedOut);
     268             :         }
     269             :         else
     270             :         {
     271           2 :             CPLDebug(
     272             :                 "OGR",
     273             :                 "Cannot add geometry of type (%d) to geometry of type (%d)",
     274           2 :                 eFlattenSubGeomType, poGeom->getGeometryType());
     275           2 :             return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
     276             :         }
     277             : 
     278        1858 :         if (eErr == OGRERR_NONE)
     279             :         {
     280        1747 :             CPLAssert(nSubGeomBytesConsumedOut > 0);
     281        1747 :             if (nSize != static_cast<size_t>(-1))
     282             :             {
     283        1747 :                 CPLAssert(nSize >= nSubGeomBytesConsumedOut);
     284        1747 :                 nSize -= nSubGeomBytesConsumedOut;
     285             :             }
     286             : 
     287        1747 :             nDataOffset += nSubGeomBytesConsumedOut;
     288             : 
     289        1747 :             OGRCurve *poCurve = poSubGeom->toCurve();
     290        1747 :             eErr = pfnAddCurveDirectlyFromWkb(poGeom, poCurve);
     291             :         }
     292        1858 :         if (eErr != OGRERR_NONE)
     293             :         {
     294         113 :             delete poSubGeom;
     295         113 :             return eErr;
     296             :         }
     297             :     }
     298        1744 :     nBytesConsumedOut = nDataOffset;
     299             : 
     300        1744 :     return OGRERR_NONE;
     301             : }
     302             : 
     303             : /************************************************************************/
     304             : /*                            exportToWkt()                             */
     305             : /************************************************************************/
     306             : 
     307         263 : std::string OGRCurveCollection::exportToWkt(const OGRGeometry *baseGeom,
     308             :                                             const OGRWktOptions &opts,
     309             :                                             OGRErr *err) const
     310             : {
     311             :     try
     312             :     {
     313         263 :         bool first = true;
     314         526 :         std::string wkt(baseGeom->getGeometryName());
     315             : 
     316         263 :         OGRWktOptions optsModified(opts);
     317         263 :         optsModified.variant = wkbVariantIso;
     318         263 :         wkt += baseGeom->wktTypeString(optsModified.variant);
     319             : 
     320         613 :         for (int i = 0; i < nCurveCount; ++i)
     321             :         {
     322         350 :             OGRGeometry *geom = papoCurves[i];
     323             : 
     324         350 :             OGRErr subgeomErr = OGRERR_NONE;
     325         350 :             std::string tempWkt = geom->exportToWkt(optsModified, &subgeomErr);
     326         350 :             if (subgeomErr != OGRERR_NONE)
     327             :             {
     328           0 :                 if (err)
     329           0 :                     *err = subgeomErr;
     330           0 :                 return std::string();
     331             :             }
     332             : 
     333             :             // A curve collection has a list of linestrings (OGRCompoundCurve),
     334             :             // which should have their leader removed, or a OGRCurvePolygon,
     335             :             // which has leaders for each of its sub-geometries that aren't
     336             :             // linestrings.
     337         350 :             if (tempWkt.compare(0, strlen("LINESTRING"), "LINESTRING") == 0)
     338             :             {
     339         177 :                 auto pos = tempWkt.find('(');
     340         177 :                 if (pos != std::string::npos)
     341         177 :                     tempWkt = tempWkt.substr(pos);
     342             :             }
     343             : 
     344         350 :             if (tempWkt.find("EMPTY") != std::string::npos)
     345           0 :                 continue;
     346             : 
     347         350 :             if (first)
     348         232 :                 wkt += '(';
     349             :             else
     350         118 :                 wkt += ',';
     351         350 :             first = false;
     352         350 :             wkt += tempWkt;
     353             :         }
     354             : 
     355         263 :         if (err)
     356         262 :             *err = OGRERR_NONE;
     357         263 :         if (first)
     358          31 :             wkt += "EMPTY";
     359             :         else
     360         232 :             wkt += ')';
     361         263 :         return wkt;
     362             :     }
     363           0 :     catch (const std::bad_alloc &e)
     364             :     {
     365           0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
     366           0 :         if (err)
     367           0 :             *err = OGRERR_FAILURE;
     368           0 :         return std::string();
     369             :     }
     370             : }
     371             : 
     372             : /************************************************************************/
     373             : /*                            exportToWkb()                             */
     374             : /************************************************************************/
     375             : 
     376             : OGRErr
     377         913 : OGRCurveCollection::exportToWkb(const OGRGeometry *poGeom,
     378             :                                 unsigned char *pabyData,
     379             :                                 const OGRwkbExportOptions *psOptions) const
     380             : {
     381         913 :     if (psOptions == nullptr)
     382             :     {
     383             :         static const OGRwkbExportOptions defaultOptions;
     384           0 :         psOptions = &defaultOptions;
     385             :     }
     386             : 
     387             :     /* -------------------------------------------------------------------- */
     388             :     /*      Set the byte order.                                             */
     389             :     /* -------------------------------------------------------------------- */
     390         913 :     pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER(
     391             :         static_cast<unsigned char>(psOptions->eByteOrder));
     392             : 
     393             :     /* -------------------------------------------------------------------- */
     394             :     /*      Set the geometry feature type, ensuring that 3D flag is         */
     395             :     /*      preserved.                                                      */
     396             :     /* -------------------------------------------------------------------- */
     397         913 :     GUInt32 nGType = poGeom->getIsoGeometryType();
     398         913 :     if (psOptions->eWkbVariant == wkbVariantPostGIS1)
     399             :     {
     400           0 :         const bool bIs3D = wkbHasZ(static_cast<OGRwkbGeometryType>(nGType));
     401           0 :         nGType = wkbFlatten(nGType);
     402           0 :         if (nGType == wkbCurvePolygon)
     403           0 :             nGType = POSTGIS15_CURVEPOLYGON;
     404           0 :         if (bIs3D)
     405             :             // Explicitly set wkb25DBit.
     406           0 :             nGType =
     407           0 :                 static_cast<OGRwkbGeometryType>(nGType | wkb25DBitInternalUse);
     408             :     }
     409             : 
     410         913 :     if (OGR_SWAP(psOptions->eByteOrder))
     411             :     {
     412           0 :         nGType = CPL_SWAP32(nGType);
     413             :     }
     414             : 
     415         913 :     memcpy(pabyData + 1, &nGType, 4);
     416             : 
     417             :     /* -------------------------------------------------------------------- */
     418             :     /*      Copy in the raw data.                                           */
     419             :     /* -------------------------------------------------------------------- */
     420         913 :     if (OGR_SWAP(psOptions->eByteOrder))
     421             :     {
     422           0 :         const int nCount = CPL_SWAP32(nCurveCount);
     423           0 :         memcpy(pabyData + 5, &nCount, 4);
     424             :     }
     425             :     else
     426             :     {
     427         913 :         memcpy(pabyData + 5, &nCurveCount, 4);
     428             :     }
     429             : 
     430             :     // TODO(schwehr): Where do these 9 values come from?
     431         913 :     size_t nOffset = 9;
     432             : 
     433             :     /* ==================================================================== */
     434             :     /*      Serialize each of the Geoms.                                    */
     435             :     /* ==================================================================== */
     436        1825 :     for (auto &&poSubGeom : *this)
     437             :     {
     438         912 :         poSubGeom->exportToWkb(pabyData + nOffset, psOptions);
     439             : 
     440         912 :         nOffset += poSubGeom->WkbSize();
     441             :     }
     442             : 
     443         913 :     return OGRERR_NONE;
     444             : }
     445             : 
     446             : /************************************************************************/
     447             : /*                               empty()                                */
     448             : /************************************************************************/
     449             : 
     450     3202790 : void OGRCurveCollection::empty(OGRGeometry *poGeom)
     451             : {
     452     3202790 :     if (papoCurves != nullptr)
     453             :     {
     454     6274760 :         for (auto &&poSubGeom : *this)
     455             :         {
     456     3139840 :             delete poSubGeom;
     457             :         }
     458     3134930 :         CPLFree(papoCurves);
     459             :     }
     460             : 
     461     3202800 :     nCurveCount = 0;
     462     3202800 :     papoCurves = nullptr;
     463     3202800 :     if (poGeom)
     464       64458 :         poGeom->setCoordinateDimension(2);
     465     3202800 : }
     466             : 
     467             : /************************************************************************/
     468             : /*                            getEnvelope()                             */
     469             : /************************************************************************/
     470             : 
     471      260505 : void OGRCurveCollection::getEnvelope(OGREnvelope *psEnvelope) const
     472             : {
     473      260505 :     OGREnvelope3D oEnv3D;
     474      260505 :     getEnvelope(&oEnv3D);
     475      260505 :     psEnvelope->MinX = oEnv3D.MinX;
     476      260505 :     psEnvelope->MinY = oEnv3D.MinY;
     477      260505 :     psEnvelope->MaxX = oEnv3D.MaxX;
     478      260505 :     psEnvelope->MaxY = oEnv3D.MaxY;
     479      260505 : }
     480             : 
     481             : /************************************************************************/
     482             : /*                            getEnvelope()                             */
     483             : /************************************************************************/
     484             : 
     485      641643 : void OGRCurveCollection::getEnvelope(OGREnvelope3D *psEnvelope) const
     486             : {
     487      641643 :     OGREnvelope3D oGeomEnv;
     488      641643 :     bool bExtentSet = false;
     489             : 
     490      641643 :     *psEnvelope = OGREnvelope3D();
     491     1285030 :     for (int iGeom = 0; iGeom < nCurveCount; iGeom++)
     492             :     {
     493      643386 :         if (!papoCurves[iGeom]->IsEmpty())
     494             :         {
     495      643386 :             bExtentSet = true;
     496      643386 :             papoCurves[iGeom]->getEnvelope(&oGeomEnv);
     497      643386 :             psEnvelope->Merge(oGeomEnv);
     498             :         }
     499             :     }
     500             : 
     501      641643 :     if (!bExtentSet)
     502             :     {
     503             :         // To be backward compatible when called on empty geom
     504          10 :         psEnvelope->MinX = 0.0;
     505          10 :         psEnvelope->MinY = 0.0;
     506          10 :         psEnvelope->MinZ = 0.0;
     507          10 :         psEnvelope->MaxX = 0.0;
     508          10 :         psEnvelope->MaxY = 0.0;
     509          10 :         psEnvelope->MaxZ = 0.0;
     510             :     }
     511      641643 : }
     512             : 
     513             : /************************************************************************/
     514             : /*                               IsEmpty()                              */
     515             : /************************************************************************/
     516             : 
     517      574835 : OGRBoolean OGRCurveCollection::IsEmpty() const
     518             : {
     519      574859 :     for (auto &&poSubGeom : *this)
     520             :     {
     521      574148 :         if (!poSubGeom->IsEmpty())
     522      574124 :             return FALSE;
     523             :     }
     524         712 :     return TRUE;
     525             : }
     526             : 
     527             : /************************************************************************/
     528             : /*                               Equals()                                */
     529             : /************************************************************************/
     530             : 
     531       43559 : OGRBoolean OGRCurveCollection::Equals(const OGRCurveCollection *poOCC) const
     532             : {
     533       43559 :     if (getNumCurves() != poOCC->getNumCurves())
     534           2 :         return FALSE;
     535             : 
     536             :     // Should eventually test the SRS.
     537             : 
     538       73198 :     for (int iGeom = 0; iGeom < nCurveCount; iGeom++)
     539             :     {
     540       43782 :         if (!getCurve(iGeom)->Equals(poOCC->getCurve(iGeom)))
     541       14141 :             return FALSE;
     542             :     }
     543             : 
     544       29416 :     return TRUE;
     545             : }
     546             : 
     547             : /************************************************************************/
     548             : /*                       setCoordinateDimension()                       */
     549             : /************************************************************************/
     550             : 
     551       65335 : bool OGRCurveCollection::setCoordinateDimension(OGRGeometry *poGeom,
     552             :                                                 int nNewDimension)
     553             : {
     554       66264 :     for (auto &&poSubGeom : *this)
     555             :     {
     556         929 :         if (!poSubGeom->setCoordinateDimension(nNewDimension))
     557           0 :             return false;
     558             :     }
     559             : 
     560       65336 :     return poGeom->OGRGeometry::setCoordinateDimension(nNewDimension);
     561             : }
     562             : 
     563     1463470 : bool OGRCurveCollection::set3D(OGRGeometry *poGeom, OGRBoolean bIs3D)
     564             : {
     565     1571020 :     for (auto &&poSubGeom : *this)
     566             :     {
     567      107555 :         if (!poSubGeom->set3D(bIs3D))
     568           0 :             return false;
     569             :     }
     570             : 
     571     1463470 :     return poGeom->OGRGeometry::set3D(bIs3D);
     572             : }
     573             : 
     574      237829 : bool OGRCurveCollection::setMeasured(OGRGeometry *poGeom,
     575             :                                      OGRBoolean bIsMeasured)
     576             : {
     577      345457 :     for (auto &&poSubGeom : *this)
     578             :     {
     579      107628 :         if (!poSubGeom->setMeasured(bIsMeasured))
     580           0 :             return false;
     581             :     }
     582             : 
     583      237830 :     return poGeom->OGRGeometry::setMeasured(bIsMeasured);
     584             : }
     585             : 
     586             : /************************************************************************/
     587             : /*                       assignSpatialReference()                       */
     588             : /************************************************************************/
     589             : 
     590     1511120 : void OGRCurveCollection::assignSpatialReference(OGRGeometry *poGeom,
     591             :                                                 const OGRSpatialReference *poSR)
     592             : {
     593     3024840 :     for (auto &&poSubGeom : *this)
     594             :     {
     595     1513720 :         poSubGeom->assignSpatialReference(poSR);
     596             :     }
     597     1511120 :     poGeom->OGRGeometry::assignSpatialReference(poSR);
     598     1511120 : }
     599             : 
     600             : /************************************************************************/
     601             : /*                          getNumCurves()                              */
     602             : /************************************************************************/
     603             : 
     604       87118 : int OGRCurveCollection::getNumCurves() const
     605             : {
     606       87118 :     return nCurveCount;
     607             : }
     608             : 
     609             : /************************************************************************/
     610             : /*                           getCurve()                                 */
     611             : /************************************************************************/
     612             : 
     613      125491 : OGRCurve *OGRCurveCollection::getCurve(int i)
     614             : {
     615      125491 :     if (i < 0 || i >= nCurveCount)
     616         184 :         return nullptr;
     617      125307 :     return papoCurves[i];
     618             : }
     619             : 
     620             : /************************************************************************/
     621             : /*                           getCurve()                                 */
     622             : /************************************************************************/
     623             : 
     624      211670 : const OGRCurve *OGRCurveCollection::getCurve(int i) const
     625             : {
     626      211670 :     if (i < 0 || i >= nCurveCount)
     627           3 :         return nullptr;
     628      211667 :     return papoCurves[i];
     629             : }
     630             : 
     631             : /************************************************************************/
     632             : /*                           stealCurve()                               */
     633             : /************************************************************************/
     634             : 
     635           5 : OGRCurve *OGRCurveCollection::stealCurve(int i)
     636             : {
     637           5 :     if (i < 0 || i >= nCurveCount)
     638           0 :         return nullptr;
     639           5 :     OGRCurve *poRet = papoCurves[i];
     640           5 :     if (i < nCurveCount - 1)
     641             :     {
     642           2 :         memmove(papoCurves + i, papoCurves + i + 1,
     643           2 :                 (nCurveCount - i - 1) * sizeof(OGRCurve *));
     644             :     }
     645           5 :     nCurveCount--;
     646           5 :     return poRet;
     647             : }
     648             : 
     649             : /************************************************************************/
     650             : /*                             transform()                              */
     651             : /************************************************************************/
     652             : 
     653         638 : OGRErr OGRCurveCollection::transform(OGRGeometry *poGeom,
     654             :                                      OGRCoordinateTransformation *poCT)
     655             : {
     656        1498 :     for (int iGeom = 0; iGeom < nCurveCount; iGeom++)
     657             :     {
     658         860 :         const OGRErr eErr = papoCurves[iGeom]->transform(poCT);
     659         860 :         if (eErr != OGRERR_NONE)
     660             :         {
     661           0 :             if (iGeom != 0)
     662             :             {
     663           0 :                 CPLDebug("OGR", "OGRCurveCollection::transform() failed for a "
     664             :                                 "geometry other than the first, meaning some "
     665             :                                 "geometries are transformed and some are not!");
     666             : 
     667           0 :                 return OGRERR_FAILURE;
     668             :             }
     669             : 
     670           0 :             return eErr;
     671             :         }
     672             :     }
     673             : 
     674         638 :     poGeom->assignSpatialReference(poCT->GetTargetCS());
     675             : 
     676         638 :     return OGRERR_NONE;
     677             : }
     678             : 
     679             : /************************************************************************/
     680             : /*                            flattenTo2D()                             */
     681             : /************************************************************************/
     682             : 
     683         792 : void OGRCurveCollection::flattenTo2D(OGRGeometry *poGeom)
     684             : {
     685        1650 :     for (auto &&poSubGeom : *this)
     686             :     {
     687         858 :         poSubGeom->flattenTo2D();
     688             :     }
     689             : 
     690         792 :     poGeom->setCoordinateDimension(2);
     691         792 : }
     692             : 
     693             : /************************************************************************/
     694             : /*                              segmentize()                            */
     695             : /************************************************************************/
     696             : 
     697          44 : bool OGRCurveCollection::segmentize(double dfMaxLength)
     698             : {
     699          88 :     for (auto &&poSubGeom : *this)
     700             :     {
     701          44 :         if (!poSubGeom->segmentize(dfMaxLength))
     702           0 :             return false;
     703             :     }
     704          44 :     return true;
     705             : }
     706             : 
     707             : /************************************************************************/
     708             : /*                               swapXY()                               */
     709             : /************************************************************************/
     710             : 
     711          75 : void OGRCurveCollection::swapXY()
     712             : {
     713         150 :     for (auto &&poSubGeom : *this)
     714             :     {
     715          75 :         poSubGeom->swapXY();
     716             :     }
     717          75 : }
     718             : 
     719             : /************************************************************************/
     720             : /*                         hasCurveGeometry()                           */
     721             : /************************************************************************/
     722             : 
     723         129 : OGRBoolean OGRCurveCollection::hasCurveGeometry(int bLookForNonLinear) const
     724             : {
     725         183 :     for (auto &&poSubGeom : *this)
     726             :     {
     727         155 :         if (poSubGeom->hasCurveGeometry(bLookForNonLinear))
     728         101 :             return TRUE;
     729             :     }
     730          28 :     return FALSE;
     731             : }
     732             : 
     733             : /************************************************************************/
     734             : /*                           removeCurve()                              */
     735             : /************************************************************************/
     736             : 
     737             : /**
     738             :  * \brief Remove a geometry from the container.
     739             :  *
     740             :  * Removing a geometry will cause the geometry count to drop by one, and all
     741             :  * "higher" geometries will shuffle down one in index.
     742             :  *
     743             :  * @param iIndex the index of the geometry to delete.  A value of -1 is a
     744             :  * special flag meaning that all geometries should be removed.
     745             :  *
     746             :  * @param bDelete if true the geometry will be deallocated, otherwise it will
     747             :  * not.  The default is true as the container is considered to own the
     748             :  * geometries in it.
     749             :  *
     750             :  * @return OGRERR_NONE if successful, or OGRERR_FAILURE if the index is
     751             :  * out of range.
     752             :  */
     753             : 
     754          22 : OGRErr OGRCurveCollection::removeCurve(int iIndex, bool bDelete)
     755             : 
     756             : {
     757          22 :     if (iIndex < -1 || iIndex >= nCurveCount)
     758           2 :         return OGRERR_FAILURE;
     759             : 
     760             :     // Special case.
     761          20 :     if (iIndex == -1)
     762             :     {
     763           3 :         while (nCurveCount > 0)
     764           2 :             removeCurve(nCurveCount - 1, bDelete);
     765           1 :         return OGRERR_NONE;
     766             :     }
     767             : 
     768          19 :     if (bDelete)
     769          19 :         delete papoCurves[iIndex];
     770             : 
     771          19 :     memmove(papoCurves + iIndex, papoCurves + iIndex + 1,
     772          19 :             sizeof(void *) * (nCurveCount - iIndex - 1));
     773             : 
     774          19 :     nCurveCount--;
     775             : 
     776          19 :     return OGRERR_NONE;
     777             : }
     778             : 
     779             : /************************************************************************/
     780             : /*                           hasEmptyParts()                            */
     781             : /************************************************************************/
     782             : 
     783             : /**
     784             :  * \brief Returns whether a geometry has empty parts/rings.
     785             :  *
     786             :  * Returns true if removeEmptyParts() will modify the geometry.
     787             :  *
     788             :  * This is different from IsEmpty().
     789             :  *
     790             :  * @since GDAL 3.10
     791             :  */
     792          99 : bool OGRCurveCollection::hasEmptyParts() const
     793             : {
     794         198 :     for (int i = 0; i < nCurveCount; ++i)
     795             :     {
     796         103 :         if (papoCurves[i]->IsEmpty() || papoCurves[i]->hasEmptyParts())
     797           4 :             return true;
     798             :     }
     799          95 :     return false;
     800             : }
     801             : 
     802             : /************************************************************************/
     803             : /*                          removeEmptyParts()                          */
     804             : /************************************************************************/
     805             : 
     806             : /**
     807             :  * \brief Remove empty parts/rings from this geometry.
     808             :  *
     809             :  * @since GDAL 3.10
     810             :  */
     811           9 : void OGRCurveCollection::removeEmptyParts()
     812             : {
     813          21 :     for (int i = nCurveCount - 1; i >= 0; --i)
     814             :     {
     815          12 :         papoCurves[i]->removeEmptyParts();
     816          12 :         if (papoCurves[i]->IsEmpty())
     817           4 :             removeCurve(i, true);
     818             :     }
     819           9 : }
     820             : 
     821             : /************************************************************************/
     822             : /*                           reversePoints()                            */
     823             : /************************************************************************/
     824             : 
     825             : /**
     826             :  * \brief Reverse point order.
     827             :  *
     828             :  * This method updates the points in this curve in place
     829             :  * reversing the point ordering (first for last, etc) and component ordering.
     830             :  *
     831             :  * @since 3.10
     832             :  */
     833           1 : void OGRCurveCollection::reversePoints()
     834             : 
     835             : {
     836           2 :     for (int i = 0; i < nCurveCount / 2; ++i)
     837             :     {
     838           1 :         std::swap(papoCurves[i], papoCurves[nCurveCount - 1 - i]);
     839             :     }
     840           3 :     for (int i = 0; i < nCurveCount; ++i)
     841             :     {
     842           2 :         papoCurves[i]->reversePoints();
     843             :     }
     844           1 : }
     845             : 
     846             : //! @endcond

Generated by: LCOV version 1.14