LCOV - code coverage report
Current view: top level - ogr - ogrcurvepolygon.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 239 253 94.5 %
Date: 2025-10-15 23:46:56 Functions: 54 56 96.4 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  The OGRCurvePolygon geometry class.
       5             :  * Author:   Even Rouault <even dot rouault at spatialys dot com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_port.h"
      14             : #include "ogr_geometry.h"
      15             : 
      16             : #include <cstddef>
      17             : 
      18             : #include "cpl_error.h"
      19             : #include "ogr_api.h"
      20             : #include "ogr_core.h"
      21             : #include "ogr_geos.h"
      22             : #include "ogr_sfcgal.h"
      23             : #include "ogr_p.h"
      24             : #include "ogr_spatialref.h"
      25             : 
      26             : /************************************************************************/
      27             : /*               OGRCurvePolygon( const OGRCurvePolygon& )              */
      28             : /************************************************************************/
      29             : 
      30             : /**
      31             :  * \brief Copy constructor.
      32             :  */
      33             : 
      34             : OGRCurvePolygon::OGRCurvePolygon(const OGRCurvePolygon &) = default;
      35             : 
      36             : /************************************************************************/
      37             : /*                 operator=( const OGRCurvePolygon&)                  */
      38             : /************************************************************************/
      39             : 
      40             : /**
      41             :  * \brief Assignment operator.
      42             :  */
      43             : 
      44          14 : OGRCurvePolygon &OGRCurvePolygon::operator=(const OGRCurvePolygon &other)
      45             : {
      46          14 :     if (this != &other)
      47             :     {
      48          13 :         OGRSurface::operator=(other);
      49             : 
      50          23 :         for (const auto *poRing : other.oCC)
      51             :         {
      52          11 :             if (!isRingCorrectType(poRing))
      53             :             {
      54           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
      55             :                          "Illegal use of OGRCurvePolygon::operator=(): "
      56             :                          "trying to assign an incompatible sub-geometry");
      57           1 :                 return *this;
      58             :             }
      59             :         }
      60             : 
      61          12 :         oCC = other.oCC;
      62             :     }
      63          13 :     return *this;
      64             : }
      65             : 
      66             : /************************************************************************/
      67             : /*                               clone()                                */
      68             : /************************************************************************/
      69             : 
      70         300 : OGRCurvePolygon *OGRCurvePolygon::clone() const
      71             : 
      72             : {
      73         300 :     return new (std::nothrow) OGRCurvePolygon(*this);
      74             : }
      75             : 
      76             : /************************************************************************/
      77             : /*                               empty()                                */
      78             : /************************************************************************/
      79             : 
      80       62138 : void OGRCurvePolygon::empty()
      81             : 
      82             : {
      83       62138 :     oCC.empty(this);
      84       62138 : }
      85             : 
      86             : /************************************************************************/
      87             : /*                          getGeometryType()                           */
      88             : /************************************************************************/
      89             : 
      90        1485 : OGRwkbGeometryType OGRCurvePolygon::getGeometryType() const
      91             : 
      92             : {
      93        1485 :     if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
      94         203 :         return wkbCurvePolygonZM;
      95        1282 :     else if (flags & OGR_G_MEASURED)
      96          27 :         return wkbCurvePolygonM;
      97        1255 :     else if (flags & OGR_G_3D)
      98         131 :         return wkbCurvePolygonZ;
      99             :     else
     100        1124 :         return wkbCurvePolygon;
     101             : }
     102             : 
     103             : /************************************************************************/
     104             : /*                            getDimension()                            */
     105             : /************************************************************************/
     106             : 
     107        1950 : int OGRCurvePolygon::getDimension() const
     108             : 
     109             : {
     110        1950 :     return 2;
     111             : }
     112             : 
     113             : /************************************************************************/
     114             : /*                            flattenTo2D()                             */
     115             : /************************************************************************/
     116             : 
     117         785 : void OGRCurvePolygon::flattenTo2D()
     118             : 
     119             : {
     120         785 :     oCC.flattenTo2D(this);
     121         785 : }
     122             : 
     123             : /************************************************************************/
     124             : /*                          getGeometryName()                           */
     125             : /************************************************************************/
     126             : 
     127         713 : const char *OGRCurvePolygon::getGeometryName() const
     128             : 
     129             : {
     130         713 :     return "CURVEPOLYGON";
     131             : }
     132             : 
     133             : /************************************************************************/
     134             : /*                         getExteriorRingCurve()                       */
     135             : /************************************************************************/
     136             : 
     137             : /**
     138             :  * \brief Fetch reference to external polygon ring.
     139             :  *
     140             :  * Note that the returned ring pointer is to an internal data object of the
     141             :  * OGRCurvePolygon.  It should not be modified or deleted by the application,
     142             :  * and the pointer is only valid till the polygon is next modified.  Use the
     143             :  * OGRGeometry::clone() method to make a separate copy within the application.
     144             :  *
     145             :  * Relates to the Simple Features for COM (SFCOM) IPolygon::get_ExteriorRing()
     146             :  * method.
     147             :  * TODO(rouault): What does that mean?
     148             :  *
     149             :  * @return pointer to external ring.  May be NULL if the OGRCurvePolygon is
     150             :  * empty.
     151             :  */
     152             : 
     153      125023 : OGRCurve *OGRCurvePolygon::getExteriorRingCurve()
     154             : 
     155             : {
     156      125023 :     return oCC.getCurve(0);
     157             : }
     158             : 
     159             : /**
     160             :  * \brief Fetch reference to external polygon ring.
     161             :  *
     162             :  * Note that the returned ring pointer is to an internal data object of the
     163             :  * OGRCurvePolygon.  It should not be modified or deleted by the application,
     164             :  * and the pointer is only valid till the polygon is next modified.  Use the
     165             :  * OGRGeometry::clone() method to make a separate copy within the application.
     166             :  *
     167             :  * Relates to the SFCOM IPolygon::get_ExteriorRing() method.
     168             :  *
     169             :  * @return pointer to external ring.  May be NULL if the OGRCurvePolygon is
     170             :  * empty.
     171             :  */
     172      123793 : const OGRCurve *OGRCurvePolygon::getExteriorRingCurve() const
     173             : 
     174             : {
     175      123793 :     return oCC.getCurve(0);
     176             : }
     177             : 
     178             : /************************************************************************/
     179             : /*                        getNumInteriorRings()                         */
     180             : /************************************************************************/
     181             : 
     182             : /**
     183             :  * \brief Fetch the number of internal rings.
     184             :  *
     185             :  * Relates to the SFCOM IPolygon::get_NumInteriorRings() method.
     186             :  *
     187             :  * @return count of internal rings, zero or more.
     188             :  */
     189             : 
     190      314574 : int OGRCurvePolygon::getNumInteriorRings() const
     191             : 
     192             : {
     193      314574 :     if (oCC.nCurveCount > 0)
     194      314561 :         return oCC.nCurveCount - 1;
     195             :     else
     196          13 :         return 0;
     197             : }
     198             : 
     199             : /************************************************************************/
     200             : /*                       getInteriorRingCurve()                         */
     201             : /************************************************************************/
     202             : 
     203             : /**
     204             :  * \brief Fetch reference to indicated internal ring.
     205             :  *
     206             :  * Note that the returned ring pointer is to an internal data object of the
     207             :  * OGRCurvePolygon.  It should not be modified or deleted by the application,
     208             :  * and the pointer is only valid till the polygon is next modified.  Use the
     209             :  * OGRGeometry::clone() method to make a separate copy within the application.
     210             :  *
     211             :  * Relates to the SFCOM IPolygon::get_InternalRing() method.
     212             :  *
     213             :  * @param iRing internal ring index from 0 to getNumInteriorRings() - 1.
     214             :  *
     215             :  * @return pointer to interior ring.  May be NULL.
     216             :  */
     217             : 
     218          95 : OGRCurve *OGRCurvePolygon::getInteriorRingCurve(int iRing)
     219             : 
     220             : {
     221          95 :     return oCC.getCurve(iRing + 1);
     222             : }
     223             : 
     224             : /**
     225             :  * \brief Fetch reference to indicated internal ring.
     226             :  *
     227             :  * Note that the returned ring pointer is to an internal data object of the
     228             :  * OGRCurvePolygon.  It should not be modified or deleted by the application,
     229             :  * and the pointer is only valid till the polygon is next modified.  Use the
     230             :  * OGRGeometry::clone() method to make a separate copy within the application.
     231             :  *
     232             :  * Relates to the SFCOM IPolygon::get_InternalRing() method.
     233             :  *
     234             :  * @param iRing internal ring index from 0 to getNumInteriorRings() - 1.
     235             :  *
     236             :  * @return pointer to interior ring.  May be NULL.
     237             :  */
     238             : 
     239          18 : const OGRCurve *OGRCurvePolygon::getInteriorRingCurve(int iRing) const
     240             : 
     241             : {
     242          18 :     return oCC.getCurve(iRing + 1);
     243             : }
     244             : 
     245             : /************************************************************************/
     246             : /*                        stealExteriorRingCurve()                      */
     247             : /************************************************************************/
     248             : 
     249             : /**
     250             :  * \brief "Steal" reference to external ring.
     251             :  *
     252             :  * After the call to that function, only call to stealInteriorRing() or
     253             :  * destruction of the OGRCurvePolygon is valid. Other operations may crash.
     254             :  *
     255             :  * @return pointer to external ring.  May be NULL if the OGRCurvePolygon is
     256             :  * empty.
     257             :  */
     258             : 
     259        1051 : OGRCurve *OGRCurvePolygon::stealExteriorRingCurve()
     260             : {
     261        1051 :     if (oCC.nCurveCount == 0)
     262           2 :         return nullptr;
     263        1049 :     OGRCurve *poRet = oCC.papoCurves[0];
     264        1049 :     oCC.papoCurves[0] = nullptr;
     265        1049 :     return poRet;
     266             : }
     267             : 
     268             : /************************************************************************/
     269             : /*                            removeRing()                              */
     270             : /************************************************************************/
     271             : 
     272             : /**
     273             :  * \brief Remove a geometry from the container.
     274             :  *
     275             :  * Removing a geometry will cause the geometry count to drop by one, and all
     276             :  * "higher" geometries will shuffle down one in index.
     277             :  *
     278             :  * There is no SFCOM analog to this method.
     279             :  *
     280             :  * @param iIndex the index of the geometry to delete.  A value of -1 is a
     281             :  * special flag meaning that all geometries should be removed.
     282             :  *
     283             :  * @param bDelete if true the geometry will be deallocated, otherwise it will
     284             :  * not.  The default is true as the container is considered to own the
     285             :  * geometries in it.
     286             :  *
     287             :  * @return OGRERR_NONE if successful, or OGRERR_FAILURE if the index is
     288             :  * out of range.
     289             :  */
     290             : 
     291          16 : OGRErr OGRCurvePolygon::removeRing(int iIndex, bool bDelete)
     292             : {
     293          16 :     return oCC.removeCurve(iIndex, bDelete);
     294             : }
     295             : 
     296             : /************************************************************************/
     297             : /*                              addRing()                               */
     298             : /************************************************************************/
     299             : 
     300             : /**
     301             :  * \brief Add a ring to a polygon.
     302             :  *
     303             :  * If the polygon has no external ring (it is empty) this will be used as
     304             :  * the external ring, otherwise it is used as an internal ring.  The passed
     305             :  * OGRCurve remains the responsibility of the caller (an internal copy
     306             :  * is made).
     307             :  *
     308             :  * This method has no SFCOM analog.
     309             :  *
     310             :  * @param poNewRing ring to be added to the polygon.
     311             :  * @return OGRERR_NONE in case of success
     312             :  */
     313             : 
     314        2168 : OGRErr OGRCurvePolygon::addRing(const OGRCurve *poNewRing)
     315             : 
     316             : {
     317        2168 :     OGRCurve *poNewRingCloned = poNewRing->clone();
     318        2167 :     OGRErr eErr = addRingDirectly(poNewRingCloned);
     319        2168 :     if (eErr != OGRERR_NONE)
     320           0 :         delete poNewRingCloned;
     321        2169 :     return eErr;
     322             : }
     323             : 
     324             : /************************************************************************/
     325             : /*                            isRingCorrectType()                       */
     326             : /************************************************************************/
     327         685 : bool OGRCurvePolygon::isRingCorrectType(const OGRCurve *poRing) const
     328             : {
     329         685 :     return poRing && !EQUAL(poRing->getGeometryName(), "LINEARRING");
     330             : }
     331             : 
     332             : /************************************************************************/
     333             : /*                            checkRing()                               */
     334             : /************************************************************************/
     335             : 
     336         681 : bool OGRCurvePolygon::checkRing(const OGRCurve *poNewRing) const
     337             : {
     338         681 :     if (!isRingCorrectType(poNewRing))
     339             :     {
     340           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Linearring not allowed.");
     341           1 :         return false;
     342             :     }
     343             : 
     344         680 :     if (!poNewRing->IsEmpty() && !poNewRing->get_IsClosed())
     345             :     {
     346             :         // This configuration option name must be the same as in
     347             :         // OGRPolygon::checkRing()
     348             :         const char *pszEnvVar =
     349           9 :             CPLGetConfigOption("OGR_GEOMETRY_ACCEPT_UNCLOSED_RING", nullptr);
     350           9 :         if (pszEnvVar != nullptr && !CPLTestBool(pszEnvVar))
     351             :         {
     352           2 :             CPLError(CE_Failure, CPLE_AppDefined, "Non closed ring detected.");
     353           2 :             return false;
     354             :         }
     355             :         else
     356             :         {
     357           7 :             CPLError(CE_Warning, CPLE_AppDefined, "Non closed ring detected.%s",
     358             :                      pszEnvVar == nullptr
     359             :                          ? " To avoid accepting it, set the "
     360             :                            "OGR_GEOMETRY_ACCEPT_UNCLOSED_RING configuration "
     361             :                            "option to NO"
     362             :                          : "");
     363             :         }
     364             :     }
     365             : 
     366         678 :     if (wkbFlatten(poNewRing->getGeometryType()) == wkbLineString)
     367             :     {
     368         221 :         if (poNewRing->getNumPoints() < 4)
     369             :         {
     370           8 :             return false;
     371             :         }
     372             :     }
     373             : 
     374         670 :     return true;
     375             : }
     376             : 
     377             : /************************************************************************/
     378             : /*                          addRingDirectly()                           */
     379             : /************************************************************************/
     380             : 
     381             : /**
     382             :  * \brief Add a ring to a polygon.
     383             :  *
     384             :  * If the polygon has no external ring (it is empty) this will be used as
     385             :  * the external ring, otherwise it is used as an internal ring.  Ownership
     386             :  * of the passed ring is assumed by the OGRCurvePolygon, but otherwise this
     387             :  * method operates the same as OGRCurvePolygon::AddRing().
     388             :  *
     389             :  * This method has no SFCOM analog.
     390             :  *
     391             :  * @param poNewRing ring to be added to the polygon.
     392             :  * @return OGRERR_NONE in case of success
     393             :  */
     394             : 
     395      157353 : OGRErr OGRCurvePolygon::addRingDirectly(OGRCurve *poNewRing)
     396             : {
     397      157353 :     return addRingDirectlyInternal(poNewRing, TRUE);
     398             : }
     399             : 
     400      208669 : OGRErr OGRCurvePolygon::addRingDirectlyInternal(OGRCurve *poNewRing,
     401             :                                                 int bNeedRealloc)
     402             : {
     403      208669 :     if (!checkRing(poNewRing))
     404          14 :         return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
     405             : 
     406      208655 :     HomogenizeDimensionalityWith(poNewRing);
     407             : 
     408      208655 :     return oCC.addCurveDirectly(this, poNewRing, bNeedRealloc);
     409             : }
     410             : 
     411             : /************************************************************************/
     412             : /*                             addRing()                                */
     413             : /************************************************************************/
     414             : 
     415             : /**
     416             :  * \brief Add a ring to a polygon.
     417             :  *
     418             :  * If the polygon has no external ring (it is empty) this will be used as
     419             :  * the external ring, otherwise it is used as an internal ring.
     420             :  *
     421             :  * This method has no SFCOM analog.
     422             :  *
     423             :  * @param poNewRing ring to be added to the polygon.
     424             :  * @return OGRERR_NONE in case of success
     425             :  */
     426       51278 : OGRErr OGRCurvePolygon::addRing(std::unique_ptr<OGRCurve> poNewRing)
     427             : {
     428       51278 :     OGRCurve *poNewRingPtr = poNewRing.release();
     429       51278 :     OGRErr eErr = addRingDirectlyInternal(poNewRingPtr, TRUE);
     430       51278 :     if (eErr != OGRERR_NONE)
     431           0 :         delete poNewRingPtr;
     432       51278 :     return eErr;
     433             : }
     434             : 
     435             : /************************************************************************/
     436             : /*                              WkbSize()                               */
     437             : /*                                                                      */
     438             : /*      Return the size of this object in well known binary             */
     439             : /*      representation including the byte order, and type information.  */
     440             : /************************************************************************/
     441             : 
     442         205 : size_t OGRCurvePolygon::WkbSize() const
     443             : 
     444             : {
     445         205 :     return oCC.WkbSize();
     446             : }
     447             : 
     448             : /************************************************************************/
     449             : /*                       addCurveDirectlyFromWkb()                      */
     450             : /************************************************************************/
     451             : 
     452          22 : OGRErr OGRCurvePolygon::addCurveDirectlyFromWkb(OGRGeometry *poSelf,
     453             :                                                 OGRCurve *poCurve)
     454             : {
     455          22 :     OGRCurvePolygon *poCP = poSelf->toCurvePolygon();
     456          22 :     return poCP->addRingDirectlyInternal(poCurve, FALSE);
     457             : }
     458             : 
     459             : /************************************************************************/
     460             : /*                           importFromWkb()                            */
     461             : /*                                                                      */
     462             : /*      Initialize from serialized stream in well known binary          */
     463             : /*      format.                                                         */
     464             : /************************************************************************/
     465             : 
     466          24 : OGRErr OGRCurvePolygon::importFromWkb(const unsigned char *pabyData,
     467             :                                       size_t nSize, OGRwkbVariant eWkbVariant,
     468             :                                       size_t &nBytesConsumedOut)
     469             : 
     470             : {
     471          24 :     nBytesConsumedOut = 0;
     472             :     OGRwkbByteOrder eByteOrder;
     473          24 :     size_t nDataOffset = 0;
     474             :     // coverity[tainted_data]
     475          24 :     OGRErr eErr = oCC.importPreambleFromWkb(this, pabyData, nSize, nDataOffset,
     476             :                                             eByteOrder, 9, eWkbVariant);
     477          24 :     if (eErr != OGRERR_NONE)
     478           0 :         return eErr;
     479             : 
     480          24 :     eErr = oCC.importBodyFromWkb(this, pabyData + nDataOffset, nSize,
     481             :                                  true,  // bAcceptCompoundCurve
     482             :                                  addCurveDirectlyFromWkb, eWkbVariant,
     483             :                                  nBytesConsumedOut);
     484          24 :     if (eErr == OGRERR_NONE)
     485          24 :         nBytesConsumedOut += nDataOffset;
     486          24 :     return eErr;
     487             : }
     488             : 
     489             : /************************************************************************/
     490             : /*                            exportToWkb()                             */
     491             : /*                                                                      */
     492             : /*      Build a well known binary representation of this object.        */
     493             : /************************************************************************/
     494             : 
     495          33 : OGRErr OGRCurvePolygon::exportToWkb(unsigned char *pabyData,
     496             :                                     const OGRwkbExportOptions *psOptions) const
     497             : {
     498             :     OGRwkbExportOptions sOptions(psOptions ? *psOptions
     499          33 :                                            : OGRwkbExportOptions());
     500             : 
     501             :     // Does not make sense for new geometries, so patch it.
     502          33 :     if (sOptions.eWkbVariant == wkbVariantOldOgc)
     503          14 :         sOptions.eWkbVariant = wkbVariantIso;
     504          66 :     return oCC.exportToWkb(this, pabyData, &sOptions);
     505             : }
     506             : 
     507             : /************************************************************************/
     508             : /*                       addCurveDirectlyFromWkt()                      */
     509             : /************************************************************************/
     510             : 
     511         360 : OGRErr OGRCurvePolygon::addCurveDirectlyFromWkt(OGRGeometry *poSelf,
     512             :                                                 OGRCurve *poCurve)
     513             : {
     514         360 :     OGRCurvePolygon *poCP = poSelf->toCurvePolygon();
     515         360 :     return poCP->addRingDirectly(poCurve);
     516             : }
     517             : 
     518             : /************************************************************************/
     519             : /*                           importFromWkt()                            */
     520             : /*                                                                      */
     521             : /*      Instantiate from well known text format.                        */
     522             : /************************************************************************/
     523             : 
     524         332 : OGRErr OGRCurvePolygon::importFromWkt(const char **ppszInput)
     525             : 
     526             : {
     527         332 :     return importCurveCollectionFromWkt(ppszInput,
     528             :                                         FALSE,  // bAllowEmptyComponent
     529             :                                         TRUE,   // bAllowLineString
     530             :                                         TRUE,   // bAllowCurve
     531             :                                         TRUE,   // bAllowCompoundCurve
     532         332 :                                         addCurveDirectlyFromWkt);
     533             : }
     534             : 
     535             : /************************************************************************/
     536             : /*                            exportToWkt()                             */
     537             : /************************************************************************/
     538             : 
     539         133 : std::string OGRCurvePolygon::exportToWkt(const OGRWktOptions &opts,
     540             :                                          OGRErr *err) const
     541             : {
     542         133 :     return oCC.exportToWkt(this, opts, err);
     543             : }
     544             : 
     545             : /************************************************************************/
     546             : /*                           CurvePolyToPoly()                          */
     547             : /************************************************************************/
     548             : 
     549             : /**
     550             :  * \brief Return a polygon from a curve polygon.
     551             :  *
     552             :  * This method is the same as C function OGR_G_CurvePolyToPoly().
     553             :  *
     554             :  * The returned geometry is a new instance whose ownership belongs to
     555             :  * the caller.
     556             :  *
     557             :  * @param dfMaxAngleStepSizeDegrees the largest step in degrees along the
     558             :  * arc, zero to use the default setting.
     559             :  * @param papszOptions options as a null-terminated list of strings.
     560             :  *                     Unused for now. Must be set to NULL.
     561             :  *
     562             :  * @return a linestring
     563             :  */
     564             : 
     565             : OGRPolygon *
     566         404 : OGRCurvePolygon::CurvePolyToPoly(double dfMaxAngleStepSizeDegrees,
     567             :                                  const char *const *papszOptions) const
     568             : {
     569         404 :     OGRPolygon *poPoly = new OGRPolygon();
     570         404 :     poPoly->assignSpatialReference(getSpatialReference());
     571         866 :     for (int iRing = 0; iRing < oCC.nCurveCount; iRing++)
     572             :     {
     573         924 :         OGRLineString *poLS = oCC.papoCurves[iRing]->CurveToLine(
     574         462 :             dfMaxAngleStepSizeDegrees, papszOptions);
     575         462 :         OGRLinearRing *poRing = OGRCurve::CastToLinearRing(poLS);
     576         462 :         if (poRing == nullptr)
     577             :         {
     578           0 :             CPLError(CE_Failure, CPLE_IllegalArg,
     579             :                      "OGRCurve::CastToLinearRing failed");
     580           0 :             break;
     581             :         }
     582         462 :         poPoly->addRingDirectly(poRing);
     583             :     }
     584         404 :     return poPoly;
     585             : }
     586             : 
     587             : /************************************************************************/
     588             : /*                         hasCurveGeometry()                           */
     589             : /************************************************************************/
     590             : 
     591         636 : OGRBoolean OGRCurvePolygon::hasCurveGeometry(int bLookForNonLinear) const
     592             : {
     593         636 :     if (bLookForNonLinear)
     594             :     {
     595          84 :         return oCC.hasCurveGeometry(bLookForNonLinear);
     596             :     }
     597             : 
     598         552 :     return TRUE;
     599             : }
     600             : 
     601             : /************************************************************************/
     602             : /*                         getLinearGeometry()                        */
     603             : /************************************************************************/
     604             : 
     605             : OGRGeometry *
     606         370 : OGRCurvePolygon::getLinearGeometry(double dfMaxAngleStepSizeDegrees,
     607             :                                    const char *const *papszOptions) const
     608             : {
     609         370 :     return CurvePolyToPoly(dfMaxAngleStepSizeDegrees, papszOptions);
     610             : }
     611             : 
     612             : /************************************************************************/
     613             : /*                            getEnvelope()                             */
     614             : /************************************************************************/
     615             : 
     616      259166 : void OGRCurvePolygon::getEnvelope(OGREnvelope *psEnvelope) const
     617             : 
     618             : {
     619      259166 :     oCC.getEnvelope(psEnvelope);
     620      259166 : }
     621             : 
     622             : /************************************************************************/
     623             : /*                            getEnvelope()                             */
     624             : /************************************************************************/
     625             : 
     626      381083 : void OGRCurvePolygon::getEnvelope(OGREnvelope3D *psEnvelope) const
     627             : 
     628             : {
     629      381083 :     oCC.getEnvelope(psEnvelope);
     630      381083 : }
     631             : 
     632             : /************************************************************************/
     633             : /*                               Equals()                               */
     634             : /************************************************************************/
     635             : 
     636       42619 : OGRBoolean OGRCurvePolygon::Equals(const OGRGeometry *poOther) const
     637             : 
     638             : {
     639       42619 :     if (poOther == this)
     640           1 :         return TRUE;
     641             : 
     642       42618 :     if (poOther->getGeometryType() != getGeometryType())
     643           1 :         return FALSE;
     644             : 
     645       42617 :     if (IsEmpty() && poOther->IsEmpty())
     646           6 :         return TRUE;
     647             : 
     648       42611 :     return oCC.Equals(&(poOther->toCurvePolygon()->oCC));
     649             : }
     650             : 
     651             : /************************************************************************/
     652             : /*                             transform()                              */
     653             : /************************************************************************/
     654             : 
     655         613 : OGRErr OGRCurvePolygon::transform(OGRCoordinateTransformation *poCT)
     656             : 
     657             : {
     658         613 :     return oCC.transform(this, poCT);
     659             : }
     660             : 
     661             : /************************************************************************/
     662             : /*                              get_Length()                            */
     663             : /************************************************************************/
     664             : 
     665           3 : double OGRCurvePolygon::get_Length() const
     666             : 
     667             : {
     668           3 :     double dfLength = 0.0;
     669           6 :     for (const auto &poCurve : *this)
     670             :     {
     671           3 :         dfLength += poCurve->get_Length();
     672             :     }
     673             : 
     674           3 :     return dfLength;
     675             : }
     676             : 
     677             : /************************************************************************/
     678             : /*                        get_GeodesicLength()                          */
     679             : /************************************************************************/
     680             : 
     681          14 : double OGRCurvePolygon::get_GeodesicLength(
     682             :     const OGRSpatialReference *poSRSOverride) const
     683             : 
     684             : {
     685          14 :     if (!poSRSOverride)
     686          14 :         poSRSOverride = getSpatialReference();
     687             : 
     688          14 :     double dfLength = 0.0;
     689          26 :     for (const auto &poCurve : *this)
     690             :     {
     691          14 :         const double dfLocalLength = poCurve->get_GeodesicLength(poSRSOverride);
     692          14 :         if (dfLocalLength < 0)
     693           2 :             return dfLocalLength;
     694          12 :         dfLength += dfLocalLength;
     695             :     }
     696             : 
     697          12 :     return dfLength;
     698             : }
     699             : 
     700             : /************************************************************************/
     701             : /*                              get_Area()                              */
     702             : /************************************************************************/
     703             : 
     704       61781 : double OGRCurvePolygon::get_Area() const
     705             : 
     706             : {
     707       61781 :     if (getExteriorRingCurve() == nullptr)
     708           2 :         return 0.0;
     709             : 
     710       61779 :     double dfArea = getExteriorRingCurve()->get_Area();
     711             : 
     712       61792 :     for (int iRing = 0; iRing < getNumInteriorRings(); iRing++)
     713             :     {
     714          13 :         dfArea -= getInteriorRingCurve(iRing)->get_Area();
     715             :     }
     716             : 
     717       61779 :     return dfArea;
     718             : }
     719             : 
     720             : /************************************************************************/
     721             : /*                        get_GeodesicArea()                            */
     722             : /************************************************************************/
     723             : 
     724          17 : double OGRCurvePolygon::get_GeodesicArea(
     725             :     const OGRSpatialReference *poSRSOverride) const
     726             : 
     727             : {
     728          17 :     if (getExteriorRingCurve() == nullptr)
     729           1 :         return 0.0;
     730             : 
     731          16 :     if (!poSRSOverride)
     732          16 :         poSRSOverride = getSpatialReference();
     733             : 
     734          16 :     double dfArea = getExteriorRingCurve()->get_GeodesicArea(poSRSOverride);
     735          16 :     if (dfArea > 0)
     736             :     {
     737          15 :         for (int iRing = 0; iRing < getNumInteriorRings(); iRing++)
     738             :         {
     739           1 :             dfArea -=
     740           1 :                 getInteriorRingCurve(iRing)->get_GeodesicArea(poSRSOverride);
     741             :         }
     742             :     }
     743             : 
     744          16 :     return dfArea;
     745             : }
     746             : 
     747             : /************************************************************************/
     748             : /*                       setCoordinateDimension()                       */
     749             : /************************************************************************/
     750             : 
     751       63005 : bool OGRCurvePolygon::setCoordinateDimension(int nNewDimension)
     752             : 
     753             : {
     754       63005 :     return oCC.setCoordinateDimension(this, nNewDimension);
     755             : }
     756             : 
     757     1459350 : bool OGRCurvePolygon::set3D(OGRBoolean bIs3D)
     758             : {
     759     1459350 :     return oCC.set3D(this, bIs3D);
     760             : }
     761             : 
     762      231488 : bool OGRCurvePolygon::setMeasured(OGRBoolean bIsMeasured)
     763             : {
     764      231488 :     return oCC.setMeasured(this, bIsMeasured);
     765             : }
     766             : 
     767             : /************************************************************************/
     768             : /*                       assignSpatialReference()                       */
     769             : /************************************************************************/
     770             : 
     771     1508380 : void OGRCurvePolygon::assignSpatialReference(const OGRSpatialReference *poSR)
     772             : {
     773     1508380 :     oCC.assignSpatialReference(this, poSR);
     774     1508380 : }
     775             : 
     776             : /************************************************************************/
     777             : /*                               IsEmpty()                              */
     778             : /************************************************************************/
     779             : 
     780      573794 : OGRBoolean OGRCurvePolygon::IsEmpty() const
     781             : {
     782      573794 :     return oCC.IsEmpty();
     783             : }
     784             : 
     785             : /************************************************************************/
     786             : /*                              segmentize()                            */
     787             : /************************************************************************/
     788             : 
     789          43 : bool OGRCurvePolygon::segmentize(double dfMaxLength)
     790             : {
     791          43 :     if (EQUAL(getGeometryName(), "TRIANGLE"))
     792             :     {
     793           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     794             :                  "segmentize() is not valid for Triangle");
     795           0 :         return false;
     796             :     }
     797          43 :     return oCC.segmentize(dfMaxLength);
     798             : }
     799             : 
     800             : /************************************************************************/
     801             : /*                               swapXY()                               */
     802             : /************************************************************************/
     803             : 
     804          74 : void OGRCurvePolygon::swapXY()
     805             : {
     806          74 :     oCC.swapXY();
     807          74 : }
     808             : 
     809             : /************************************************************************/
     810             : /*                           ContainsPoint()                             */
     811             : /************************************************************************/
     812             : 
     813          15 : OGRBoolean OGRCurvePolygon::ContainsPoint(const OGRPoint *p) const
     814             : {
     815          15 :     if (getExteriorRingCurve() != nullptr && getNumInteriorRings() == 0)
     816             :     {
     817          15 :         const int nRet = getExteriorRingCurve()->ContainsPoint(p);
     818          15 :         if (nRet >= 0)
     819           5 :             return nRet;
     820             :     }
     821             : 
     822          10 :     return OGRGeometry::Contains(p);
     823             : }
     824             : 
     825             : /************************************************************************/
     826             : /*                          IntersectsPoint()                           */
     827             : /************************************************************************/
     828             : 
     829           3 : OGRBoolean OGRCurvePolygon::IntersectsPoint(const OGRPoint *p) const
     830             : {
     831           3 :     if (getExteriorRingCurve() != nullptr && getNumInteriorRings() == 0)
     832             :     {
     833           3 :         const int nRet = getExteriorRingCurve()->IntersectsPoint(p);
     834           3 :         if (nRet >= 0)
     835           2 :             return nRet;
     836             :     }
     837             : 
     838           1 :     return OGRGeometry::Intersects(p);
     839             : }
     840             : 
     841             : /************************************************************************/
     842             : /*                               Contains()                             */
     843             : /************************************************************************/
     844             : 
     845          37 : OGRBoolean OGRCurvePolygon::Contains(const OGRGeometry *poOtherGeom) const
     846             : 
     847             : {
     848          74 :     if (!IsEmpty() && poOtherGeom != nullptr &&
     849          37 :         wkbFlatten(poOtherGeom->getGeometryType()) == wkbPoint)
     850             :     {
     851          15 :         return ContainsPoint(poOtherGeom->toPoint());
     852             :     }
     853             : 
     854          22 :     return OGRGeometry::Contains(poOtherGeom);
     855             : }
     856             : 
     857             : /************************************************************************/
     858             : /*                              Intersects()                            */
     859             : /************************************************************************/
     860             : 
     861          10 : OGRBoolean OGRCurvePolygon::Intersects(const OGRGeometry *poOtherGeom) const
     862             : 
     863             : {
     864          20 :     if (!IsEmpty() && poOtherGeom != nullptr &&
     865          10 :         wkbFlatten(poOtherGeom->getGeometryType()) == wkbPoint)
     866             :     {
     867           3 :         return IntersectsPoint(poOtherGeom->toPoint());
     868             :     }
     869             : 
     870           7 :     return OGRGeometry::Intersects(poOtherGeom);
     871             : }
     872             : 
     873             : /************************************************************************/
     874             : /*                           CastToPolygon()                            */
     875             : /************************************************************************/
     876             : 
     877             : /**
     878             :  * \brief Convert to polygon.
     879             :  *
     880             :  * This method should only be called if the curve polygon actually only contains
     881             :  * instances of OGRLineString. This can be verified if hasCurveGeometry(TRUE)
     882             :  * returns FALSE. It is not intended to approximate curve polygons. For that
     883             :  * use getLinearGeometry().
     884             :  *
     885             :  * The passed in geometry is consumed and a new one returned (or NULL in case
     886             :  * of failure).
     887             :  *
     888             :  * @param poCP the input geometry - ownership is passed to the method.
     889             :  * @return new geometry.
     890             :  */
     891             : 
     892          15 : OGRPolygon *OGRCurvePolygon::CastToPolygon(OGRCurvePolygon *poCP)
     893             : {
     894          29 :     for (int i = 0; i < poCP->oCC.nCurveCount; i++)
     895             :     {
     896          28 :         poCP->oCC.papoCurves[i] =
     897          14 :             OGRCurve::CastToLinearRing(poCP->oCC.papoCurves[i]);
     898          14 :         if (poCP->oCC.papoCurves[i] == nullptr)
     899             :         {
     900           0 :             delete poCP;
     901           0 :             return nullptr;
     902             :         }
     903             :     }
     904          15 :     OGRPolygon *poPoly = new OGRPolygon();
     905          15 :     poPoly->setCoordinateDimension(poCP->getCoordinateDimension());
     906          15 :     poPoly->assignSpatialReference(poCP->getSpatialReference());
     907          15 :     poPoly->oCC.nCurveCount = poCP->oCC.nCurveCount;
     908          15 :     poPoly->oCC.papoCurves = poCP->oCC.papoCurves;
     909          15 :     poCP->oCC.nCurveCount = 0;
     910          15 :     poCP->oCC.papoCurves = nullptr;
     911          15 :     delete poCP;
     912          15 :     return poPoly;
     913             : }
     914             : 
     915             : //! @cond Doxygen_Suppress
     916             : /************************************************************************/
     917             : /*                      GetCasterToPolygon()                            */
     918             : /************************************************************************/
     919             : 
     920          15 : OGRPolygon *OGRCurvePolygon::CasterToPolygon(OGRSurface *poSurface)
     921             : {
     922          15 :     OGRCurvePolygon *poCurvePoly = poSurface->toCurvePolygon();
     923          15 :     return OGRCurvePolygon::CastToPolygon(poCurvePoly);
     924             : }
     925             : 
     926          15 : OGRSurfaceCasterToPolygon OGRCurvePolygon::GetCasterToPolygon() const
     927             : {
     928          15 :     return OGRCurvePolygon::CasterToPolygon;
     929             : }
     930             : 
     931             : /************************************************************************/
     932             : /*                      GetCasterToCurvePolygon()                       */
     933             : /************************************************************************/
     934             : 
     935           0 : static OGRCurvePolygon *CasterToCurvePolygon(OGRSurface *poSurface)
     936             : {
     937           0 :     return poSurface->toCurvePolygon();
     938             : }
     939             : 
     940           0 : OGRSurfaceCasterToCurvePolygon OGRCurvePolygon::GetCasterToCurvePolygon() const
     941             : {
     942           0 :     return ::CasterToCurvePolygon;
     943             : }
     944             : 
     945             : //! @endcond
     946             : 
     947             : /************************************************************************/
     948             : /*                           hasEmptyParts()                            */
     949             : /************************************************************************/
     950             : 
     951          96 : bool OGRCurvePolygon::hasEmptyParts() const
     952             : {
     953          96 :     return oCC.hasEmptyParts();
     954             : }
     955             : 
     956             : /************************************************************************/
     957             : /*                          removeEmptyParts()                          */
     958             : /************************************************************************/
     959             : 
     960           7 : void OGRCurvePolygon::removeEmptyParts()
     961             : {
     962           7 :     auto poExteriorRing = getExteriorRingCurve();
     963           7 :     if (poExteriorRing && poExteriorRing->IsEmpty())
     964           0 :         empty();
     965             :     else
     966           7 :         oCC.removeEmptyParts();
     967           7 : }

Generated by: LCOV version 1.14