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