Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: The OGRCurvePolygon geometry class.
5 : * Author: Even Rouault <even dot rouault at spatialys dot com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "cpl_port.h"
14 : #include "ogr_geometry.h"
15 :
16 : #include <cstddef>
17 :
18 : #include "cpl_error.h"
19 : #include "ogr_api.h"
20 : #include "ogr_core.h"
21 : #include "ogr_geos.h"
22 : #include "ogr_sfcgal.h"
23 : #include "ogr_p.h"
24 : #include "ogr_spatialref.h"
25 :
26 : /************************************************************************/
27 : /* OGRCurvePolygon( const OGRCurvePolygon& ) */
28 : /************************************************************************/
29 :
30 : /**
31 : * \brief Copy constructor.
32 : */
33 :
34 : OGRCurvePolygon::OGRCurvePolygon(const OGRCurvePolygon &) = default;
35 :
36 : /************************************************************************/
37 : /* operator=( const OGRCurvePolygon&) */
38 : /************************************************************************/
39 :
40 : /**
41 : * \brief Assignment operator.
42 : */
43 :
44 14 : OGRCurvePolygon &OGRCurvePolygon::operator=(const OGRCurvePolygon &other)
45 : {
46 14 : if (this != &other)
47 : {
48 13 : OGRSurface::operator=(other);
49 :
50 23 : for (const auto *poRing : other.oCC)
51 : {
52 11 : if (!isRingCorrectType(poRing))
53 : {
54 1 : CPLError(CE_Failure, CPLE_AppDefined,
55 : "Illegal use of OGRCurvePolygon::operator=(): "
56 : "trying to assign an incompatible sub-geometry");
57 1 : return *this;
58 : }
59 : }
60 :
61 12 : oCC = other.oCC;
62 : }
63 13 : return *this;
64 : }
65 :
66 : /************************************************************************/
67 : /* clone() */
68 : /************************************************************************/
69 :
70 300 : OGRCurvePolygon *OGRCurvePolygon::clone() const
71 :
72 : {
73 300 : return new (std::nothrow) OGRCurvePolygon(*this);
74 : }
75 :
76 : /************************************************************************/
77 : /* empty() */
78 : /************************************************************************/
79 :
80 62138 : void OGRCurvePolygon::empty()
81 :
82 : {
83 62138 : oCC.empty(this);
84 62138 : }
85 :
86 : /************************************************************************/
87 : /* getGeometryType() */
88 : /************************************************************************/
89 :
90 1485 : OGRwkbGeometryType OGRCurvePolygon::getGeometryType() const
91 :
92 : {
93 1485 : if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
94 203 : return wkbCurvePolygonZM;
95 1282 : else if (flags & OGR_G_MEASURED)
96 27 : return wkbCurvePolygonM;
97 1255 : else if (flags & OGR_G_3D)
98 131 : return wkbCurvePolygonZ;
99 : else
100 1124 : return wkbCurvePolygon;
101 : }
102 :
103 : /************************************************************************/
104 : /* getDimension() */
105 : /************************************************************************/
106 :
107 1950 : int OGRCurvePolygon::getDimension() const
108 :
109 : {
110 1950 : return 2;
111 : }
112 :
113 : /************************************************************************/
114 : /* flattenTo2D() */
115 : /************************************************************************/
116 :
117 785 : void OGRCurvePolygon::flattenTo2D()
118 :
119 : {
120 785 : oCC.flattenTo2D(this);
121 785 : }
122 :
123 : /************************************************************************/
124 : /* getGeometryName() */
125 : /************************************************************************/
126 :
127 713 : const char *OGRCurvePolygon::getGeometryName() const
128 :
129 : {
130 713 : return "CURVEPOLYGON";
131 : }
132 :
133 : /************************************************************************/
134 : /* getExteriorRingCurve() */
135 : /************************************************************************/
136 :
137 : /**
138 : * \brief Fetch reference to external polygon ring.
139 : *
140 : * Note that the returned ring pointer is to an internal data object of the
141 : * OGRCurvePolygon. It should not be modified or deleted by the application,
142 : * and the pointer is only valid till the polygon is next modified. Use the
143 : * OGRGeometry::clone() method to make a separate copy within the application.
144 : *
145 : * Relates to the Simple Features for COM (SFCOM) IPolygon::get_ExteriorRing()
146 : * method.
147 : * TODO(rouault): What does that mean?
148 : *
149 : * @return pointer to external ring. May be NULL if the OGRCurvePolygon is
150 : * empty.
151 : */
152 :
153 125023 : OGRCurve *OGRCurvePolygon::getExteriorRingCurve()
154 :
155 : {
156 125023 : return oCC.getCurve(0);
157 : }
158 :
159 : /**
160 : * \brief Fetch reference to external polygon ring.
161 : *
162 : * Note that the returned ring pointer is to an internal data object of the
163 : * OGRCurvePolygon. It should not be modified or deleted by the application,
164 : * and the pointer is only valid till the polygon is next modified. Use the
165 : * OGRGeometry::clone() method to make a separate copy within the application.
166 : *
167 : * Relates to the SFCOM IPolygon::get_ExteriorRing() method.
168 : *
169 : * @return pointer to external ring. May be NULL if the OGRCurvePolygon is
170 : * empty.
171 : */
172 123793 : const OGRCurve *OGRCurvePolygon::getExteriorRingCurve() const
173 :
174 : {
175 123793 : return oCC.getCurve(0);
176 : }
177 :
178 : /************************************************************************/
179 : /* getNumInteriorRings() */
180 : /************************************************************************/
181 :
182 : /**
183 : * \brief Fetch the number of internal rings.
184 : *
185 : * Relates to the SFCOM IPolygon::get_NumInteriorRings() method.
186 : *
187 : * @return count of internal rings, zero or more.
188 : */
189 :
190 314574 : int OGRCurvePolygon::getNumInteriorRings() const
191 :
192 : {
193 314574 : if (oCC.nCurveCount > 0)
194 314561 : return oCC.nCurveCount - 1;
195 : else
196 13 : return 0;
197 : }
198 :
199 : /************************************************************************/
200 : /* getInteriorRingCurve() */
201 : /************************************************************************/
202 :
203 : /**
204 : * \brief Fetch reference to indicated internal ring.
205 : *
206 : * Note that the returned ring pointer is to an internal data object of the
207 : * OGRCurvePolygon. It should not be modified or deleted by the application,
208 : * and the pointer is only valid till the polygon is next modified. Use the
209 : * OGRGeometry::clone() method to make a separate copy within the application.
210 : *
211 : * Relates to the SFCOM IPolygon::get_InternalRing() method.
212 : *
213 : * @param iRing internal ring index from 0 to getNumInteriorRings() - 1.
214 : *
215 : * @return pointer to interior ring. May be NULL.
216 : */
217 :
218 95 : OGRCurve *OGRCurvePolygon::getInteriorRingCurve(int iRing)
219 :
220 : {
221 95 : return oCC.getCurve(iRing + 1);
222 : }
223 :
224 : /**
225 : * \brief Fetch reference to indicated internal ring.
226 : *
227 : * Note that the returned ring pointer is to an internal data object of the
228 : * OGRCurvePolygon. It should not be modified or deleted by the application,
229 : * and the pointer is only valid till the polygon is next modified. Use the
230 : * OGRGeometry::clone() method to make a separate copy within the application.
231 : *
232 : * Relates to the SFCOM IPolygon::get_InternalRing() method.
233 : *
234 : * @param iRing internal ring index from 0 to getNumInteriorRings() - 1.
235 : *
236 : * @return pointer to interior ring. May be NULL.
237 : */
238 :
239 18 : const OGRCurve *OGRCurvePolygon::getInteriorRingCurve(int iRing) const
240 :
241 : {
242 18 : return oCC.getCurve(iRing + 1);
243 : }
244 :
245 : /************************************************************************/
246 : /* stealExteriorRingCurve() */
247 : /************************************************************************/
248 :
249 : /**
250 : * \brief "Steal" reference to external ring.
251 : *
252 : * After the call to that function, only call to stealInteriorRing() or
253 : * destruction of the OGRCurvePolygon is valid. Other operations may crash.
254 : *
255 : * @return pointer to external ring. May be NULL if the OGRCurvePolygon is
256 : * empty.
257 : */
258 :
259 1051 : OGRCurve *OGRCurvePolygon::stealExteriorRingCurve()
260 : {
261 1051 : if (oCC.nCurveCount == 0)
262 2 : return nullptr;
263 1049 : OGRCurve *poRet = oCC.papoCurves[0];
264 1049 : oCC.papoCurves[0] = nullptr;
265 1049 : return poRet;
266 : }
267 :
268 : /************************************************************************/
269 : /* removeRing() */
270 : /************************************************************************/
271 :
272 : /**
273 : * \brief Remove a geometry from the container.
274 : *
275 : * Removing a geometry will cause the geometry count to drop by one, and all
276 : * "higher" geometries will shuffle down one in index.
277 : *
278 : * There is no SFCOM analog to this method.
279 : *
280 : * @param iIndex the index of the geometry to delete. A value of -1 is a
281 : * special flag meaning that all geometries should be removed.
282 : *
283 : * @param bDelete if true the geometry will be deallocated, otherwise it will
284 : * not. The default is true as the container is considered to own the
285 : * geometries in it.
286 : *
287 : * @return OGRERR_NONE if successful, or OGRERR_FAILURE if the index is
288 : * out of range.
289 : */
290 :
291 16 : OGRErr OGRCurvePolygon::removeRing(int iIndex, bool bDelete)
292 : {
293 16 : return oCC.removeCurve(iIndex, bDelete);
294 : }
295 :
296 : /************************************************************************/
297 : /* addRing() */
298 : /************************************************************************/
299 :
300 : /**
301 : * \brief Add a ring to a polygon.
302 : *
303 : * If the polygon has no external ring (it is empty) this will be used as
304 : * the external ring, otherwise it is used as an internal ring. The passed
305 : * OGRCurve remains the responsibility of the caller (an internal copy
306 : * is made).
307 : *
308 : * This method has no SFCOM analog.
309 : *
310 : * @param poNewRing ring to be added to the polygon.
311 : * @return OGRERR_NONE in case of success
312 : */
313 :
314 2168 : OGRErr OGRCurvePolygon::addRing(const OGRCurve *poNewRing)
315 :
316 : {
317 2168 : OGRCurve *poNewRingCloned = poNewRing->clone();
318 2167 : OGRErr eErr = addRingDirectly(poNewRingCloned);
319 2168 : if (eErr != OGRERR_NONE)
320 0 : delete poNewRingCloned;
321 2169 : return eErr;
322 : }
323 :
324 : /************************************************************************/
325 : /* isRingCorrectType() */
326 : /************************************************************************/
327 685 : bool OGRCurvePolygon::isRingCorrectType(const OGRCurve *poRing) const
328 : {
329 685 : return poRing && !EQUAL(poRing->getGeometryName(), "LINEARRING");
330 : }
331 :
332 : /************************************************************************/
333 : /* checkRing() */
334 : /************************************************************************/
335 :
336 681 : bool OGRCurvePolygon::checkRing(const OGRCurve *poNewRing) const
337 : {
338 681 : if (!isRingCorrectType(poNewRing))
339 : {
340 1 : CPLError(CE_Failure, CPLE_AppDefined, "Linearring not allowed.");
341 1 : return false;
342 : }
343 :
344 680 : if (!poNewRing->IsEmpty() && !poNewRing->get_IsClosed())
345 : {
346 : // This configuration option name must be the same as in
347 : // OGRPolygon::checkRing()
348 : const char *pszEnvVar =
349 9 : CPLGetConfigOption("OGR_GEOMETRY_ACCEPT_UNCLOSED_RING", nullptr);
350 9 : if (pszEnvVar != nullptr && !CPLTestBool(pszEnvVar))
351 : {
352 2 : CPLError(CE_Failure, CPLE_AppDefined, "Non closed ring detected.");
353 2 : return false;
354 : }
355 : else
356 : {
357 7 : CPLError(CE_Warning, CPLE_AppDefined, "Non closed ring detected.%s",
358 : pszEnvVar == nullptr
359 : ? " To avoid accepting it, set the "
360 : "OGR_GEOMETRY_ACCEPT_UNCLOSED_RING configuration "
361 : "option to NO"
362 : : "");
363 : }
364 : }
365 :
366 678 : if (wkbFlatten(poNewRing->getGeometryType()) == wkbLineString)
367 : {
368 221 : if (poNewRing->getNumPoints() < 4)
369 : {
370 8 : return false;
371 : }
372 : }
373 :
374 670 : return true;
375 : }
376 :
377 : /************************************************************************/
378 : /* addRingDirectly() */
379 : /************************************************************************/
380 :
381 : /**
382 : * \brief Add a ring to a polygon.
383 : *
384 : * If the polygon has no external ring (it is empty) this will be used as
385 : * the external ring, otherwise it is used as an internal ring. Ownership
386 : * of the passed ring is assumed by the OGRCurvePolygon, but otherwise this
387 : * method operates the same as OGRCurvePolygon::AddRing().
388 : *
389 : * This method has no SFCOM analog.
390 : *
391 : * @param poNewRing ring to be added to the polygon.
392 : * @return OGRERR_NONE in case of success
393 : */
394 :
395 157353 : OGRErr OGRCurvePolygon::addRingDirectly(OGRCurve *poNewRing)
396 : {
397 157353 : return addRingDirectlyInternal(poNewRing, TRUE);
398 : }
399 :
400 208669 : OGRErr OGRCurvePolygon::addRingDirectlyInternal(OGRCurve *poNewRing,
401 : int bNeedRealloc)
402 : {
403 208669 : if (!checkRing(poNewRing))
404 14 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
405 :
406 208655 : HomogenizeDimensionalityWith(poNewRing);
407 :
408 208655 : return oCC.addCurveDirectly(this, poNewRing, bNeedRealloc);
409 : }
410 :
411 : /************************************************************************/
412 : /* addRing() */
413 : /************************************************************************/
414 :
415 : /**
416 : * \brief Add a ring to a polygon.
417 : *
418 : * If the polygon has no external ring (it is empty) this will be used as
419 : * the external ring, otherwise it is used as an internal ring.
420 : *
421 : * This method has no SFCOM analog.
422 : *
423 : * @param poNewRing ring to be added to the polygon.
424 : * @return OGRERR_NONE in case of success
425 : */
426 51278 : OGRErr OGRCurvePolygon::addRing(std::unique_ptr<OGRCurve> poNewRing)
427 : {
428 51278 : OGRCurve *poNewRingPtr = poNewRing.release();
429 51278 : OGRErr eErr = addRingDirectlyInternal(poNewRingPtr, TRUE);
430 51278 : if (eErr != OGRERR_NONE)
431 0 : delete poNewRingPtr;
432 51278 : return eErr;
433 : }
434 :
435 : /************************************************************************/
436 : /* WkbSize() */
437 : /* */
438 : /* Return the size of this object in well known binary */
439 : /* representation including the byte order, and type information. */
440 : /************************************************************************/
441 :
442 205 : size_t OGRCurvePolygon::WkbSize() const
443 :
444 : {
445 205 : return oCC.WkbSize();
446 : }
447 :
448 : /************************************************************************/
449 : /* addCurveDirectlyFromWkb() */
450 : /************************************************************************/
451 :
452 22 : OGRErr OGRCurvePolygon::addCurveDirectlyFromWkb(OGRGeometry *poSelf,
453 : OGRCurve *poCurve)
454 : {
455 22 : OGRCurvePolygon *poCP = poSelf->toCurvePolygon();
456 22 : return poCP->addRingDirectlyInternal(poCurve, FALSE);
457 : }
458 :
459 : /************************************************************************/
460 : /* importFromWkb() */
461 : /* */
462 : /* Initialize from serialized stream in well known binary */
463 : /* format. */
464 : /************************************************************************/
465 :
466 24 : OGRErr OGRCurvePolygon::importFromWkb(const unsigned char *pabyData,
467 : size_t nSize, OGRwkbVariant eWkbVariant,
468 : size_t &nBytesConsumedOut)
469 :
470 : {
471 24 : nBytesConsumedOut = 0;
472 : OGRwkbByteOrder eByteOrder;
473 24 : size_t nDataOffset = 0;
474 : // coverity[tainted_data]
475 24 : OGRErr eErr = oCC.importPreambleFromWkb(this, pabyData, nSize, nDataOffset,
476 : eByteOrder, 9, eWkbVariant);
477 24 : if (eErr != OGRERR_NONE)
478 0 : return eErr;
479 :
480 24 : eErr = oCC.importBodyFromWkb(this, pabyData + nDataOffset, nSize,
481 : true, // bAcceptCompoundCurve
482 : addCurveDirectlyFromWkb, eWkbVariant,
483 : nBytesConsumedOut);
484 24 : if (eErr == OGRERR_NONE)
485 24 : nBytesConsumedOut += nDataOffset;
486 24 : return eErr;
487 : }
488 :
489 : /************************************************************************/
490 : /* exportToWkb() */
491 : /* */
492 : /* Build a well known binary representation of this object. */
493 : /************************************************************************/
494 :
495 33 : OGRErr OGRCurvePolygon::exportToWkb(unsigned char *pabyData,
496 : const OGRwkbExportOptions *psOptions) const
497 : {
498 : OGRwkbExportOptions sOptions(psOptions ? *psOptions
499 33 : : OGRwkbExportOptions());
500 :
501 : // Does not make sense for new geometries, so patch it.
502 33 : if (sOptions.eWkbVariant == wkbVariantOldOgc)
503 14 : sOptions.eWkbVariant = wkbVariantIso;
504 66 : return oCC.exportToWkb(this, pabyData, &sOptions);
505 : }
506 :
507 : /************************************************************************/
508 : /* addCurveDirectlyFromWkt() */
509 : /************************************************************************/
510 :
511 360 : OGRErr OGRCurvePolygon::addCurveDirectlyFromWkt(OGRGeometry *poSelf,
512 : OGRCurve *poCurve)
513 : {
514 360 : OGRCurvePolygon *poCP = poSelf->toCurvePolygon();
515 360 : return poCP->addRingDirectly(poCurve);
516 : }
517 :
518 : /************************************************************************/
519 : /* importFromWkt() */
520 : /* */
521 : /* Instantiate from well known text format. */
522 : /************************************************************************/
523 :
524 332 : OGRErr OGRCurvePolygon::importFromWkt(const char **ppszInput)
525 :
526 : {
527 332 : return importCurveCollectionFromWkt(ppszInput,
528 : FALSE, // bAllowEmptyComponent
529 : TRUE, // bAllowLineString
530 : TRUE, // bAllowCurve
531 : TRUE, // bAllowCompoundCurve
532 332 : addCurveDirectlyFromWkt);
533 : }
534 :
535 : /************************************************************************/
536 : /* exportToWkt() */
537 : /************************************************************************/
538 :
539 133 : std::string OGRCurvePolygon::exportToWkt(const OGRWktOptions &opts,
540 : OGRErr *err) const
541 : {
542 133 : return oCC.exportToWkt(this, opts, err);
543 : }
544 :
545 : /************************************************************************/
546 : /* CurvePolyToPoly() */
547 : /************************************************************************/
548 :
549 : /**
550 : * \brief Return a polygon from a curve polygon.
551 : *
552 : * This method is the same as C function OGR_G_CurvePolyToPoly().
553 : *
554 : * The returned geometry is a new instance whose ownership belongs to
555 : * the caller.
556 : *
557 : * @param dfMaxAngleStepSizeDegrees the largest step in degrees along the
558 : * arc, zero to use the default setting.
559 : * @param papszOptions options as a null-terminated list of strings.
560 : * Unused for now. Must be set to NULL.
561 : *
562 : * @return a linestring
563 : */
564 :
565 : OGRPolygon *
566 404 : OGRCurvePolygon::CurvePolyToPoly(double dfMaxAngleStepSizeDegrees,
567 : const char *const *papszOptions) const
568 : {
569 404 : OGRPolygon *poPoly = new OGRPolygon();
570 404 : poPoly->assignSpatialReference(getSpatialReference());
571 866 : for (int iRing = 0; iRing < oCC.nCurveCount; iRing++)
572 : {
573 924 : OGRLineString *poLS = oCC.papoCurves[iRing]->CurveToLine(
574 462 : dfMaxAngleStepSizeDegrees, papszOptions);
575 462 : OGRLinearRing *poRing = OGRCurve::CastToLinearRing(poLS);
576 462 : if (poRing == nullptr)
577 : {
578 0 : CPLError(CE_Failure, CPLE_IllegalArg,
579 : "OGRCurve::CastToLinearRing failed");
580 0 : break;
581 : }
582 462 : poPoly->addRingDirectly(poRing);
583 : }
584 404 : return poPoly;
585 : }
586 :
587 : /************************************************************************/
588 : /* hasCurveGeometry() */
589 : /************************************************************************/
590 :
591 636 : OGRBoolean OGRCurvePolygon::hasCurveGeometry(int bLookForNonLinear) const
592 : {
593 636 : if (bLookForNonLinear)
594 : {
595 84 : return oCC.hasCurveGeometry(bLookForNonLinear);
596 : }
597 :
598 552 : return TRUE;
599 : }
600 :
601 : /************************************************************************/
602 : /* getLinearGeometry() */
603 : /************************************************************************/
604 :
605 : OGRGeometry *
606 370 : OGRCurvePolygon::getLinearGeometry(double dfMaxAngleStepSizeDegrees,
607 : const char *const *papszOptions) const
608 : {
609 370 : return CurvePolyToPoly(dfMaxAngleStepSizeDegrees, papszOptions);
610 : }
611 :
612 : /************************************************************************/
613 : /* getEnvelope() */
614 : /************************************************************************/
615 :
616 259166 : void OGRCurvePolygon::getEnvelope(OGREnvelope *psEnvelope) const
617 :
618 : {
619 259166 : oCC.getEnvelope(psEnvelope);
620 259166 : }
621 :
622 : /************************************************************************/
623 : /* getEnvelope() */
624 : /************************************************************************/
625 :
626 381083 : void OGRCurvePolygon::getEnvelope(OGREnvelope3D *psEnvelope) const
627 :
628 : {
629 381083 : oCC.getEnvelope(psEnvelope);
630 381083 : }
631 :
632 : /************************************************************************/
633 : /* Equals() */
634 : /************************************************************************/
635 :
636 42619 : OGRBoolean OGRCurvePolygon::Equals(const OGRGeometry *poOther) const
637 :
638 : {
639 42619 : if (poOther == this)
640 1 : return TRUE;
641 :
642 42618 : if (poOther->getGeometryType() != getGeometryType())
643 1 : return FALSE;
644 :
645 42617 : if (IsEmpty() && poOther->IsEmpty())
646 6 : return TRUE;
647 :
648 42611 : return oCC.Equals(&(poOther->toCurvePolygon()->oCC));
649 : }
650 :
651 : /************************************************************************/
652 : /* transform() */
653 : /************************************************************************/
654 :
655 613 : OGRErr OGRCurvePolygon::transform(OGRCoordinateTransformation *poCT)
656 :
657 : {
658 613 : return oCC.transform(this, poCT);
659 : }
660 :
661 : /************************************************************************/
662 : /* get_Length() */
663 : /************************************************************************/
664 :
665 3 : double OGRCurvePolygon::get_Length() const
666 :
667 : {
668 3 : double dfLength = 0.0;
669 6 : for (const auto &poCurve : *this)
670 : {
671 3 : dfLength += poCurve->get_Length();
672 : }
673 :
674 3 : return dfLength;
675 : }
676 :
677 : /************************************************************************/
678 : /* get_GeodesicLength() */
679 : /************************************************************************/
680 :
681 14 : double OGRCurvePolygon::get_GeodesicLength(
682 : const OGRSpatialReference *poSRSOverride) const
683 :
684 : {
685 14 : if (!poSRSOverride)
686 14 : poSRSOverride = getSpatialReference();
687 :
688 14 : double dfLength = 0.0;
689 26 : for (const auto &poCurve : *this)
690 : {
691 14 : const double dfLocalLength = poCurve->get_GeodesicLength(poSRSOverride);
692 14 : if (dfLocalLength < 0)
693 2 : return dfLocalLength;
694 12 : dfLength += dfLocalLength;
695 : }
696 :
697 12 : return dfLength;
698 : }
699 :
700 : /************************************************************************/
701 : /* get_Area() */
702 : /************************************************************************/
703 :
704 61781 : double OGRCurvePolygon::get_Area() const
705 :
706 : {
707 61781 : if (getExteriorRingCurve() == nullptr)
708 2 : return 0.0;
709 :
710 61779 : double dfArea = getExteriorRingCurve()->get_Area();
711 :
712 61792 : for (int iRing = 0; iRing < getNumInteriorRings(); iRing++)
713 : {
714 13 : dfArea -= getInteriorRingCurve(iRing)->get_Area();
715 : }
716 :
717 61779 : return dfArea;
718 : }
719 :
720 : /************************************************************************/
721 : /* get_GeodesicArea() */
722 : /************************************************************************/
723 :
724 17 : double OGRCurvePolygon::get_GeodesicArea(
725 : const OGRSpatialReference *poSRSOverride) const
726 :
727 : {
728 17 : if (getExteriorRingCurve() == nullptr)
729 1 : return 0.0;
730 :
731 16 : if (!poSRSOverride)
732 16 : poSRSOverride = getSpatialReference();
733 :
734 16 : double dfArea = getExteriorRingCurve()->get_GeodesicArea(poSRSOverride);
735 16 : if (dfArea > 0)
736 : {
737 15 : for (int iRing = 0; iRing < getNumInteriorRings(); iRing++)
738 : {
739 1 : dfArea -=
740 1 : getInteriorRingCurve(iRing)->get_GeodesicArea(poSRSOverride);
741 : }
742 : }
743 :
744 16 : return dfArea;
745 : }
746 :
747 : /************************************************************************/
748 : /* setCoordinateDimension() */
749 : /************************************************************************/
750 :
751 63005 : bool OGRCurvePolygon::setCoordinateDimension(int nNewDimension)
752 :
753 : {
754 63005 : return oCC.setCoordinateDimension(this, nNewDimension);
755 : }
756 :
757 1459350 : bool OGRCurvePolygon::set3D(OGRBoolean bIs3D)
758 : {
759 1459350 : return oCC.set3D(this, bIs3D);
760 : }
761 :
762 231488 : bool OGRCurvePolygon::setMeasured(OGRBoolean bIsMeasured)
763 : {
764 231488 : return oCC.setMeasured(this, bIsMeasured);
765 : }
766 :
767 : /************************************************************************/
768 : /* assignSpatialReference() */
769 : /************************************************************************/
770 :
771 1508380 : void OGRCurvePolygon::assignSpatialReference(const OGRSpatialReference *poSR)
772 : {
773 1508380 : oCC.assignSpatialReference(this, poSR);
774 1508380 : }
775 :
776 : /************************************************************************/
777 : /* IsEmpty() */
778 : /************************************************************************/
779 :
780 573794 : OGRBoolean OGRCurvePolygon::IsEmpty() const
781 : {
782 573794 : return oCC.IsEmpty();
783 : }
784 :
785 : /************************************************************************/
786 : /* segmentize() */
787 : /************************************************************************/
788 :
789 43 : bool OGRCurvePolygon::segmentize(double dfMaxLength)
790 : {
791 43 : if (EQUAL(getGeometryName(), "TRIANGLE"))
792 : {
793 0 : CPLError(CE_Failure, CPLE_NotSupported,
794 : "segmentize() is not valid for Triangle");
795 0 : return false;
796 : }
797 43 : return oCC.segmentize(dfMaxLength);
798 : }
799 :
800 : /************************************************************************/
801 : /* swapXY() */
802 : /************************************************************************/
803 :
804 74 : void OGRCurvePolygon::swapXY()
805 : {
806 74 : oCC.swapXY();
807 74 : }
808 :
809 : /************************************************************************/
810 : /* ContainsPoint() */
811 : /************************************************************************/
812 :
813 15 : OGRBoolean OGRCurvePolygon::ContainsPoint(const OGRPoint *p) const
814 : {
815 15 : if (getExteriorRingCurve() != nullptr && getNumInteriorRings() == 0)
816 : {
817 15 : const int nRet = getExteriorRingCurve()->ContainsPoint(p);
818 15 : if (nRet >= 0)
819 5 : return nRet;
820 : }
821 :
822 10 : return OGRGeometry::Contains(p);
823 : }
824 :
825 : /************************************************************************/
826 : /* IntersectsPoint() */
827 : /************************************************************************/
828 :
829 3 : OGRBoolean OGRCurvePolygon::IntersectsPoint(const OGRPoint *p) const
830 : {
831 3 : if (getExteriorRingCurve() != nullptr && getNumInteriorRings() == 0)
832 : {
833 3 : const int nRet = getExteriorRingCurve()->IntersectsPoint(p);
834 3 : if (nRet >= 0)
835 2 : return nRet;
836 : }
837 :
838 1 : return OGRGeometry::Intersects(p);
839 : }
840 :
841 : /************************************************************************/
842 : /* Contains() */
843 : /************************************************************************/
844 :
845 37 : OGRBoolean OGRCurvePolygon::Contains(const OGRGeometry *poOtherGeom) const
846 :
847 : {
848 74 : if (!IsEmpty() && poOtherGeom != nullptr &&
849 37 : wkbFlatten(poOtherGeom->getGeometryType()) == wkbPoint)
850 : {
851 15 : return ContainsPoint(poOtherGeom->toPoint());
852 : }
853 :
854 22 : return OGRGeometry::Contains(poOtherGeom);
855 : }
856 :
857 : /************************************************************************/
858 : /* Intersects() */
859 : /************************************************************************/
860 :
861 10 : OGRBoolean OGRCurvePolygon::Intersects(const OGRGeometry *poOtherGeom) const
862 :
863 : {
864 20 : if (!IsEmpty() && poOtherGeom != nullptr &&
865 10 : wkbFlatten(poOtherGeom->getGeometryType()) == wkbPoint)
866 : {
867 3 : return IntersectsPoint(poOtherGeom->toPoint());
868 : }
869 :
870 7 : return OGRGeometry::Intersects(poOtherGeom);
871 : }
872 :
873 : /************************************************************************/
874 : /* CastToPolygon() */
875 : /************************************************************************/
876 :
877 : /**
878 : * \brief Convert to polygon.
879 : *
880 : * This method should only be called if the curve polygon actually only contains
881 : * instances of OGRLineString. This can be verified if hasCurveGeometry(TRUE)
882 : * returns FALSE. It is not intended to approximate curve polygons. For that
883 : * use getLinearGeometry().
884 : *
885 : * The passed in geometry is consumed and a new one returned (or NULL in case
886 : * of failure).
887 : *
888 : * @param poCP the input geometry - ownership is passed to the method.
889 : * @return new geometry.
890 : */
891 :
892 15 : OGRPolygon *OGRCurvePolygon::CastToPolygon(OGRCurvePolygon *poCP)
893 : {
894 29 : for (int i = 0; i < poCP->oCC.nCurveCount; i++)
895 : {
896 28 : poCP->oCC.papoCurves[i] =
897 14 : OGRCurve::CastToLinearRing(poCP->oCC.papoCurves[i]);
898 14 : if (poCP->oCC.papoCurves[i] == nullptr)
899 : {
900 0 : delete poCP;
901 0 : return nullptr;
902 : }
903 : }
904 15 : OGRPolygon *poPoly = new OGRPolygon();
905 15 : poPoly->setCoordinateDimension(poCP->getCoordinateDimension());
906 15 : poPoly->assignSpatialReference(poCP->getSpatialReference());
907 15 : poPoly->oCC.nCurveCount = poCP->oCC.nCurveCount;
908 15 : poPoly->oCC.papoCurves = poCP->oCC.papoCurves;
909 15 : poCP->oCC.nCurveCount = 0;
910 15 : poCP->oCC.papoCurves = nullptr;
911 15 : delete poCP;
912 15 : return poPoly;
913 : }
914 :
915 : //! @cond Doxygen_Suppress
916 : /************************************************************************/
917 : /* GetCasterToPolygon() */
918 : /************************************************************************/
919 :
920 15 : OGRPolygon *OGRCurvePolygon::CasterToPolygon(OGRSurface *poSurface)
921 : {
922 15 : OGRCurvePolygon *poCurvePoly = poSurface->toCurvePolygon();
923 15 : return OGRCurvePolygon::CastToPolygon(poCurvePoly);
924 : }
925 :
926 15 : OGRSurfaceCasterToPolygon OGRCurvePolygon::GetCasterToPolygon() const
927 : {
928 15 : return OGRCurvePolygon::CasterToPolygon;
929 : }
930 :
931 : /************************************************************************/
932 : /* GetCasterToCurvePolygon() */
933 : /************************************************************************/
934 :
935 0 : static OGRCurvePolygon *CasterToCurvePolygon(OGRSurface *poSurface)
936 : {
937 0 : return poSurface->toCurvePolygon();
938 : }
939 :
940 0 : OGRSurfaceCasterToCurvePolygon OGRCurvePolygon::GetCasterToCurvePolygon() const
941 : {
942 0 : return ::CasterToCurvePolygon;
943 : }
944 :
945 : //! @endcond
946 :
947 : /************************************************************************/
948 : /* hasEmptyParts() */
949 : /************************************************************************/
950 :
951 96 : bool OGRCurvePolygon::hasEmptyParts() const
952 : {
953 96 : return oCC.hasEmptyParts();
954 : }
955 :
956 : /************************************************************************/
957 : /* removeEmptyParts() */
958 : /************************************************************************/
959 :
960 7 : void OGRCurvePolygon::removeEmptyParts()
961 : {
962 7 : auto poExteriorRing = getExteriorRingCurve();
963 7 : if (poExteriorRing && poExteriorRing->IsEmpty())
964 0 : empty();
965 : else
966 7 : oCC.removeEmptyParts();
967 7 : }
|