LCOV - code coverage report
Current view: top level - ogr - ogrpolygon.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 275 295 93.2 %
Date: 2024-11-21 22:18:42 Functions: 28 29 96.6 %

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

Generated by: LCOV version 1.14