LCOV - code coverage report
Current view: top level - ogr - ogrpolygon.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 286 309 92.6 %
Date: 2025-02-20 10:14:44 Functions: 29 30 96.7 %

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

Generated by: LCOV version 1.14