LCOV - code coverage report
Current view: top level - ogr - ogrmultisurface.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 100 106 94.3 %
Date: 2025-10-21 22:35:35 Functions: 10 11 90.9 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  The OGRMultiSurface class.
       5             :  * Author:   Even Rouault <even dot rouault at spatialys dot com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_port.h"
      14             : #include "ogr_geometry.h"
      15             : 
      16             : #include <cstddef>
      17             : 
      18             : #include "cpl_conv.h"
      19             : #include "cpl_error.h"
      20             : #include "ogr_api.h"
      21             : #include "ogr_core.h"
      22             : #include "ogr_p.h"
      23             : 
      24             : /************************************************************************/
      25             : /*              OGRMultiSurface( const OGRMultiSurface& )               */
      26             : /************************************************************************/
      27             : 
      28             : /**
      29             :  * \brief Copy constructor.
      30             :  */
      31             : 
      32             : OGRMultiSurface::OGRMultiSurface(const OGRMultiSurface &) = default;
      33             : 
      34             : /************************************************************************/
      35             : /*                  operator=( const OGRMultiCurve&)                    */
      36             : /************************************************************************/
      37             : 
      38             : /**
      39             :  * \brief Assignment operator.
      40             :  */
      41             : 
      42          13 : OGRMultiSurface &OGRMultiSurface::operator=(const OGRMultiSurface &other)
      43             : {
      44          13 :     if (this != &other)
      45             :     {
      46          12 :         OGRGeometryCollection::operator=(other);
      47             :     }
      48          13 :     return *this;
      49             : }
      50             : 
      51             : /************************************************************************/
      52             : /*                               clone()                                */
      53             : /************************************************************************/
      54             : 
      55         144 : OGRMultiSurface *OGRMultiSurface::clone() const
      56             : 
      57             : {
      58         144 :     auto ret = new (std::nothrow) OGRMultiSurface(*this);
      59         144 :     if (ret)
      60             :     {
      61         144 :         if (ret->WkbSize() != WkbSize())
      62             :         {
      63           0 :             delete ret;
      64           0 :             ret = nullptr;
      65             :         }
      66             :     }
      67         144 :     return ret;
      68             : }
      69             : 
      70             : /************************************************************************/
      71             : /*                          getGeometryType()                           */
      72             : /************************************************************************/
      73             : 
      74        3832 : OGRwkbGeometryType OGRMultiSurface::getGeometryType() const
      75             : 
      76             : {
      77        3832 :     if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
      78        3041 :         return wkbMultiSurfaceZM;
      79         791 :     else if (flags & OGR_G_MEASURED)
      80          23 :         return wkbMultiSurfaceM;
      81         768 :     else if (flags & OGR_G_3D)
      82         107 :         return wkbMultiSurfaceZ;
      83             :     else
      84         661 :         return wkbMultiSurface;
      85             : }
      86             : 
      87             : /************************************************************************/
      88             : /*                            getDimension()                            */
      89             : /************************************************************************/
      90             : 
      91          11 : int OGRMultiSurface::getDimension() const
      92             : 
      93             : {
      94          11 :     return 2;
      95             : }
      96             : 
      97             : /************************************************************************/
      98             : /*                          getGeometryName()                           */
      99             : /************************************************************************/
     100             : 
     101         419 : const char *OGRMultiSurface::getGeometryName() const
     102             : 
     103             : {
     104         419 :     return "MULTISURFACE";
     105             : }
     106             : 
     107             : /************************************************************************/
     108             : /*                          isCompatibleSubType()                       */
     109             : /************************************************************************/
     110             : 
     111             : OGRBoolean
     112        1415 : OGRMultiSurface::isCompatibleSubType(OGRwkbGeometryType eGeomType) const
     113             : {
     114        1415 :     OGRwkbGeometryType eFlattenGeomType = wkbFlatten(eGeomType);
     115        1415 :     return eFlattenGeomType == wkbPolygon ||
     116        1415 :            eFlattenGeomType == wkbCurvePolygon;
     117             : }
     118             : 
     119             : /************************************************************************/
     120             : /*                           importFromWkt()                            */
     121             : /*                                                                      */
     122             : /*      Instantiate from well known text format.                        */
     123             : /************************************************************************/
     124             : 
     125        1087 : OGRErr OGRMultiSurface::importFromWkt(const char **ppszInput)
     126             : 
     127             : {
     128        1087 :     int bHasZ = FALSE;
     129        1087 :     int bHasM = FALSE;
     130        1087 :     bool bIsEmpty = false;
     131        1087 :     OGRErr eErr = importPreambleFromWkt(ppszInput, &bHasZ, &bHasM, &bIsEmpty);
     132        1087 :     flags = 0;
     133        1087 :     if (eErr != OGRERR_NONE)
     134           5 :         return eErr;
     135        1082 :     if (bHasZ)
     136         172 :         flags |= OGR_G_3D;
     137        1082 :     if (bHasM)
     138         113 :         flags |= OGR_G_MEASURED;
     139        1082 :     if (bIsEmpty)
     140          73 :         return OGRERR_NONE;
     141             : 
     142        1009 :     char szToken[OGR_WKT_TOKEN_MAX] = {};
     143        1009 :     const char *pszInput = *ppszInput;
     144        1009 :     eErr = OGRERR_NONE;
     145             : 
     146             :     // Skip first '('.
     147        1009 :     pszInput = OGRWktReadToken(pszInput, szToken);
     148             : 
     149             :     /* ==================================================================== */
     150             :     /*      Read each surface in turn.  Note that we try to reuse the same  */
     151             :     /*      point list buffer from ring to ring to cut down on              */
     152             :     /*      allocate/deallocate overhead.                                   */
     153             :     /* ==================================================================== */
     154        1009 :     OGRRawPoint *paoPoints = nullptr;
     155        1009 :     int nMaxPoints = 0;
     156        1009 :     double *padfZ = nullptr;
     157             : 
     158         322 :     do
     159             :     {
     160             :         /* --------------------------------------------------------------------
     161             :          */
     162             :         /*      Get the first token, which should be the geometry type. */
     163             :         /* --------------------------------------------------------------------
     164             :          */
     165        1331 :         const char *pszInputBefore = pszInput;
     166        1331 :         pszInput = OGRWktReadToken(pszInput, szToken);
     167             : 
     168        1331 :         OGRSurface *poSurface = nullptr;
     169             : 
     170             :         /* --------------------------------------------------------------------
     171             :          */
     172             :         /*      Do the import. */
     173             :         /* --------------------------------------------------------------------
     174             :          */
     175        1331 :         if (EQUAL(szToken, "("))
     176             :         {
     177        1209 :             OGRPolygon *poPolygon = new OGRPolygon();
     178        1209 :             poSurface = poPolygon;
     179        1209 :             pszInput = pszInputBefore;
     180        1209 :             eErr = poPolygon->importFromWKTListOnly(
     181        1209 :                 &pszInput, bHasZ, bHasM, paoPoints, nMaxPoints, padfZ);
     182             :         }
     183         122 :         else if (EQUAL(szToken, "EMPTY"))
     184             :         {
     185          12 :             poSurface = new OGRPolygon();
     186             :         }
     187             :         // We accept POLYGON() but this is an extension to the BNF, also
     188             :         // accepted by PostGIS.
     189         110 :         else if (STARTS_WITH_CI(szToken, "POLYGON") ||
     190         106 :                  STARTS_WITH_CI(szToken, "CURVEPOLYGON"))
     191             :         {
     192          95 :             OGRGeometry *poGeom = nullptr;
     193          95 :             pszInput = pszInputBefore;
     194             :             eErr =
     195          95 :                 OGRGeometryFactory::createFromWkt(&pszInput, nullptr, &poGeom);
     196          95 :             if (poGeom == nullptr)
     197             :             {
     198           1 :                 eErr = OGRERR_CORRUPT_DATA;
     199           1 :                 break;
     200             :             }
     201          94 :             poSurface = poGeom->toSurface();
     202             :         }
     203             :         else
     204             :         {
     205          15 :             CPLError(CE_Failure, CPLE_AppDefined, "Unexpected token : %s",
     206             :                      szToken);
     207          15 :             eErr = OGRERR_CORRUPT_DATA;
     208          15 :             break;
     209             :         }
     210             : 
     211        1315 :         if (eErr == OGRERR_NONE)
     212        1301 :             eErr = addGeometryDirectly(poSurface);
     213        1315 :         if (eErr != OGRERR_NONE)
     214             :         {
     215          14 :             delete poSurface;
     216          14 :             break;
     217             :         }
     218             : 
     219             :         /* --------------------------------------------------------------------
     220             :          */
     221             :         /*      Read the delimiter following the surface. */
     222             :         /* --------------------------------------------------------------------
     223             :          */
     224        1301 :         pszInput = OGRWktReadToken(pszInput, szToken);
     225        1301 :     } while (szToken[0] == ',' && eErr == OGRERR_NONE);
     226             : 
     227        1009 :     CPLFree(paoPoints);
     228        1009 :     CPLFree(padfZ);
     229             : 
     230             :     /* -------------------------------------------------------------------- */
     231             :     /*      freak if we don't get a closing bracket.                        */
     232             :     /* -------------------------------------------------------------------- */
     233             : 
     234        1009 :     if (eErr != OGRERR_NONE)
     235          30 :         return eErr;
     236             : 
     237         979 :     if (szToken[0] != ')')
     238           3 :         return OGRERR_CORRUPT_DATA;
     239             : 
     240         976 :     *ppszInput = pszInput;
     241         976 :     return OGRERR_NONE;
     242             : }
     243             : 
     244             : /************************************************************************/
     245             : /*                            exportToWkt()                             */
     246             : /************************************************************************/
     247             : 
     248          85 : std::string OGRMultiSurface::exportToWkt(const OGRWktOptions &opts,
     249             :                                          OGRErr *err) const
     250             : {
     251          85 :     OGRWktOptions optsModified(opts);
     252          85 :     optsModified.variant = wkbVariantIso;
     253          85 :     return exportToWktInternal(optsModified, err, "POLYGON");
     254             : }
     255             : 
     256             : /************************************************************************/
     257             : /*                         hasCurveGeometry()                           */
     258             : /************************************************************************/
     259             : 
     260        1218 : OGRBoolean OGRMultiSurface::hasCurveGeometry(int bLookForNonLinear) const
     261             : {
     262        1218 :     if (bLookForNonLinear)
     263          23 :         return OGRGeometryCollection::hasCurveGeometry(TRUE);
     264        1195 :     return TRUE;
     265             : }
     266             : 
     267             : /************************************************************************/
     268             : /*                            PointOnSurface()                          */
     269             : /************************************************************************/
     270             : 
     271             : /** \brief This method relates to the SFCOM
     272             :  * IMultiSurface::get_PointOnSurface() method.
     273             :  *
     274             :  * NOTE: Only implemented when GEOS included in build.
     275             :  *
     276             :  * @param poPoint point to be set with an internal point.
     277             :  *
     278             :  * @return OGRERR_NONE if it succeeds or OGRERR_FAILURE otherwise.
     279             :  */
     280             : 
     281           0 : OGRErr OGRMultiSurface::PointOnSurface(OGRPoint *poPoint) const
     282             : {
     283           0 :     return PointOnSurfaceInternal(poPoint);
     284             : }
     285             : 
     286             : /************************************************************************/
     287             : /*                         CastToMultiPolygon()                         */
     288             : /************************************************************************/
     289             : 
     290             : /**
     291             :  * \brief Cast to multipolygon.
     292             :  *
     293             :  * This method should only be called if the multisurface actually only contains
     294             :  * instances of OGRPolygon. This can be verified if hasCurveGeometry(TRUE)
     295             :  * returns FALSE. It is not intended to approximate curve polygons. For that
     296             :  * use getLinearGeometry().
     297             :  *
     298             :  * The passed in geometry is consumed and a new one returned (or NULL in case
     299             :  * of failure).
     300             :  *
     301             :  * @param poMS the input geometry - ownership is passed to the method.
     302             :  * @return new geometry.
     303             :  */
     304             : 
     305          62 : OGRMultiPolygon *OGRMultiSurface::CastToMultiPolygon(OGRMultiSurface *poMS)
     306             : {
     307         128 :     for (auto &&poSubGeom : *poMS)
     308             :     {
     309          66 :         poSubGeom = OGRSurface::CastToPolygon(poSubGeom);
     310          66 :         if (poSubGeom == nullptr)
     311             :         {
     312           0 :             delete poMS;
     313           0 :             return nullptr;
     314             :         }
     315             :     }
     316             : 
     317          62 :     OGRMultiPolygon *poMP = new OGRMultiPolygon();
     318          62 :     TransferMembersAndDestroy(poMS, poMP);
     319          62 :     return poMP;
     320             : }

Generated by: LCOV version 1.14