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

Generated by: LCOV version 1.14