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 : }
|