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

Generated by: LCOV version 1.14