LCOV - code coverage report
Current view: top level - ogr - ogrpolygon.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 289 312 92.6 %
Date: 2025-05-09 19:18:34 Functions: 30 31 96.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  The OGRPolygon geometry class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999, Frank Warmerdam
       9             :  * Copyright (c) 2008-2014, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "ogr_geometry.h"
      16             : 
      17             : #include <cstring>
      18             : #include <cstddef>
      19             : #include <new>
      20             : 
      21             : #include "cpl_conv.h"
      22             : #include "cpl_error.h"
      23             : #include "cpl_vsi.h"
      24             : #include "ogr_api.h"
      25             : #include "ogr_core.h"
      26             : #include "ogr_geos.h"
      27             : #include "ogr_sfcgal.h"
      28             : #include "ogr_p.h"
      29             : 
      30             : /************************************************************************/
      31             : /*        OGRPolygon(double x1, double y1, double x2, double y2)        */
      32             : /************************************************************************/
      33             : 
      34             : /**
      35             :  * \brief Construct a rectangular polygon from opposite corner coordinates.
      36             :  *
      37             :  * @since GDAL 3.11
      38             :  */
      39             : 
      40          20 : OGRPolygon::OGRPolygon(double x1, double y1, double x2, double y2)
      41             : {
      42          40 :     auto poLR = std::make_unique<OGRLinearRing>();
      43          20 :     poLR->addPoint(x1, y1);
      44          20 :     poLR->addPoint(x1, y2);
      45          20 :     poLR->addPoint(x2, y2);
      46          20 :     poLR->addPoint(x2, y1);
      47          20 :     poLR->addPoint(x1, y1);
      48          20 :     addRingDirectly(poLR.release());
      49          20 : }
      50             : 
      51             : /************************************************************************/
      52             : /*                OGRPolygon(const OGREnvelope &envelope)               */
      53             : /************************************************************************/
      54             : 
      55             : /**
      56             :  * \brief Construct a rectangular polygon from opposite corner coordinates
      57             :  * of a OGREnvelope.
      58             :  *
      59             :  * @since GDAL 3.11
      60             :  */
      61             : 
      62           1 : OGRPolygon::OGRPolygon(const OGREnvelope &envelope)
      63           1 :     : OGRPolygon(envelope.MinX, envelope.MinY, envelope.MaxX, envelope.MaxY)
      64             : {
      65           1 : }
      66             : 
      67             : /************************************************************************/
      68             : /*                     OGRPolygon( const OGRPolygon& )                  */
      69             : /************************************************************************/
      70             : 
      71             : /**
      72             :  * \brief Copy constructor.
      73             :  *
      74             :  * Note: before GDAL 2.1, only the default implementation of the constructor
      75             :  * existed, which could be unsafe to use.
      76             :  *
      77             :  * @since GDAL 2.1
      78             :  */
      79             : 
      80             : OGRPolygon::OGRPolygon(const OGRPolygon &) = default;
      81             : 
      82             : /************************************************************************/
      83             : /*                     operator=( const OGRPolygon&)                    */
      84             : /************************************************************************/
      85             : 
      86             : /**
      87             :  * \brief Assignment operator.
      88             :  *
      89             :  * Note: before GDAL 2.1, only the default implementation of the operator
      90             :  * existed, which could be unsafe to use.
      91             :  *
      92             :  * @since GDAL 2.1
      93             :  */
      94             : 
      95           9 : OGRPolygon &OGRPolygon::operator=(const OGRPolygon &other)
      96             : {
      97           9 :     if (this != &other)
      98             :     {
      99           8 :         OGRCurvePolygon::operator=(other);
     100             :     }
     101           9 :     return *this;
     102             : }
     103             : 
     104             : /************************************************************************/
     105             : /*                               clone()                                */
     106             : /************************************************************************/
     107             : 
     108      201082 : OGRPolygon *OGRPolygon::clone() const
     109             : 
     110             : {
     111      201082 :     auto ret = new (std::nothrow) OGRPolygon(*this);
     112      201082 :     if (ret)
     113             :     {
     114      201082 :         if (ret->WkbSize() != WkbSize())
     115             :         {
     116           0 :             delete ret;
     117           0 :             ret = nullptr;
     118             :         }
     119             :     }
     120      201082 :     return ret;
     121             : }
     122             : 
     123             : /************************************************************************/
     124             : /*                          getGeometryType()                           */
     125             : /************************************************************************/
     126             : 
     127      774529 : OGRwkbGeometryType OGRPolygon::getGeometryType() const
     128             : 
     129             : {
     130      774529 :     if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
     131       47469 :         return wkbPolygonZM;
     132      727060 :     else if (flags & OGR_G_MEASURED)
     133         811 :         return wkbPolygonM;
     134      726249 :     else if (flags & OGR_G_3D)
     135      124176 :         return wkbPolygon25D;
     136             :     else
     137      602073 :         return wkbPolygon;
     138             : }
     139             : 
     140             : /************************************************************************/
     141             : /*                          getGeometryName()                           */
     142             : /************************************************************************/
     143             : 
     144       21835 : const char *OGRPolygon::getGeometryName() const
     145             : 
     146             : {
     147       21835 :     return "POLYGON";
     148             : }
     149             : 
     150             : /************************************************************************/
     151             : /*                          getExteriorRing()                           */
     152             : /************************************************************************/
     153             : 
     154             : /**
     155             :  * \brief Fetch reference to external polygon ring.
     156             :  *
     157             :  * Note that the returned ring pointer is to an internal data object of
     158             :  * the OGRPolygon.  It should not be modified or deleted by the application,
     159             :  * and the pointer is only valid till the polygon is next modified.  Use
     160             :  * the OGRGeometry::clone() method to make a separate copy within the
     161             :  * application.
     162             :  *
     163             :  * Relates to the SFCOM IPolygon::get_ExteriorRing() method.
     164             :  *
     165             :  * @return pointer to external ring.  May be NULL if the OGRPolygon is empty.
     166             :  */
     167             : 
     168       35116 : OGRLinearRing *OGRPolygon::getExteriorRing()
     169             : 
     170             : {
     171       35116 :     if (oCC.nCurveCount > 0)
     172       35025 :         return oCC.papoCurves[0]->toLinearRing();
     173             : 
     174          91 :     return nullptr;
     175             : }
     176             : 
     177             : /**
     178             :  * \brief Fetch reference to external polygon ring.
     179             :  *
     180             :  * Note that the returned ring pointer is to an internal data object of
     181             :  * the OGRPolygon.  It should not be modified or deleted by the application,
     182             :  * and the pointer is only valid till the polygon is next modified.  Use
     183             :  * the OGRGeometry::clone() method to make a separate copy within the
     184             :  * application.
     185             :  *
     186             :  * Relates to the SFCOM IPolygon::get_ExteriorRing() method.
     187             :  *
     188             :  * @return pointer to external ring.  May be NULL if the OGRPolygon is empty.
     189             :  */
     190             : 
     191      160530 : const OGRLinearRing *OGRPolygon::getExteriorRing() const
     192             : 
     193             : {
     194      160530 :     if (oCC.nCurveCount > 0)
     195      160404 :         return oCC.papoCurves[0]->toLinearRing();
     196             : 
     197         126 :     return nullptr;
     198             : }
     199             : 
     200             : /************************************************************************/
     201             : /*                          stealExteriorRing()                         */
     202             : /************************************************************************/
     203             : 
     204             : /**
     205             :  * \brief "Steal" reference to external polygon ring.
     206             :  *
     207             :  * After the call to that function, only call to stealInteriorRing() or
     208             :  * destruction of the OGRPolygon is valid. Other operations may crash.
     209             :  *
     210             :  * @return pointer to external ring.  May be NULL if the OGRPolygon is empty.
     211             :  */
     212             : 
     213          14 : OGRLinearRing *OGRPolygon::stealExteriorRing()
     214             : {
     215          14 :     return stealExteriorRingCurve()->toLinearRing();
     216             : }
     217             : 
     218             : /************************************************************************/
     219             : /*                          getInteriorRing()                           */
     220             : /************************************************************************/
     221             : 
     222             : /**
     223             :  * \brief Fetch reference to indicated internal ring.
     224             :  *
     225             :  * Note that the returned ring pointer is to an internal data object of
     226             :  * the OGRPolygon.  It should not be modified or deleted by the application,
     227             :  * and the pointer is only valid till the polygon is next modified.  Use
     228             :  * the OGRGeometry::clone() method to make a separate copy within the
     229             :  * application.
     230             :  *
     231             :  * Relates to the SFCOM IPolygon::get_InternalRing() method.
     232             :  *
     233             :  * @param iRing internal ring index from 0 to getNumInteriorRings() - 1.
     234             :  *
     235             :  * @return pointer to interior ring.  May be NULL.
     236             :  */
     237             : 
     238          35 : OGRLinearRing *OGRPolygon::getInteriorRing(int iRing)
     239             : 
     240             : {
     241          35 :     if (iRing < 0 || iRing >= oCC.nCurveCount - 1)
     242           0 :         return nullptr;
     243             : 
     244          35 :     return oCC.papoCurves[iRing + 1]->toLinearRing();
     245             : }
     246             : 
     247             : /**
     248             :  * \brief Fetch reference to indicated internal ring.
     249             :  *
     250             :  * Note that the returned ring pointer is to an internal data object of
     251             :  * the OGRPolygon.  It should not be modified or deleted by the application,
     252             :  * and the pointer is only valid till the polygon is next modified.  Use
     253             :  * the OGRGeometry::clone() method to make a separate copy within the
     254             :  * application.
     255             :  *
     256             :  * Relates to the SFCOM IPolygon::get_InternalRing() method.
     257             :  *
     258             :  * @param iRing internal ring index from 0 to getNumInteriorRings() - 1.
     259             :  *
     260             :  * @return pointer to interior ring.  May be NULL.
     261             :  */
     262             : 
     263         703 : const OGRLinearRing *OGRPolygon::getInteriorRing(int iRing) const
     264             : 
     265             : {
     266         703 :     if (iRing < 0 || iRing >= oCC.nCurveCount - 1)
     267           0 :         return nullptr;
     268             : 
     269         703 :     return oCC.papoCurves[iRing + 1]->toLinearRing();
     270             : }
     271             : 
     272             : /************************************************************************/
     273             : /*                          stealInteriorRing()                         */
     274             : /************************************************************************/
     275             : 
     276             : /**
     277             :  * \brief "Steal" reference to indicated interior ring.
     278             :  *
     279             :  * After the call to that function, only call to stealInteriorRing() or
     280             :  * destruction of the OGRPolygon is valid. Other operations may crash.
     281             :  *
     282             :  * @param iRing internal ring index from 0 to getNumInteriorRings() - 1.
     283             :  * @return pointer to interior ring.  May be NULL.
     284             :  */
     285             : 
     286           8 : OGRLinearRing *OGRPolygon::stealInteriorRing(int iRing)
     287             : {
     288           8 :     if (iRing < 0 || iRing >= oCC.nCurveCount - 1)
     289           0 :         return nullptr;
     290           8 :     OGRLinearRing *poRet = oCC.papoCurves[iRing + 1]->toLinearRing();
     291           8 :     oCC.papoCurves[iRing + 1] = nullptr;
     292           8 :     return poRet;
     293             : }
     294             : 
     295             : /*! @cond Doxygen_Suppress */
     296             : 
     297             : /************************************************************************/
     298             : /*                            isRingCorrectType()                               */
     299             : /************************************************************************/
     300      204946 : bool OGRPolygon::isRingCorrectType(const OGRCurve *poRing) const
     301             : {
     302      204946 :     return poRing != nullptr && EQUAL(poRing->getGeometryName(), "LINEARRING");
     303             : }
     304             : 
     305             : /************************************************************************/
     306             : /*                            checkRing()                               */
     307             : /************************************************************************/
     308             : 
     309      204940 : bool OGRPolygon::checkRing(const OGRCurve *poNewRing) const
     310             : {
     311      204940 :     if (!isRingCorrectType(poNewRing))
     312             :     {
     313           3 :         CPLError(CE_Failure, CPLE_AppDefined,
     314             :                  "Wrong curve type. Expected LINEARRING.");
     315           3 :         return false;
     316             :     }
     317             : 
     318      204936 :     if (!poNewRing->IsEmpty() && !poNewRing->get_IsClosed())
     319             :     {
     320             :         // This configuration option name must be the same as in
     321             :         // OGRCurvePolygon::checkRing()
     322             :         const char *pszEnvVar =
     323          79 :             CPLGetConfigOption("OGR_GEOMETRY_ACCEPT_UNCLOSED_RING", nullptr);
     324          79 :         if (pszEnvVar != nullptr && !CPLTestBool(pszEnvVar))
     325             :         {
     326           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Non closed ring detected.");
     327           0 :             return false;
     328             :         }
     329             :         else
     330             :         {
     331          79 :             CPLError(CE_Warning, CPLE_AppDefined, "Non closed ring detected.%s",
     332             :                      pszEnvVar == nullptr
     333             :                          ? " To avoid accepting it, set the "
     334             :                            "OGR_GEOMETRY_ACCEPT_UNCLOSED_RING configuration "
     335             :                            "option to NO"
     336             :                          : "");
     337             :         }
     338             :     }
     339             : 
     340      204935 :     return true;
     341             : }
     342             : 
     343             : /*! @endcond */
     344             : 
     345             : /************************************************************************/
     346             : /*                              WkbSize()                               */
     347             : /*                                                                      */
     348             : /*      Return the size of this object in well known binary             */
     349             : /*      representation including the byte order, and type information.  */
     350             : /************************************************************************/
     351             : 
     352      962623 : size_t OGRPolygon::WkbSize() const
     353             : 
     354             : {
     355      962623 :     size_t nSize = 9;
     356             : 
     357     1928460 :     for (auto &&poRing : *this)
     358             :     {
     359      965836 :         nSize += poRing->_WkbSize(flags);
     360             :     }
     361             : 
     362      962576 :     return nSize;
     363             : }
     364             : 
     365             : /************************************************************************/
     366             : /*                           importFromWkb()                            */
     367             : /*                                                                      */
     368             : /*      Initialize from serialized stream in well known binary          */
     369             : /*      format.                                                         */
     370             : /************************************************************************/
     371             : 
     372       42032 : OGRErr OGRPolygon::importFromWkb(const unsigned char *pabyData, size_t nSize,
     373             :                                  OGRwkbVariant eWkbVariant,
     374             :                                  size_t &nBytesConsumedOut)
     375             : 
     376             : {
     377       42032 :     OGRwkbByteOrder eByteOrder = wkbNDR;
     378       42032 :     size_t nDataOffset = 0;
     379             : 
     380       42032 :     if (oCC.nCurveCount == 1 && flags == 0 && nSize >= 9 &&
     381          25 :         pabyData[0] == wkbNDR &&
     382          25 :         memcmp(pabyData + 1, "\x03\x00\x00\x00\x01\x00\x00\x00", 8) == 0)
     383             :     {
     384             :         // Optimization to import a Intel-ordered 1-ring polygon on
     385             :         // top of an existing 1-ring polygon, to save dynamic memory
     386             :         // allocations.
     387          24 :         size_t nBytesConsumedRing = 0;
     388          24 :         nDataOffset = 9;
     389             :         // cppcheck-suppress knownConditionTrueFalse
     390          24 :         if (nSize != static_cast<size_t>(-1))
     391          22 :             nSize -= nDataOffset;
     392             :         OGRErr eErr =
     393          24 :             cpl::down_cast<OGRLinearRing *>(oCC.papoCurves[0])
     394          48 :                 ->_importFromWkb(eByteOrder, flags, pabyData + nDataOffset,
     395          24 :                                  nSize, nBytesConsumedRing);
     396          24 :         if (eErr == OGRERR_NONE)
     397             :         {
     398          22 :             nBytesConsumedOut = nDataOffset + nBytesConsumedRing;
     399             :         }
     400             :         else
     401             :         {
     402           2 :             empty();
     403             :         }
     404             : 
     405          24 :         return eErr;
     406             :     }
     407             : 
     408       42008 :     nBytesConsumedOut = 0;
     409             : 
     410             :     // coverity[tainted_data]
     411       42008 :     OGRErr eErr = oCC.importPreambleFromWkb(this, pabyData, nSize, nDataOffset,
     412             :                                             eByteOrder, 4, eWkbVariant);
     413       42008 :     if (eErr != OGRERR_NONE)
     414         335 :         return eErr;
     415             : 
     416             :     /* -------------------------------------------------------------------- */
     417             :     /*      Get the rings.                                                  */
     418             :     /* -------------------------------------------------------------------- */
     419       82585 :     for (int iRing = 0; iRing < oCC.nCurveCount; iRing++)
     420             :     {
     421       41939 :         OGRLinearRing *poLR = new OGRLinearRing();
     422       41940 :         oCC.papoCurves[iRing] = poLR;
     423       41940 :         size_t nBytesConsumedRing = 0;
     424       83879 :         eErr = poLR->_importFromWkb(eByteOrder, flags, pabyData + nDataOffset,
     425       41940 :                                     nSize, nBytesConsumedRing);
     426       41939 :         if (eErr != OGRERR_NONE)
     427             :         {
     428        1027 :             delete oCC.papoCurves[iRing];
     429        1027 :             oCC.nCurveCount = iRing;
     430        1027 :             return eErr;
     431             :         }
     432             : 
     433       40912 :         CPLAssert(nBytesConsumedRing > 0);
     434       40912 :         if (nSize != static_cast<size_t>(-1))
     435             :         {
     436       40901 :             CPLAssert(nSize >= nBytesConsumedRing);
     437       40901 :             nSize -= nBytesConsumedRing;
     438             :         }
     439             : 
     440       40912 :         nDataOffset += nBytesConsumedRing;
     441             :     }
     442       40646 :     nBytesConsumedOut = nDataOffset;
     443             : 
     444       40646 :     return OGRERR_NONE;
     445             : }
     446             : 
     447             : /************************************************************************/
     448             : /*                            exportToWkb()                             */
     449             : /*                                                                      */
     450             : /*      Build a well known binary representation of this object.        */
     451             : /************************************************************************/
     452             : 
     453      258973 : OGRErr OGRPolygon::exportToWkb(unsigned char *pabyData,
     454             :                                const OGRwkbExportOptions *psOptions) const
     455             : 
     456             : {
     457      258973 :     if (psOptions == nullptr)
     458             :     {
     459             :         static const OGRwkbExportOptions defaultOptions;
     460           0 :         psOptions = &defaultOptions;
     461             :     }
     462             : 
     463             :     /* -------------------------------------------------------------------- */
     464             :     /*      Set the byte order.                                             */
     465             :     /* -------------------------------------------------------------------- */
     466      258973 :     pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER(
     467             :         static_cast<unsigned char>(psOptions->eByteOrder));
     468             : 
     469             :     /* -------------------------------------------------------------------- */
     470             :     /*      Set the geometry feature type.                                  */
     471             :     /* -------------------------------------------------------------------- */
     472      258973 :     GUInt32 nGType = getGeometryType();
     473             : 
     474      258980 :     if (psOptions->eWkbVariant == wkbVariantPostGIS1)
     475             :     {
     476         307 :         nGType = wkbFlatten(nGType);
     477         307 :         if (Is3D())
     478             :             // Explicitly set wkb25DBit.
     479         294 :             nGType =
     480         294 :                 static_cast<OGRwkbGeometryType>(nGType | wkb25DBitInternalUse);
     481         307 :         if (IsMeasured())
     482           0 :             nGType = static_cast<OGRwkbGeometryType>(nGType | 0x40000000);
     483             :     }
     484      258673 :     else if (psOptions->eWkbVariant == wkbVariantIso)
     485      125359 :         nGType = getIsoGeometryType();
     486             : 
     487      258980 :     if (OGR_SWAP(psOptions->eByteOrder))
     488             :     {
     489          20 :         nGType = CPL_SWAP32(nGType);
     490             :     }
     491             : 
     492      258980 :     memcpy(pabyData + 1, &nGType, 4);
     493             : 
     494             :     /* -------------------------------------------------------------------- */
     495             :     /*      Copy in the raw data.                                           */
     496             :     /* -------------------------------------------------------------------- */
     497      258980 :     if (OGR_SWAP(psOptions->eByteOrder))
     498             :     {
     499          20 :         const int nCount = CPL_SWAP32(oCC.nCurveCount);
     500          20 :         memcpy(pabyData + 5, &nCount, 4);
     501             :     }
     502             :     else
     503             :     {
     504      258960 :         memcpy(pabyData + 5, &oCC.nCurveCount, 4);
     505             :     }
     506             : 
     507             :     /* ==================================================================== */
     508             :     /*      Serialize each of the rings.                                    */
     509             :     /* ==================================================================== */
     510      258980 :     size_t nOffset = 9;
     511             : 
     512      518198 :     for (auto &&poRing : *this)
     513             :     {
     514      259221 :         poRing->_exportToWkb(flags, pabyData + nOffset, psOptions);
     515             : 
     516      259217 :         nOffset += poRing->_WkbSize(flags);
     517             :     }
     518             : 
     519      258964 :     return OGRERR_NONE;
     520             : }
     521             : 
     522             : /************************************************************************/
     523             : /*                           importFromWkt()                            */
     524             : /*                                                                      */
     525             : /*      Instantiate from well known text format.  Currently this is     */
     526             : /*      `POLYGON ((x y, x y, ...),(x y, ...),...)'.                     */
     527             : /************************************************************************/
     528             : 
     529       16290 : OGRErr OGRPolygon::importFromWkt(const char **ppszInput)
     530             : 
     531             : {
     532       16290 :     int bHasZ = FALSE;
     533       16290 :     int bHasM = FALSE;
     534       16290 :     bool bIsEmpty = false;
     535       16290 :     OGRErr eErr = importPreambleFromWkt(ppszInput, &bHasZ, &bHasM, &bIsEmpty);
     536       16290 :     flags = 0;
     537       16290 :     if (eErr != OGRERR_NONE)
     538           5 :         return eErr;
     539       16285 :     if (bHasZ)
     540         170 :         flags |= OGR_G_3D;
     541       16285 :     if (bHasM)
     542          78 :         flags |= OGR_G_MEASURED;
     543       16285 :     if (bIsEmpty)
     544          88 :         return OGRERR_NONE;
     545             : 
     546       16197 :     OGRRawPoint *paoPoints = nullptr;
     547       16197 :     int nMaxPoints = 0;
     548       16197 :     double *padfZ = nullptr;
     549             : 
     550       32394 :     eErr = importFromWKTListOnly(ppszInput, bHasZ, bHasM, paoPoints, nMaxPoints,
     551       16197 :                                  padfZ);
     552             : 
     553       16197 :     CPLFree(paoPoints);
     554       16197 :     CPLFree(padfZ);
     555             : 
     556       16197 :     return eErr;
     557             : }
     558             : 
     559             : /*! @cond Doxygen_Suppress */
     560             : /************************************************************************/
     561             : /*                        importFromWKTListOnly()                       */
     562             : /*                                                                      */
     563             : /*      Instantiate from "((x y, x y, ...),(x y, ...),...)"             */
     564             : /************************************************************************/
     565             : 
     566       17671 : OGRErr OGRPolygon::importFromWKTListOnly(const char **ppszInput, int bHasZ,
     567             :                                          int bHasM, OGRRawPoint *&paoPoints,
     568             :                                          int &nMaxPoints, double *&padfZ)
     569             : 
     570             : {
     571       17671 :     char szToken[OGR_WKT_TOKEN_MAX] = {};
     572       17671 :     const char *pszInput = *ppszInput;
     573             : 
     574             :     // Skip first '('.
     575       17671 :     pszInput = OGRWktReadToken(pszInput, szToken);
     576       17671 :     if (EQUAL(szToken, "EMPTY"))
     577             :     {
     578           0 :         *ppszInput = pszInput;
     579           0 :         return OGRERR_NONE;
     580             :     }
     581       17671 :     if (!EQUAL(szToken, "("))
     582           0 :         return OGRERR_CORRUPT_DATA;
     583             : 
     584             :     /* ==================================================================== */
     585             :     /*      Read each ring in turn.  Note that we try to reuse the same     */
     586             :     /*      point list buffer from ring to ring to cut down on              */
     587             :     /*      allocate/deallocate overhead.                                   */
     588             :     /* ==================================================================== */
     589       17671 :     int nMaxRings = 0;
     590       17671 :     double *padfM = nullptr;
     591             : 
     592         386 :     do
     593             :     {
     594       18057 :         const char *pszNext = OGRWktReadToken(pszInput, szToken);
     595       18057 :         if (EQUAL(szToken, "EMPTY"))
     596             :         {
     597             :             /* --------------------------------------------------------------------
     598             :              */
     599             :             /*      Do we need to grow the ring array? */
     600             :             /* --------------------------------------------------------------------
     601             :              */
     602          26 :             if (oCC.nCurveCount == nMaxRings)
     603             :             {
     604          23 :                 nMaxRings = nMaxRings * 2 + 1;
     605          23 :                 oCC.papoCurves = static_cast<OGRCurve **>(CPLRealloc(
     606          23 :                     oCC.papoCurves, nMaxRings * sizeof(OGRLinearRing *)));
     607             :             }
     608          26 :             oCC.papoCurves[oCC.nCurveCount] = new OGRLinearRing();
     609          26 :             oCC.nCurveCount++;
     610             : 
     611          26 :             pszInput = OGRWktReadToken(pszNext, szToken);
     612          26 :             if (!EQUAL(szToken, ","))
     613          13 :                 break;
     614             : 
     615          13 :             continue;
     616             :         }
     617             : 
     618             :         /* --------------------------------------------------------------------
     619             :          */
     620             :         /*      Read points for one ring from input. */
     621             :         /* --------------------------------------------------------------------
     622             :          */
     623       18031 :         int nPoints = 0;
     624       18031 :         int flagsFromInput = flags;
     625       18031 :         if (flagsFromInput == 0)
     626             :         {
     627             :             // Flags was not set, this is not called by us.
     628       17768 :             if (bHasM)
     629         141 :                 flagsFromInput |= OGR_G_MEASURED;
     630       17768 :             if (bHasZ)
     631         362 :                 flagsFromInput |= OGR_G_3D;
     632             :         }
     633             : 
     634       18031 :         pszInput = OGRWktReadPointsM(pszInput, &paoPoints, &padfZ, &padfM,
     635             :                                      &flagsFromInput, &nMaxPoints, &nPoints);
     636       18031 :         if (pszInput == nullptr || nPoints == 0)
     637             :         {
     638          33 :             CPLFree(padfM);
     639          33 :             return OGRERR_CORRUPT_DATA;
     640             :         }
     641       17998 :         if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
     642             :         {
     643         838 :             flags |= OGR_G_3D;
     644         838 :             bHasZ = TRUE;
     645             :         }
     646       17998 :         if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
     647             :         {
     648         141 :             flags |= OGR_G_MEASURED;
     649         141 :             bHasM = TRUE;
     650             :         }
     651             : 
     652             :         /* --------------------------------------------------------------------
     653             :          */
     654             :         /*      Do we need to grow the ring array? */
     655             :         /* --------------------------------------------------------------------
     656             :          */
     657       17998 :         if (oCC.nCurveCount == nMaxRings)
     658             :         {
     659       17978 :             nMaxRings = nMaxRings * 2 + 1;
     660       17978 :             oCC.papoCurves = static_cast<OGRCurve **>(CPLRealloc(
     661       17978 :                 oCC.papoCurves, nMaxRings * sizeof(OGRLinearRing *)));
     662             :         }
     663             : 
     664             :         /* --------------------------------------------------------------------
     665             :          */
     666             :         /*      Create the new ring, and assign to ring list. */
     667             :         /* --------------------------------------------------------------------
     668             :          */
     669       17998 :         OGRLinearRing *poLR = new OGRLinearRing();
     670       17998 :         oCC.papoCurves[oCC.nCurveCount] = poLR;
     671             : 
     672       17998 :         if (bHasM && bHasZ)
     673         121 :             poLR->setPoints(nPoints, paoPoints, padfZ, padfM);
     674       17877 :         else if (bHasM)
     675         109 :             poLR->setPointsM(nPoints, paoPoints, padfM);
     676       17768 :         else if (bHasZ)
     677         930 :             poLR->setPoints(nPoints, paoPoints, padfZ);
     678             :         else
     679       16838 :             poLR->setPoints(nPoints, paoPoints);
     680             : 
     681       17998 :         oCC.nCurveCount++;
     682             : 
     683             :         /* --------------------------------------------------------------------
     684             :          */
     685             :         /*      Read the delimiter following the ring. */
     686             :         /* --------------------------------------------------------------------
     687             :          */
     688             : 
     689       17998 :         pszInput = OGRWktReadToken(pszInput, szToken);
     690       18011 :     } while (szToken[0] == ',');
     691             : 
     692       17638 :     CPLFree(padfM);
     693             : 
     694             :     /* -------------------------------------------------------------------- */
     695             :     /*      freak if we don't get a closing bracket.                        */
     696             :     /* -------------------------------------------------------------------- */
     697             : 
     698       17638 :     if (szToken[0] != ')')
     699           5 :         return OGRERR_CORRUPT_DATA;
     700             : 
     701       17633 :     *ppszInput = pszInput;
     702       17633 :     return OGRERR_NONE;
     703             : }
     704             : 
     705             : /*! @endcond */
     706             : 
     707             : /************************************************************************/
     708             : /*                            exportToWkt()                             */
     709             : /*                                                                      */
     710             : /*      Translate this structure into its well known text format        */
     711             : /*      equivalent.  This could be made a lot more CPU efficient.       */
     712             : /************************************************************************/
     713             : 
     714        2308 : std::string OGRPolygon::exportToWkt(const OGRWktOptions &opts,
     715             :                                     OGRErr *err) const
     716             : {
     717        4616 :     std::string wkt;
     718             :     /* -------------------------------------------------------------------- */
     719             :     /*      If we have no valid exterior ring, return POLYGON EMPTY.        */
     720             :     /* -------------------------------------------------------------------- */
     721        2308 :     wkt = getGeometryName();
     722        2308 :     wkt += wktTypeString(opts.variant);
     723        2308 :     if (getExteriorRing() == nullptr || getExteriorRing()->IsEmpty())
     724          93 :         wkt += "EMPTY";
     725             : 
     726             :     /* -------------------------------------------------------------------- */
     727             :     /*      Build a list of strings containing the stuff for each ring.     */
     728             :     /* -------------------------------------------------------------------- */
     729             : 
     730             :     else
     731             :     {
     732             :         try
     733             :         {
     734        2215 :             bool first(true);
     735        2215 :             wkt += '(';
     736        4661 :             for (int iRing = 0; iRing < oCC.nCurveCount; iRing++)
     737             :             {
     738        2446 :                 OGRLinearRing *poLR = oCC.papoCurves[iRing]->toLinearRing();
     739        2446 :                 if (poLR->getNumPoints())
     740             :                 {
     741        2434 :                     if (!first)
     742         219 :                         wkt += ',';
     743        2434 :                     first = false;
     744        2434 :                     OGRErr subgeomErr = OGRERR_NONE;
     745        2434 :                     std::string tempWkt = poLR->exportToWkt(opts, &subgeomErr);
     746        2434 :                     if (subgeomErr != OGRERR_NONE)
     747             :                     {
     748           0 :                         if (err)
     749           0 :                             *err = subgeomErr;
     750           0 :                         return std::string();
     751             :                     }
     752             : 
     753             :                     // Remove leading "LINEARRING..."
     754        2434 :                     wkt += tempWkt.substr(tempWkt.find_first_of('('));
     755             :                 }
     756             :             }
     757        2215 :             wkt += ')';
     758             :         }
     759           0 :         catch (const std::bad_alloc &e)
     760             :         {
     761           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
     762           0 :             if (err)
     763           0 :                 *err = OGRERR_FAILURE;
     764           0 :             return std::string();
     765             :         }
     766             :     }
     767             : 
     768        2308 :     if (err)
     769        2280 :         *err = OGRERR_NONE;
     770        2308 :     return wkt;
     771             : }
     772             : 
     773             : /************************************************************************/
     774             : /*                           IsPointOnSurface()                           */
     775             : /************************************************************************/
     776             : 
     777             : /** Return whether the point is on the surface.
     778             :  * @return TRUE or FALSE
     779             :  */
     780           5 : OGRBoolean OGRPolygon::IsPointOnSurface(const OGRPoint *pt) const
     781             : {
     782           5 :     if (nullptr == pt)
     783           0 :         return FALSE;
     784             : 
     785           5 :     bool bOnSurface = false;
     786             :     // The point must be in the outer ring, but not in the inner rings
     787           5 :     int iRing = 0;
     788           8 :     for (auto &&poRing : *this)
     789             :     {
     790           5 :         if (poRing->isPointInRing(pt))
     791             :         {
     792           3 :             if (iRing == 0)
     793             :             {
     794           2 :                 bOnSurface = true;
     795             :             }
     796             :             else
     797             :             {
     798           1 :                 return false;
     799             :             }
     800             :         }
     801             :         else
     802             :         {
     803           2 :             if (iRing == 0)
     804             :             {
     805           1 :                 return false;
     806             :             }
     807             :         }
     808           3 :         iRing++;
     809             :     }
     810             : 
     811           3 :     return bOnSurface;
     812             : }
     813             : 
     814             : /************************************************************************/
     815             : /*                             closeRings()                             */
     816             : /************************************************************************/
     817             : 
     818        1157 : void OGRPolygon::closeRings()
     819             : 
     820             : {
     821        2347 :     for (auto &&poRing : *this)
     822        1190 :         poRing->closeRings();
     823        1157 : }
     824             : 
     825             : /************************************************************************/
     826             : /*                           CurvePolyToPoly()                          */
     827             : /************************************************************************/
     828             : 
     829             : OGRPolygon *
     830           0 : OGRPolygon::CurvePolyToPoly(CPL_UNUSED double dfMaxAngleStepSizeDegrees,
     831             :                             CPL_UNUSED const char *const *papszOptions) const
     832             : {
     833           0 :     return clone();
     834             : }
     835             : 
     836             : /************************************************************************/
     837             : /*                         hasCurveGeometry()                           */
     838             : /************************************************************************/
     839             : 
     840      134165 : OGRBoolean OGRPolygon::hasCurveGeometry(CPL_UNUSED int bLookForNonLinear) const
     841             : {
     842      134165 :     return FALSE;
     843             : }
     844             : 
     845             : /************************************************************************/
     846             : /*                         getLinearGeometry()                        */
     847             : /************************************************************************/
     848             : 
     849             : OGRGeometry *
     850          34 : OGRPolygon::getLinearGeometry(double dfMaxAngleStepSizeDegrees,
     851             :                               const char *const *papszOptions) const
     852             : {
     853          34 :     return OGRGeometry::getLinearGeometry(dfMaxAngleStepSizeDegrees,
     854          34 :                                           papszOptions);
     855             : }
     856             : 
     857             : /************************************************************************/
     858             : /*                             getCurveGeometry()                       */
     859             : /************************************************************************/
     860             : 
     861          18 : OGRGeometry *OGRPolygon::getCurveGeometry(const char *const *papszOptions) const
     862             : {
     863          18 :     OGRCurvePolygon *poCC = new OGRCurvePolygon();
     864          18 :     poCC->assignSpatialReference(getSpatialReference());
     865          18 :     bool bHasCurveGeometry = false;
     866          35 :     for (auto &&poRing : *this)
     867             :     {
     868          17 :         auto poSubGeom = poRing->getCurveGeometry(papszOptions);
     869          17 :         if (wkbFlatten(poSubGeom->getGeometryType()) != wkbLineString)
     870          15 :             bHasCurveGeometry = true;
     871          17 :         poCC->addRingDirectly(poSubGeom->toCurve());
     872             :     }
     873          18 :     if (!bHasCurveGeometry)
     874             :     {
     875           3 :         delete poCC;
     876           3 :         return clone();
     877             :     }
     878          15 :     return poCC;
     879             : }
     880             : 
     881             : /*! @cond Doxygen_Suppress */
     882             : /************************************************************************/
     883             : /*                        CastToCurvePolygon()                          */
     884             : /************************************************************************/
     885             : 
     886             : /**
     887             :  * \brief Cast to curve polygon.
     888             :  *
     889             :  * The passed in geometry is consumed and a new one returned .
     890             :  *
     891             :  * @param poPoly the input geometry - ownership is passed to the method.
     892             :  * @return new geometry.
     893             :  */
     894             : 
     895          21 : OGRCurvePolygon *OGRPolygon::CastToCurvePolygon(OGRPolygon *poPoly)
     896             : {
     897          21 :     OGRCurvePolygon *poCP = new OGRCurvePolygon();
     898          21 :     poCP->set3D(poPoly->Is3D());
     899          21 :     poCP->setMeasured(poPoly->IsMeasured());
     900          21 :     poCP->assignSpatialReference(poPoly->getSpatialReference());
     901          21 :     poCP->oCC.nCurveCount = poPoly->oCC.nCurveCount;
     902          21 :     poCP->oCC.papoCurves = poPoly->oCC.papoCurves;
     903          21 :     poPoly->oCC.nCurveCount = 0;
     904          21 :     poPoly->oCC.papoCurves = nullptr;
     905             : 
     906          48 :     for (auto &&poRing : *poCP)
     907             :     {
     908          27 :         poRing = OGRLinearRing::CastToLineString(poRing->toLinearRing());
     909             :     }
     910             : 
     911          21 :     delete poPoly;
     912          21 :     return poCP;
     913             : }
     914             : 
     915             : /************************************************************************/
     916             : /*                      GetCasterToPolygon()                            */
     917             : /************************************************************************/
     918             : 
     919          71 : static OGRPolygon *CasterToPolygon(OGRSurface *poSurface)
     920             : {
     921          71 :     return poSurface->toPolygon();
     922             : }
     923             : 
     924          71 : OGRSurfaceCasterToPolygon OGRPolygon::GetCasterToPolygon() const
     925             : {
     926          71 :     return ::CasterToPolygon;
     927             : }
     928             : 
     929             : /************************************************************************/
     930             : /*                      OGRSurfaceCasterToCurvePolygon()                */
     931             : /************************************************************************/
     932             : 
     933          21 : OGRCurvePolygon *OGRPolygon::CasterToCurvePolygon(OGRSurface *poSurface)
     934             : {
     935          21 :     return OGRPolygon::CastToCurvePolygon(poSurface->toPolygon());
     936             : }
     937             : 
     938          21 : OGRSurfaceCasterToCurvePolygon OGRPolygon::GetCasterToCurvePolygon() const
     939             : {
     940          21 :     return OGRPolygon::CasterToCurvePolygon;
     941             : }
     942             : 
     943             : /*! @endcond */

Generated by: LCOV version 1.14