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