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