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