LCOV - code coverage report
Current view: top level - ogr - ogrpolyhedralsurface.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 263 305 86.2 %
Date: 2024-05-03 15:49:35 Functions: 37 44 84.1 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * $Id$
       3             :  *
       4             :  * Project:  OpenGIS Simple Features Reference Implementation
       5             :  * Purpose:  The OGRPolyhedralSurface geometry class.
       6             :  * Author:   Avyav Kumar Singh <avyavkumar at gmail dot com>
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2016, Avyav Kumar Singh <avyavkumar at gmail dot com>
      10             :  * Copyright (c) 2016, Even Rouault <even.roauult at spatialys.com>
      11             :  *
      12             :  * Permission is hereby granted, free of charge, to any person obtaining a
      13             :  * copy of this software and associated documentation files (the "Software"),
      14             :  * to deal in the Software without restriction, including without limitation
      15             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16             :  * and/or sell copies of the Software, and to permit persons to whom the
      17             :  * Software is furnished to do so, subject to the following conditions:
      18             :  *
      19             :  * The above copyright notice and this permission notice shall be included
      20             :  * in all copies or substantial portions of the Software.
      21             :  *
      22             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28             :  * DEALINGS IN THE SOFTWARE.
      29             :  ****************************************************************************/
      30             : 
      31             : #include "ogr_geometry.h"
      32             : #include "ogr_p.h"
      33             : #include "ogr_sfcgal.h"
      34             : #include "ogr_api.h"
      35             : #include "ogr_libs.h"
      36             : 
      37             : #include <new>
      38             : 
      39             : /************************************************************************/
      40             : /*                         OGRPolyhedralSurface()                       */
      41             : /************************************************************************/
      42             : 
      43             : /**
      44             :  * \brief Create an empty PolyhedralSurface
      45             :  */
      46             : 
      47             : OGRPolyhedralSurface::OGRPolyhedralSurface() = default;
      48             : 
      49             : /************************************************************************/
      50             : /*         OGRPolyhedralSurface( const OGRPolyhedralSurface& )          */
      51             : /************************************************************************/
      52             : 
      53             : /**
      54             :  * \brief Copy constructor.
      55             :  *
      56             :  */
      57             : 
      58             : OGRPolyhedralSurface::OGRPolyhedralSurface(const OGRPolyhedralSurface &) =
      59             :     default;
      60             : 
      61             : /************************************************************************/
      62             : /*                        ~OGRPolyhedralSurface()                       */
      63             : /************************************************************************/
      64             : 
      65             : /**
      66             :  * \brief Destructor
      67             :  *
      68             :  */
      69             : 
      70             : OGRPolyhedralSurface::~OGRPolyhedralSurface() = default;
      71             : 
      72             : /************************************************************************/
      73             : /*                 operator=( const OGRPolyhedralSurface&)              */
      74             : /************************************************************************/
      75             : 
      76             : /**
      77             :  * \brief Assignment operator.
      78             :  *
      79             :  */
      80             : 
      81             : OGRPolyhedralSurface &
      82           5 : OGRPolyhedralSurface::operator=(const OGRPolyhedralSurface &other)
      83             : {
      84           5 :     if (this != &other)
      85             :     {
      86           4 :         OGRSurface::operator=(other);
      87           4 :         oMP = other.oMP;
      88             :     }
      89           5 :     return *this;
      90             : }
      91             : 
      92             : /************************************************************************/
      93             : /*                               clone()                                */
      94             : /************************************************************************/
      95             : 
      96          39 : OGRPolyhedralSurface *OGRPolyhedralSurface::clone() const
      97             : 
      98             : {
      99          39 :     return new (std::nothrow) OGRPolyhedralSurface(*this);
     100             : }
     101             : 
     102             : /************************************************************************/
     103             : /*                          getGeometryName()                           */
     104             : /************************************************************************/
     105             : 
     106         126 : const char *OGRPolyhedralSurface::getGeometryName() const
     107             : {
     108         126 :     return "POLYHEDRALSURFACE";
     109             : }
     110             : 
     111             : /************************************************************************/
     112             : /*                          getGeometryType()                           */
     113             : /************************************************************************/
     114             : 
     115             : /**
     116             :  * \brief Returns the WKB Type of PolyhedralSurface
     117             :  *
     118             :  */
     119             : 
     120       17732 : OGRwkbGeometryType OGRPolyhedralSurface::getGeometryType() const
     121             : {
     122       17732 :     if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
     123       17472 :         return wkbPolyhedralSurfaceZM;
     124         260 :     else if (flags & OGR_G_MEASURED)
     125           4 :         return wkbPolyhedralSurfaceM;
     126         256 :     else if (flags & OGR_G_3D)
     127         172 :         return wkbPolyhedralSurfaceZ;
     128             :     else
     129          84 :         return wkbPolyhedralSurface;
     130             : }
     131             : 
     132             : /************************************************************************/
     133             : /*                              WkbSize()                               */
     134             : /************************************************************************/
     135             : 
     136        6102 : size_t OGRPolyhedralSurface::WkbSize() const
     137             : {
     138        6102 :     size_t nSize = 9;
     139       18130 :     for (auto &&poSubGeom : *this)
     140             :     {
     141       12028 :         nSize += poSubGeom->WkbSize();
     142             :     }
     143        6102 :     return nSize;
     144             : }
     145             : 
     146             : /************************************************************************/
     147             : /*                            getDimension()                            */
     148             : /************************************************************************/
     149             : 
     150           2 : int OGRPolyhedralSurface::getDimension() const
     151             : {
     152           2 :     return 2;
     153             : }
     154             : 
     155             : /************************************************************************/
     156             : /*                               empty()                                */
     157             : /************************************************************************/
     158             : 
     159       14583 : void OGRPolyhedralSurface::empty()
     160             : {
     161       14583 :     if (oMP.papoGeoms != nullptr)
     162             :     {
     163          12 :         for (auto &&poSubGeom : *this)
     164             :         {
     165           9 :             delete poSubGeom;
     166             :         }
     167           3 :         CPLFree(oMP.papoGeoms);
     168             :     }
     169       14583 :     oMP.nGeomCount = 0;
     170       14583 :     oMP.papoGeoms = nullptr;
     171       14583 : }
     172             : 
     173             : /************************************************************************/
     174             : /*                            getEnvelope()                             */
     175             : /************************************************************************/
     176             : 
     177          70 : void OGRPolyhedralSurface::getEnvelope(OGREnvelope *psEnvelope) const
     178             : {
     179          70 :     oMP.getEnvelope(psEnvelope);
     180          70 : }
     181             : 
     182             : /************************************************************************/
     183             : /*                            getEnvelope()                             */
     184             : /************************************************************************/
     185             : 
     186         375 : void OGRPolyhedralSurface::getEnvelope(OGREnvelope3D *psEnvelope) const
     187             : {
     188         375 :     oMP.getEnvelope(psEnvelope);
     189         375 : }
     190             : 
     191             : /************************************************************************/
     192             : /*                           importFromWkb()                            */
     193             : /************************************************************************/
     194             : 
     195       13597 : OGRErr OGRPolyhedralSurface::importFromWkb(const unsigned char *pabyData,
     196             :                                            size_t nSize,
     197             :                                            OGRwkbVariant eWkbVariant,
     198             :                                            size_t &nBytesConsumedOut)
     199             : {
     200       13597 :     nBytesConsumedOut = 0;
     201       13597 :     oMP.nGeomCount = 0;
     202       13597 :     OGRwkbByteOrder eByteOrder = wkbXDR;
     203       13597 :     size_t nDataOffset = 0;
     204       27194 :     OGRErr eErr = importPreambleOfCollectionFromWkb(
     205       13597 :         pabyData, nSize, nDataOffset, eByteOrder, 9, oMP.nGeomCount,
     206             :         eWkbVariant);
     207             : 
     208       13597 :     if (eErr != OGRERR_NONE)
     209         126 :         return eErr;
     210             : 
     211       13471 :     oMP.papoGeoms = reinterpret_cast<OGRGeometry **>(
     212       13471 :         VSI_CALLOC_VERBOSE(sizeof(void *), oMP.nGeomCount));
     213       13471 :     if (oMP.nGeomCount != 0 && oMP.papoGeoms == nullptr)
     214             :     {
     215           0 :         oMP.nGeomCount = 0;
     216           0 :         return OGRERR_NOT_ENOUGH_MEMORY;
     217             :     }
     218             : 
     219             :     /* -------------------------------------------------------------------- */
     220             :     /*      Get the Geoms.                                                  */
     221             :     /* -------------------------------------------------------------------- */
     222       36986 :     for (int iGeom = 0; iGeom < oMP.nGeomCount; iGeom++)
     223             :     {
     224             :         // Parse the polygons
     225       25827 :         const unsigned char *pabySubData = pabyData + nDataOffset;
     226       25827 :         if (nSize < 9 && nSize != static_cast<size_t>(-1))
     227        2312 :             return OGRERR_NOT_ENOUGH_DATA;
     228             : 
     229             :         OGRwkbGeometryType eSubGeomType;
     230       25807 :         eErr = OGRReadWKBGeometryType(pabySubData, eWkbVariant, &eSubGeomType);
     231       25807 :         if (eErr != OGRERR_NONE)
     232         254 :             return eErr;
     233             : 
     234       25553 :         if (!isCompatibleSubType(eSubGeomType))
     235             :         {
     236           0 :             oMP.nGeomCount = iGeom;
     237           0 :             CPLDebug("OGR",
     238             :                      "Cannot add geometry of type (%d) to "
     239             :                      "geometry of type (%d)",
     240           0 :                      eSubGeomType, getGeometryType());
     241           0 :             return OGRERR_CORRUPT_DATA;
     242             :         }
     243             : 
     244       25553 :         OGRGeometry *poSubGeom = nullptr;
     245       25553 :         size_t nSubGeomBytesConsumed = 0;
     246       25553 :         eErr = OGRGeometryFactory::createFromWkb(pabySubData, nullptr,
     247             :                                                  &poSubGeom, nSize, eWkbVariant,
     248             :                                                  nSubGeomBytesConsumed);
     249             : 
     250       25553 :         if (eErr != OGRERR_NONE)
     251             :         {
     252        2038 :             oMP.nGeomCount = iGeom;
     253        2038 :             delete poSubGeom;
     254        2038 :             return eErr;
     255             :         }
     256             : 
     257       23515 :         oMP.papoGeoms[iGeom] = poSubGeom;
     258             : 
     259       23515 :         if (oMP.papoGeoms[iGeom]->Is3D())
     260       23511 :             flags |= OGR_G_3D;
     261       23515 :         if (oMP.papoGeoms[iGeom]->IsMeasured())
     262       23476 :             flags |= OGR_G_MEASURED;
     263             : 
     264       23515 :         CPLAssert(nSubGeomBytesConsumed > 0);
     265       23515 :         if (nSize != static_cast<size_t>(-1))
     266             :         {
     267       23515 :             CPLAssert(nSize >= nSubGeomBytesConsumed);
     268       23515 :             nSize -= nSubGeomBytesConsumed;
     269             :         }
     270             : 
     271       23515 :         nDataOffset += nSubGeomBytesConsumed;
     272             :     }
     273       11159 :     nBytesConsumedOut = nDataOffset;
     274             : 
     275       11159 :     return OGRERR_NONE;
     276             : }
     277             : 
     278             : /************************************************************************/
     279             : /*                            exportToWkb()                             */
     280             : /************************************************************************/
     281             : 
     282             : OGRErr
     283        5855 : OGRPolyhedralSurface::exportToWkb(unsigned char *pabyData,
     284             :                                   const OGRwkbExportOptions *psOptions) const
     285             : 
     286             : {
     287        5855 :     if (!psOptions)
     288             :     {
     289             :         static const OGRwkbExportOptions defaultOptions;
     290           0 :         psOptions = &defaultOptions;
     291             :     }
     292             : 
     293             :     /* -------------------------------------------------------------------- */
     294             :     /*      Set the byte order.                                             */
     295             :     /* -------------------------------------------------------------------- */
     296        5855 :     pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER(
     297             :         static_cast<unsigned char>(psOptions->eByteOrder));
     298             : 
     299             :     /* -------------------------------------------------------------------- */
     300             :     /*      Set the geometry feature type, ensuring that 3D flag is         */
     301             :     /*      preserved.                                                      */
     302             :     /* -------------------------------------------------------------------- */
     303        5855 :     GUInt32 nGType = getIsoGeometryType();
     304             : 
     305        5855 :     if (OGR_SWAP(psOptions->eByteOrder))
     306             :     {
     307           2 :         nGType = CPL_SWAP32(nGType);
     308             :     }
     309             : 
     310        5855 :     memcpy(pabyData + 1, &nGType, 4);
     311             : 
     312             :     // Copy the raw data
     313        5855 :     if (OGR_SWAP(psOptions->eByteOrder))
     314             :     {
     315           2 :         int nCount = CPL_SWAP32(oMP.nGeomCount);
     316           2 :         memcpy(pabyData + 5, &nCount, 4);
     317             :     }
     318             :     else
     319        5853 :         memcpy(pabyData + 5, &oMP.nGeomCount, 4);
     320             : 
     321        5855 :     size_t nOffset = 9;
     322             : 
     323             :     // serialize each of the geometries
     324       17464 :     for (auto &&poSubGeom : *this)
     325             :     {
     326       11609 :         poSubGeom->exportToWkb(pabyData + nOffset, psOptions);
     327       11609 :         nOffset += poSubGeom->WkbSize();
     328             :     }
     329             : 
     330        5855 :     return OGRERR_NONE;
     331             : }
     332             : 
     333             : /************************************************************************/
     334             : /*                           importFromWkt()                            */
     335             : /*              Instantiate from well known text format.                */
     336             : /************************************************************************/
     337             : 
     338         265 : OGRErr OGRPolyhedralSurface::importFromWkt(const char **ppszInput)
     339             : {
     340         265 :     int bHasZ = FALSE, bHasM = FALSE;
     341         265 :     bool bIsEmpty = false;
     342         265 :     OGRErr eErr = importPreambleFromWkt(ppszInput, &bHasZ, &bHasM, &bIsEmpty);
     343         265 :     flags = 0;
     344         265 :     if (eErr != OGRERR_NONE)
     345           0 :         return eErr;
     346         265 :     if (bHasZ)
     347         180 :         flags |= OGR_G_3D;
     348         265 :     if (bHasM)
     349          24 :         flags |= OGR_G_MEASURED;
     350         265 :     if (bIsEmpty)
     351          16 :         return OGRERR_NONE;
     352             : 
     353             :     char szToken[OGR_WKT_TOKEN_MAX];
     354         249 :     const char *pszInput = *ppszInput;
     355             : 
     356             :     /* Skip first '(' */
     357         249 :     pszInput = OGRWktReadToken(pszInput, szToken);
     358             : 
     359             :     /* ==================================================================== */
     360             :     /*      Read each surface in turn.  Note that we try to reuse the same  */
     361             :     /*      point list buffer from ring to ring to cut down on              */
     362             :     /*      allocate/deallocate overhead.                                   */
     363             :     /* ==================================================================== */
     364         249 :     OGRRawPoint *paoPoints = nullptr;
     365         249 :     int nMaxPoints = 0;
     366         249 :     double *padfZ = nullptr;
     367             : 
     368         172 :     do
     369             :     {
     370             : 
     371             :         /* --------------------------------------------------------------------
     372             :          */
     373             :         /*      Get the first token, which should be the geometry type. */
     374             :         /* --------------------------------------------------------------------
     375             :          */
     376         421 :         const char *pszInputBefore = pszInput;
     377         421 :         pszInput = OGRWktReadToken(pszInput, szToken);
     378             : 
     379         421 :         OGRSurface *poSurface = nullptr;
     380             : 
     381             :         /* --------------------------------------------------------------------
     382             :          */
     383             :         /*      Do the import. */
     384             :         /* --------------------------------------------------------------------
     385             :          */
     386         421 :         if (EQUAL(szToken, "("))
     387             :         {
     388             :             OGRPolygon *poPolygon =
     389         420 :                 OGRGeometryFactory::createGeometry(getSubGeometryType())
     390         420 :                     ->toPolygon();
     391         420 :             poSurface = poPolygon;
     392         420 :             pszInput = pszInputBefore;
     393         420 :             eErr = poPolygon->importFromWKTListOnly(
     394         420 :                 &pszInput, bHasZ, bHasM, paoPoints, nMaxPoints, padfZ);
     395             :         }
     396             :         else
     397             :         {
     398           1 :             CPLError(CE_Failure, CPLE_AppDefined, "Unexpected token : %s",
     399             :                      szToken);
     400           1 :             eErr = OGRERR_CORRUPT_DATA;
     401           1 :             break;
     402             :         }
     403             : 
     404         420 :         if (eErr == OGRERR_NONE)
     405         418 :             eErr = oMP._addGeometryDirectlyWithExpectedSubGeometryType(
     406         418 :                 poSurface, getSubGeometryType());
     407         420 :         if (eErr != OGRERR_NONE)
     408             :         {
     409           2 :             delete poSurface;
     410           2 :             break;
     411             :         }
     412             : 
     413             :         // Read the delimiter following the surface.
     414         418 :         pszInput = OGRWktReadToken(pszInput, szToken);
     415             : 
     416         418 :     } while (szToken[0] == ',' && eErr == OGRERR_NONE);
     417             : 
     418         249 :     CPLFree(paoPoints);
     419         249 :     CPLFree(padfZ);
     420             : 
     421             :     // Check for a closing bracket
     422         249 :     if (eErr != OGRERR_NONE)
     423           3 :         return eErr;
     424             : 
     425         246 :     if (szToken[0] != ')')
     426           0 :         return OGRERR_CORRUPT_DATA;
     427             : 
     428         246 :     set3D(oMP.Is3D());
     429         246 :     setMeasured(oMP.IsMeasured());
     430             : 
     431         246 :     *ppszInput = pszInput;
     432         246 :     return OGRERR_NONE;
     433             : }
     434             : 
     435             : /************************************************************************/
     436             : /*                            exportToWkt()                             */
     437             : /************************************************************************/
     438             : 
     439         103 : std::string OGRPolyhedralSurface::exportToWkt(const OGRWktOptions &opts,
     440             :                                               OGRErr *err) const
     441             : {
     442         103 :     OGRWktOptions optsModified(opts);
     443         103 :     optsModified.variant = wkbVariantIso;
     444         206 :     return exportToWktInternal(optsModified, err);
     445             : }
     446             : 
     447             : //! @cond Doxygen_Suppress
     448         103 : std::string OGRPolyhedralSurface::exportToWktInternal(const OGRWktOptions &opts,
     449             :                                                       OGRErr *err) const
     450             : {
     451             :     try
     452             :     {
     453         206 :         std::string wkt(getGeometryName());
     454         103 :         wkt += wktTypeString(opts.variant);
     455         103 :         bool first = true;
     456             : 
     457         265 :         for (int i = 0; i < oMP.nGeomCount; ++i)
     458             :         {
     459         162 :             OGRGeometry *geom = oMP.papoGeoms[i];
     460             : 
     461         162 :             OGRErr subgeomErr = OGRERR_NONE;
     462         162 :             std::string tempWkt = geom->exportToWkt(opts, &subgeomErr);
     463         162 :             if (subgeomErr != OGRERR_NONE)
     464             :             {
     465           0 :                 if (err)
     466           0 :                     *err = subgeomErr;
     467           0 :                 return std::string();
     468             :             }
     469             : 
     470         162 :             auto pos = tempWkt.find('(');
     471             : 
     472             :             // Skip empty geoms
     473         162 :             if (pos == std::string::npos)
     474           1 :                 continue;
     475         161 :             if (first)
     476          88 :                 wkt += '(';
     477             :             else
     478          73 :                 wkt += ',';
     479         161 :             first = false;
     480             : 
     481             :             // Extract the '( ... )' part of the child geometry.
     482         161 :             wkt += tempWkt.substr(pos);
     483             :         }
     484             : 
     485         103 :         if (err)
     486         103 :             *err = OGRERR_NONE;
     487         103 :         if (first)
     488          15 :             wkt += "EMPTY";
     489             :         else
     490          88 :             wkt += ')';
     491         103 :         return wkt;
     492             :     }
     493           0 :     catch (const std::bad_alloc &e)
     494             :     {
     495           0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
     496           0 :         if (err)
     497           0 :             *err = OGRERR_FAILURE;
     498           0 :         return std::string();
     499             :     }
     500             : }
     501             : 
     502             : //! @endcond
     503             : 
     504             : /************************************************************************/
     505             : /*                            flattenTo2D()                             */
     506             : /************************************************************************/
     507             : 
     508           7 : void OGRPolyhedralSurface::flattenTo2D()
     509             : {
     510           7 :     oMP.flattenTo2D();
     511             : 
     512           7 :     flags &= ~OGR_G_3D;
     513           7 :     flags &= ~OGR_G_MEASURED;
     514           7 : }
     515             : 
     516             : /************************************************************************/
     517             : /*                             transform()                              */
     518             : /************************************************************************/
     519             : 
     520           1 : OGRErr OGRPolyhedralSurface::transform(OGRCoordinateTransformation *poCT)
     521             : {
     522           1 :     return oMP.transform(poCT);
     523             : }
     524             : 
     525             : /************************************************************************/
     526             : /*                      GetCasterToPolygon()                            */
     527             : /************************************************************************/
     528             : 
     529             : //! @cond Doxygen_Suppress
     530           0 : static OGRPolygon *CasterToPolygon(OGRSurface *poGeom)
     531             : {
     532           0 :     CPLError(CE_Failure, CPLE_AppDefined, "%s found. Conversion impossible",
     533           0 :              poGeom->getGeometryName());
     534           0 :     delete poGeom;
     535           0 :     return nullptr;
     536             : }
     537             : 
     538           0 : OGRSurfaceCasterToPolygon OGRPolyhedralSurface::GetCasterToPolygon() const
     539             : {
     540           0 :     return ::CasterToPolygon;
     541             : }
     542             : 
     543             : //! @endcond
     544             : 
     545             : /************************************************************************/
     546             : /*                      OGRSurfaceCasterToCurvePolygon()                */
     547             : /************************************************************************/
     548             : 
     549             : //! @cond Doxygen_Suppress
     550           0 : static OGRCurvePolygon *CasterToCurvePolygon(OGRSurface *poGeom)
     551             : {
     552           0 :     CPLError(CE_Failure, CPLE_AppDefined, "%s found. Conversion impossible",
     553           0 :              poGeom->getGeometryName());
     554           0 :     delete poGeom;
     555           0 :     return nullptr;
     556             : }
     557             : 
     558             : OGRSurfaceCasterToCurvePolygon
     559           0 : OGRPolyhedralSurface::GetCasterToCurvePolygon() const
     560             : {
     561           0 :     return ::CasterToCurvePolygon;
     562             : }
     563             : 
     564             : //! @endcond
     565             : 
     566             : /************************************************************************/
     567             : /*                         isCompatibleSubType()                        */
     568             : /************************************************************************/
     569             : 
     570             : //! @cond Doxygen_Suppress
     571             : OGRBoolean
     572       14371 : OGRPolyhedralSurface::isCompatibleSubType(OGRwkbGeometryType eSubType) const
     573             : {
     574       14371 :     return wkbFlatten(eSubType) == wkbPolygon;
     575             : }
     576             : 
     577             : //! @endcond
     578             : 
     579             : /************************************************************************/
     580             : /*                         getSubGeometryName()                         */
     581             : /************************************************************************/
     582             : 
     583             : //! @cond Doxygen_Suppress
     584           0 : const char *OGRPolyhedralSurface::getSubGeometryName() const
     585             : {
     586           0 :     return "POLYGON";
     587             : }
     588             : 
     589             : //! @endcond
     590             : 
     591             : /************************************************************************/
     592             : /*                         getSubGeometryType()                         */
     593             : /************************************************************************/
     594             : 
     595             : //! @cond Doxygen_Suppress
     596         214 : OGRwkbGeometryType OGRPolyhedralSurface::getSubGeometryType() const
     597             : {
     598         214 :     return wkbPolygon;
     599             : }
     600             : 
     601             : //! @endcond
     602             : 
     603             : /************************************************************************/
     604             : /*                               Equals()                               */
     605             : /************************************************************************/
     606             : 
     607        5725 : OGRBoolean OGRPolyhedralSurface::Equals(const OGRGeometry *poOther) const
     608             : {
     609             : 
     610        5725 :     if (poOther == this)
     611           1 :         return TRUE;
     612             : 
     613        5724 :     if (poOther->getGeometryType() != getGeometryType())
     614           2 :         return FALSE;
     615             : 
     616        5722 :     if (IsEmpty() && poOther->IsEmpty())
     617           2 :         return TRUE;
     618             : 
     619        5720 :     auto poOMP = poOther->toPolyhedralSurface();
     620        5720 :     if (oMP.getNumGeometries() != poOMP->oMP.getNumGeometries())
     621           1 :         return FALSE;
     622             : 
     623       17105 :     for (int iGeom = 0; iGeom < oMP.nGeomCount; iGeom++)
     624             :     {
     625       22774 :         if (!oMP.getGeometryRef(iGeom)->Equals(
     626       11387 :                 poOMP->oMP.getGeometryRef(iGeom)))
     627           1 :             return FALSE;
     628             :     }
     629             : 
     630        5718 :     return TRUE;
     631             : }
     632             : 
     633             : /************************************************************************/
     634             : /*                              get_Area()                              */
     635             : /************************************************************************/
     636             : 
     637             : /**
     638             :  * \brief Returns the area enclosed
     639             :  *
     640             :  * This method is built on the SFCGAL library, check it for the definition
     641             :  * of the geometry operation.
     642             :  * If OGR is built without the SFCGAL library, this method will always return
     643             :  * -1.0
     644             :  *
     645             :  * @return area enclosed by the PolyhedralSurface
     646             :  */
     647             : 
     648           0 : double OGRPolyhedralSurface::get_Area() const
     649             : {
     650             : #ifndef HAVE_SFCGAL
     651             : 
     652           0 :     CPLError(CE_Failure, CPLE_NotSupported, "SFCGAL support not enabled.");
     653           0 :     return -1.0;
     654             : 
     655             : #else
     656             : 
     657             :     sfcgal_init();
     658             :     sfcgal_geometry_t *poThis = OGRGeometry::OGRexportToSFCGAL(this);
     659             :     if (poThis == nullptr)
     660             :         return -1.0;
     661             : 
     662             :     double area = sfcgal_geometry_area_3d(poThis);
     663             : 
     664             :     sfcgal_geometry_delete(poThis);
     665             : 
     666             :     return (area > 0) ? area : -1.0;
     667             : 
     668             : #endif
     669             : }
     670             : 
     671             : /************************************************************************/
     672             : /*                        get_GeodesicArea()                            */
     673             : /************************************************************************/
     674             : 
     675           3 : double OGRPolyhedralSurface::get_GeodesicArea(const OGRSpatialReference *) const
     676             : {
     677           3 :     if (IsEmpty())
     678           1 :         return 0;
     679             : 
     680           2 :     CPLError(CE_Failure, CPLE_NotSupported,
     681             :              "get_GeodesicArea() not implemented for PolyhedralSurface");
     682           2 :     return -1;
     683             : }
     684             : 
     685             : /************************************************************************/
     686             : /*                           PointOnSurface()                           */
     687             : /************************************************************************/
     688             : 
     689           0 : OGRErr OGRPolyhedralSurface::PointOnSurface(OGRPoint *poPoint) const
     690             : {
     691           0 :     return PointOnSurfaceInternal(poPoint);
     692             : }
     693             : 
     694             : /************************************************************************/
     695             : /*                     GetCasterToMultiPolygon()                        */
     696             : /************************************************************************/
     697             : //! @cond Doxygen_Suppress
     698             : OGRPolyhedralSurfaceCastToMultiPolygon
     699          16 : OGRPolyhedralSurface::GetCasterToMultiPolygon() const
     700             : {
     701          16 :     return OGRPolyhedralSurface::CastToMultiPolygonImpl;
     702             : }
     703             : 
     704             : /************************************************************************/
     705             : /*                      CastToMultiPolygonImpl()                        */
     706             : /************************************************************************/
     707             : 
     708             : OGRMultiPolygon *
     709          16 : OGRPolyhedralSurface::CastToMultiPolygonImpl(OGRPolyhedralSurface *poPS)
     710             : {
     711          16 :     OGRMultiPolygon *poMultiPolygon = new OGRMultiPolygon(poPS->oMP);
     712          16 :     poMultiPolygon->assignSpatialReference(poPS->getSpatialReference());
     713          16 :     delete poPS;
     714          16 :     return poMultiPolygon;
     715             : }
     716             : 
     717             : //! @endcond
     718             : 
     719             : /************************************************************************/
     720             : /*                         CastToMultiPolygon()                         */
     721             : /************************************************************************/
     722             : 
     723             : /**
     724             :  * \brief Casts the OGRPolyhedralSurface to an OGRMultiPolygon
     725             :  *
     726             :  * The passed in geometry is consumed and a new one returned (or NULL in case
     727             :  * of failure)
     728             :  *
     729             :  * @param poPS the input geometry - ownership is passed to the method.
     730             :  * @return new geometry.
     731             :  */
     732             : 
     733             : OGRMultiPolygon *
     734         274 : OGRPolyhedralSurface::CastToMultiPolygon(OGRPolyhedralSurface *poPS)
     735             : {
     736             :     OGRPolyhedralSurfaceCastToMultiPolygon pfn =
     737         274 :         poPS->GetCasterToMultiPolygon();
     738         274 :     return pfn(poPS);
     739             : }
     740             : 
     741             : /************************************************************************/
     742             : /*                            addGeometry()                             */
     743             : /************************************************************************/
     744             : 
     745             : /**
     746             :  * \brief Add a new geometry to a collection.
     747             :  *
     748             :  * Only a POLYGON can be added to a POLYHEDRALSURFACE.
     749             :  *
     750             :  * @return OGRErr OGRERR_NONE if the polygon is successfully added
     751             :  */
     752             : 
     753        1235 : OGRErr OGRPolyhedralSurface::addGeometry(const OGRGeometry *poNewGeom)
     754             : {
     755        1235 :     if (!isCompatibleSubType(poNewGeom->getGeometryType()))
     756           1 :         return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
     757             : 
     758        1234 :     OGRGeometry *poClone = poNewGeom->clone();
     759             :     OGRErr eErr;
     760             : 
     761        1234 :     if (poClone == nullptr)
     762           0 :         return OGRERR_FAILURE;
     763             : 
     764        1234 :     eErr = addGeometryDirectly(poClone);
     765             : 
     766        1234 :     if (eErr != OGRERR_NONE)
     767           0 :         delete poClone;
     768             : 
     769        1234 :     return eErr;
     770             : }
     771             : 
     772             : /************************************************************************/
     773             : /*                        addGeometryDirectly()                         */
     774             : /************************************************************************/
     775             : 
     776             : /**
     777             :  * \brief Add a geometry directly to the container.
     778             :  *
     779             :  * Ownership of the passed geometry is taken by the container rather than
     780             :  * cloning as addCurve() does, but only if the method is successful.
     781             :  * If the method fails, ownership still belongs to the caller.
     782             :  *
     783             :  * This method is the same as the C function OGR_G_AddGeometryDirectly().
     784             :  *
     785             :  * There is no SFCOM analog to this method.
     786             :  *
     787             :  * @param poNewGeom geometry to add to the container.
     788             :  *
     789             :  * @return OGRERR_NONE if successful, or OGRERR_UNSUPPORTED_GEOMETRY_TYPE if
     790             :  * the geometry type is illegal for the type of geometry container.
     791             :  */
     792             : 
     793        4958 : OGRErr OGRPolyhedralSurface::addGeometryDirectly(OGRGeometry *poNewGeom)
     794             : {
     795        4958 :     if (!isCompatibleSubType(poNewGeom->getGeometryType()))
     796             :     {
     797           2 :         return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
     798             :     }
     799             : 
     800        4956 :     HomogenizeDimensionalityWith(poNewGeom);
     801             : 
     802             :     OGRGeometry **papoNewGeoms =
     803        4956 :         static_cast<OGRGeometry **>(VSI_REALLOC_VERBOSE(
     804             :             oMP.papoGeoms, sizeof(void *) * (oMP.nGeomCount + 1)));
     805        4956 :     if (papoNewGeoms == nullptr)
     806           0 :         return OGRERR_FAILURE;
     807             : 
     808        4956 :     oMP.papoGeoms = papoNewGeoms;
     809        4956 :     oMP.papoGeoms[oMP.nGeomCount] = poNewGeom;
     810        4956 :     oMP.nGeomCount++;
     811             : 
     812        4956 :     return OGRERR_NONE;
     813             : }
     814             : 
     815             : /************************************************************************/
     816             : /*                            addGeometry()                             */
     817             : /************************************************************************/
     818             : 
     819             : /**
     820             :  * \brief Add a geometry directly to the container.
     821             :  *
     822             :  * There is no SFCOM analog to this method.
     823             :  *
     824             :  * @param geom geometry to add to the container.
     825             :  *
     826             :  * @return OGRERR_NONE if successful, or OGRERR_UNSUPPORTED_GEOMETRY_TYPE if
     827             :  * the geometry type is illegal for the type of geometry container.
     828             :  */
     829             : 
     830          89 : OGRErr OGRPolyhedralSurface::addGeometry(std::unique_ptr<OGRGeometry> geom)
     831             : {
     832          89 :     OGRGeometry *poGeom = geom.release();
     833          89 :     OGRErr eErr = addGeometryDirectly(poGeom);
     834          89 :     if (eErr != OGRERR_NONE)
     835           0 :         delete poGeom;
     836          89 :     return eErr;
     837             : }
     838             : 
     839             : /************************************************************************/
     840             : /*                          getNumGeometries()                          */
     841             : /************************************************************************/
     842             : 
     843             : /**
     844             :  * \brief Fetch number of geometries in PolyhedralSurface
     845             :  *
     846             :  * @return count of children geometries.  May be zero.
     847             :  */
     848             : 
     849         123 : int OGRPolyhedralSurface::getNumGeometries() const
     850             : {
     851         123 :     return oMP.nGeomCount;
     852             : }
     853             : 
     854             : /************************************************************************/
     855             : /*                         getGeometryRef()                             */
     856             : /************************************************************************/
     857             : 
     858             : /**
     859             :  * \brief Fetch geometry from container.
     860             :  *
     861             :  * This method returns a pointer to an geometry within the container.  The
     862             :  * returned geometry remains owned by the container, and should not be
     863             :  * modified.  The pointer is only valid until the next change to the
     864             :  * geometry container.  Use IGeometry::clone() to make a copy.
     865             :  *
     866             :  * @param i the index of the geometry to fetch, between 0 and
     867             :  *          getNumGeometries() - 1.
     868             :  * @return pointer to requested geometry.
     869             :  */
     870             : 
     871         136 : OGRPolygon *OGRPolyhedralSurface::getGeometryRef(int i)
     872             : {
     873         136 :     return oMP.papoGeoms[i]->toPolygon();
     874             : }
     875             : 
     876             : /************************************************************************/
     877             : /*                         getGeometryRef()                             */
     878             : /************************************************************************/
     879             : 
     880             : /**
     881             :  * \brief Fetch geometry from container.
     882             :  *
     883             :  * This method returns a pointer to an geometry within the container.  The
     884             :  * returned geometry remains owned by the container, and should not be
     885             :  * modified.  The pointer is only valid until the next change to the
     886             :  * geometry container.  Use IGeometry::clone() to make a copy.
     887             :  *
     888             :  * @param i the index of the geometry to fetch, between 0 and
     889             :  *          getNumGeometries() - 1.
     890             :  * @return pointer to requested geometry.
     891             :  */
     892             : 
     893           9 : const OGRPolygon *OGRPolyhedralSurface::getGeometryRef(int i) const
     894             : {
     895           9 :     return oMP.papoGeoms[i]->toPolygon();
     896             : }
     897             : 
     898             : /************************************************************************/
     899             : /*                               IsEmpty()                              */
     900             : /************************************************************************/
     901             : 
     902             : /**
     903             :  * \brief Checks if the PolyhedralSurface is empty
     904             :  *
     905             :  * @return TRUE if the PolyhedralSurface is empty, FALSE otherwise
     906             :  */
     907             : 
     908        6557 : OGRBoolean OGRPolyhedralSurface::IsEmpty() const
     909             : {
     910        6557 :     return oMP.IsEmpty();
     911             : }
     912             : 
     913             : /************************************************************************/
     914             : /*                                 set3D()                              */
     915             : /************************************************************************/
     916             : 
     917             : /**
     918             :  * \brief Set the type as 3D geometry
     919             :  */
     920             : 
     921       30316 : void OGRPolyhedralSurface::set3D(OGRBoolean bIs3D)
     922             : {
     923       30316 :     oMP.set3D(bIs3D);
     924             : 
     925       30316 :     OGRGeometry::set3D(bIs3D);
     926       30316 : }
     927             : 
     928             : /************************************************************************/
     929             : /*                             setMeasured()                            */
     930             : /************************************************************************/
     931             : 
     932             : /**
     933             :  * \brief Set the type as Measured
     934             :  */
     935             : 
     936       28159 : void OGRPolyhedralSurface::setMeasured(OGRBoolean bIsMeasured)
     937             : {
     938       28159 :     oMP.setMeasured(bIsMeasured);
     939             : 
     940       28159 :     OGRGeometry::setMeasured(bIsMeasured);
     941       28159 : }
     942             : 
     943             : /************************************************************************/
     944             : /*                       setCoordinateDimension()                       */
     945             : /************************************************************************/
     946             : 
     947             : /**
     948             :  * \brief Set the coordinate dimension.
     949             :  *
     950             :  * This method sets the explicit coordinate dimension.  Setting the coordinate
     951             :  * dimension of a geometry to 2 should zero out any existing Z values.
     952             :  * This will also remove the M dimension if present before this call.
     953             :  *
     954             :  * @param nNewDimension New coordinate dimension value, either 2 or 3.
     955             :  */
     956             : 
     957           8 : void OGRPolyhedralSurface::setCoordinateDimension(int nNewDimension)
     958             : {
     959           8 :     oMP.setCoordinateDimension(nNewDimension);
     960             : 
     961           8 :     OGRGeometry::setCoordinateDimension(nNewDimension);
     962           8 : }
     963             : 
     964             : /************************************************************************/
     965             : /*                               swapXY()                               */
     966             : /************************************************************************/
     967             : 
     968             : /**
     969             :  * \brief Swap x and y coordinates.
     970             :  */
     971             : 
     972           3 : void OGRPolyhedralSurface::swapXY()
     973             : {
     974           3 :     oMP.swapXY();
     975           3 : }
     976             : 
     977             : /************************************************************************/
     978             : /*                         hasCurveGeometry()                           */
     979             : /************************************************************************/
     980             : 
     981       11918 : OGRBoolean OGRPolyhedralSurface::hasCurveGeometry(int) const
     982             : {
     983       11918 :     return FALSE;
     984             : }
     985             : 
     986             : /************************************************************************/
     987             : /*                          removeGeometry()                            */
     988             : /************************************************************************/
     989             : 
     990             : /**
     991             :  * \brief Remove a geometry from the container.
     992             :  *
     993             :  * Removing a geometry will cause the geometry count to drop by one, and all
     994             :  * "higher" geometries will shuffle down one in index.
     995             :  *
     996             :  * @param iGeom the index of the geometry to delete.  A value of -1 is a
     997             :  * special flag meaning that all geometries should be removed.
     998             :  *
     999             :  * @param bDelete if TRUE the geometry will be deallocated, otherwise it will
    1000             :  * not.  The default is TRUE as the container is considered to own the
    1001             :  * geometries in it.
    1002             :  *
    1003             :  * @return OGRERR_NONE if successful, or OGRERR_FAILURE if the index is
    1004             :  * out of range.
    1005             :  */
    1006             : 
    1007           5 : OGRErr OGRPolyhedralSurface::removeGeometry(int iGeom, int bDelete)
    1008             : {
    1009           5 :     return oMP.removeGeometry(iGeom, bDelete);
    1010             : }
    1011             : 
    1012             : /************************************************************************/
    1013             : /*                       assignSpatialReference()                       */
    1014             : /************************************************************************/
    1015             : 
    1016       14668 : void OGRPolyhedralSurface::assignSpatialReference(
    1017             :     const OGRSpatialReference *poSR)
    1018             : {
    1019       14668 :     OGRGeometry::assignSpatialReference(poSR);
    1020       14668 :     oMP.assignSpatialReference(poSR);
    1021       14668 : }

Generated by: LCOV version 1.14