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

Generated by: LCOV version 1.14