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: 2024-11-21 22:18:42 Functions: 40 48 83.3 %

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

Generated by: LCOV version 1.14