LCOV - code coverage report
Current view: top level - ogr - ogrpolyhedralsurface.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 269 316 85.1 %
Date: 2025-01-18 12:42:00 Functions: 40 48 83.3 %

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

Generated by: LCOV version 1.14