LCOV - code coverage report
Current view: top level - ogr - ogrpolygon.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 271 294 92.2 %
Date: 2024-05-04 12:52:34 Functions: 27 28 96.4 %

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

Generated by: LCOV version 1.14