/src/gdal/ogr/ogrcurvepolygon.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 0 | 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 | | OGRCurvePolygon &OGRCurvePolygon::operator=(const OGRCurvePolygon &other) |
55 | 0 | { |
56 | 0 | if (this != &other) |
57 | 0 | { |
58 | 0 | OGRSurface::operator=(other); |
59 | |
|
60 | 0 | for (const auto *poRing : other.oCC) |
61 | 0 | { |
62 | 0 | if (!isRingCorrectType(poRing)) |
63 | 0 | { |
64 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
65 | 0 | "Illegal use of OGRCurvePolygon::operator=(): " |
66 | 0 | "trying to assign an incompatible sub-geometry"); |
67 | 0 | return *this; |
68 | 0 | } |
69 | 0 | } |
70 | | |
71 | 0 | oCC = other.oCC; |
72 | 0 | } |
73 | 0 | return *this; |
74 | 0 | } |
75 | | |
76 | | /************************************************************************/ |
77 | | /* clone() */ |
78 | | /************************************************************************/ |
79 | | |
80 | | OGRCurvePolygon *OGRCurvePolygon::clone() const |
81 | | |
82 | 0 | { |
83 | 0 | return new (std::nothrow) OGRCurvePolygon(*this); |
84 | 0 | } |
85 | | |
86 | | /************************************************************************/ |
87 | | /* empty() */ |
88 | | /************************************************************************/ |
89 | | |
90 | | void OGRCurvePolygon::empty() |
91 | | |
92 | 0 | { |
93 | 0 | oCC.empty(this); |
94 | 0 | } |
95 | | |
96 | | /************************************************************************/ |
97 | | /* getGeometryType() */ |
98 | | /************************************************************************/ |
99 | | |
100 | | OGRwkbGeometryType OGRCurvePolygon::getGeometryType() const |
101 | | |
102 | 0 | { |
103 | 0 | if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED)) |
104 | 0 | return wkbCurvePolygonZM; |
105 | 0 | else if (flags & OGR_G_MEASURED) |
106 | 0 | return wkbCurvePolygonM; |
107 | 0 | else if (flags & OGR_G_3D) |
108 | 0 | return wkbCurvePolygonZ; |
109 | 0 | else |
110 | 0 | return wkbCurvePolygon; |
111 | 0 | } |
112 | | |
113 | | /************************************************************************/ |
114 | | /* getDimension() */ |
115 | | /************************************************************************/ |
116 | | |
117 | | int OGRCurvePolygon::getDimension() const |
118 | | |
119 | 0 | { |
120 | 0 | return 2; |
121 | 0 | } |
122 | | |
123 | | /************************************************************************/ |
124 | | /* flattenTo2D() */ |
125 | | /************************************************************************/ |
126 | | |
127 | | void OGRCurvePolygon::flattenTo2D() |
128 | | |
129 | 0 | { |
130 | 0 | oCC.flattenTo2D(this); |
131 | 0 | } |
132 | | |
133 | | /************************************************************************/ |
134 | | /* getGeometryName() */ |
135 | | /************************************************************************/ |
136 | | |
137 | | const char *OGRCurvePolygon::getGeometryName() const |
138 | | |
139 | 0 | { |
140 | 0 | return "CURVEPOLYGON"; |
141 | 0 | } |
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 | | OGRCurve *OGRCurvePolygon::getExteriorRingCurve() |
164 | | |
165 | 0 | { |
166 | 0 | return oCC.getCurve(0); |
167 | 0 | } |
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 | | const OGRCurve *OGRCurvePolygon::getExteriorRingCurve() const |
183 | | |
184 | 0 | { |
185 | 0 | return oCC.getCurve(0); |
186 | 0 | } |
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 | | int OGRCurvePolygon::getNumInteriorRings() const |
201 | | |
202 | 0 | { |
203 | 0 | if (oCC.nCurveCount > 0) |
204 | 0 | return oCC.nCurveCount - 1; |
205 | 0 | else |
206 | 0 | return 0; |
207 | 0 | } |
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 | | OGRCurve *OGRCurvePolygon::getInteriorRingCurve(int iRing) |
229 | | |
230 | 0 | { |
231 | 0 | return oCC.getCurve(iRing + 1); |
232 | 0 | } |
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 | | const OGRCurve *OGRCurvePolygon::getInteriorRingCurve(int iRing) const |
250 | | |
251 | 0 | { |
252 | 0 | return oCC.getCurve(iRing + 1); |
253 | 0 | } |
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 | | OGRCurve *OGRCurvePolygon::stealExteriorRingCurve() |
270 | 0 | { |
271 | 0 | if (oCC.nCurveCount == 0) |
272 | 0 | return nullptr; |
273 | 0 | OGRCurve *poRet = oCC.papoCurves[0]; |
274 | 0 | oCC.papoCurves[0] = nullptr; |
275 | 0 | return poRet; |
276 | 0 | } |
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 | | OGRErr OGRCurvePolygon::removeRing(int iIndex, bool bDelete) |
302 | 0 | { |
303 | 0 | return oCC.removeCurve(iIndex, bDelete); |
304 | 0 | } |
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 | | OGRErr OGRCurvePolygon::addRing(const OGRCurve *poNewRing) |
325 | | |
326 | 0 | { |
327 | 0 | OGRCurve *poNewRingCloned = poNewRing->clone(); |
328 | 0 | OGRErr eErr = addRingDirectly(poNewRingCloned); |
329 | 0 | if (eErr != OGRERR_NONE) |
330 | 0 | delete poNewRingCloned; |
331 | 0 | return eErr; |
332 | 0 | } |
333 | | |
334 | | /************************************************************************/ |
335 | | /* isRingCorrectType() */ |
336 | | /************************************************************************/ |
337 | | bool OGRCurvePolygon::isRingCorrectType(const OGRCurve *poRing) const |
338 | 0 | { |
339 | 0 | return poRing && !EQUAL(poRing->getGeometryName(), "LINEARRING"); |
340 | 0 | } |
341 | | |
342 | | /************************************************************************/ |
343 | | /* checkRing() */ |
344 | | /************************************************************************/ |
345 | | |
346 | | bool OGRCurvePolygon::checkRing(const OGRCurve *poNewRing) const |
347 | 0 | { |
348 | 0 | if (!isRingCorrectType(poNewRing)) |
349 | 0 | { |
350 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Linearring not allowed."); |
351 | 0 | return false; |
352 | 0 | } |
353 | | |
354 | 0 | if (!poNewRing->IsEmpty() && !poNewRing->get_IsClosed()) |
355 | 0 | { |
356 | | // This configuration option name must be the same as in |
357 | | // OGRPolygon::checkRing() |
358 | 0 | const char *pszEnvVar = |
359 | 0 | CPLGetConfigOption("OGR_GEOMETRY_ACCEPT_UNCLOSED_RING", nullptr); |
360 | 0 | if (pszEnvVar != nullptr && !CPLTestBool(pszEnvVar)) |
361 | 0 | { |
362 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Non closed ring detected."); |
363 | 0 | return false; |
364 | 0 | } |
365 | 0 | else |
366 | 0 | { |
367 | 0 | CPLError(CE_Warning, CPLE_AppDefined, "Non closed ring detected.%s", |
368 | 0 | pszEnvVar == nullptr |
369 | 0 | ? " To avoid accepting it, set the " |
370 | 0 | "OGR_GEOMETRY_ACCEPT_UNCLOSED_RING configuration " |
371 | 0 | "option to NO" |
372 | 0 | : ""); |
373 | 0 | } |
374 | 0 | } |
375 | | |
376 | 0 | if (wkbFlatten(poNewRing->getGeometryType()) == wkbLineString) |
377 | 0 | { |
378 | 0 | if (poNewRing->getNumPoints() < 4) |
379 | 0 | { |
380 | 0 | return false; |
381 | 0 | } |
382 | 0 | } |
383 | | |
384 | 0 | return true; |
385 | 0 | } |
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 | | OGRErr OGRCurvePolygon::addRingDirectly(OGRCurve *poNewRing) |
406 | 0 | { |
407 | 0 | return addRingDirectlyInternal(poNewRing, TRUE); |
408 | 0 | } |
409 | | |
410 | | OGRErr OGRCurvePolygon::addRingDirectlyInternal(OGRCurve *poNewRing, |
411 | | int bNeedRealloc) |
412 | 0 | { |
413 | 0 | if (!checkRing(poNewRing)) |
414 | 0 | return OGRERR_UNSUPPORTED_GEOMETRY_TYPE; |
415 | | |
416 | 0 | HomogenizeDimensionalityWith(poNewRing); |
417 | |
|
418 | 0 | return oCC.addCurveDirectly(this, poNewRing, bNeedRealloc); |
419 | 0 | } |
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 | | OGRErr OGRCurvePolygon::addRing(std::unique_ptr<OGRCurve> poNewRing) |
437 | 0 | { |
438 | 0 | OGRCurve *poNewRingPtr = poNewRing.release(); |
439 | 0 | OGRErr eErr = addRingDirectlyInternal(poNewRingPtr, TRUE); |
440 | 0 | if (eErr != OGRERR_NONE) |
441 | 0 | delete poNewRingPtr; |
442 | 0 | return eErr; |
443 | 0 | } |
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 | | size_t OGRCurvePolygon::WkbSize() const |
453 | | |
454 | 0 | { |
455 | 0 | return oCC.WkbSize(); |
456 | 0 | } |
457 | | |
458 | | /************************************************************************/ |
459 | | /* addCurveDirectlyFromWkb() */ |
460 | | /************************************************************************/ |
461 | | |
462 | | OGRErr OGRCurvePolygon::addCurveDirectlyFromWkb(OGRGeometry *poSelf, |
463 | | OGRCurve *poCurve) |
464 | 0 | { |
465 | 0 | OGRCurvePolygon *poCP = poSelf->toCurvePolygon(); |
466 | 0 | return poCP->addRingDirectlyInternal(poCurve, FALSE); |
467 | 0 | } |
468 | | |
469 | | /************************************************************************/ |
470 | | /* importFromWkb() */ |
471 | | /* */ |
472 | | /* Initialize from serialized stream in well known binary */ |
473 | | /* format. */ |
474 | | /************************************************************************/ |
475 | | |
476 | | OGRErr OGRCurvePolygon::importFromWkb(const unsigned char *pabyData, |
477 | | size_t nSize, OGRwkbVariant eWkbVariant, |
478 | | size_t &nBytesConsumedOut) |
479 | | |
480 | 0 | { |
481 | 0 | nBytesConsumedOut = 0; |
482 | 0 | OGRwkbByteOrder eByteOrder; |
483 | 0 | size_t nDataOffset = 0; |
484 | | // coverity[tainted_data] |
485 | 0 | OGRErr eErr = oCC.importPreambleFromWkb(this, pabyData, nSize, nDataOffset, |
486 | 0 | eByteOrder, 9, eWkbVariant); |
487 | 0 | if (eErr != OGRERR_NONE) |
488 | 0 | return eErr; |
489 | | |
490 | 0 | eErr = oCC.importBodyFromWkb(this, pabyData + nDataOffset, nSize, |
491 | 0 | true, // bAcceptCompoundCurve |
492 | 0 | addCurveDirectlyFromWkb, eWkbVariant, |
493 | 0 | nBytesConsumedOut); |
494 | 0 | if (eErr == OGRERR_NONE) |
495 | 0 | nBytesConsumedOut += nDataOffset; |
496 | 0 | return eErr; |
497 | 0 | } |
498 | | |
499 | | /************************************************************************/ |
500 | | /* exportToWkb() */ |
501 | | /* */ |
502 | | /* Build a well known binary representation of this object. */ |
503 | | /************************************************************************/ |
504 | | |
505 | | OGRErr OGRCurvePolygon::exportToWkb(unsigned char *pabyData, |
506 | | const OGRwkbExportOptions *psOptions) const |
507 | 0 | { |
508 | 0 | OGRwkbExportOptions sOptions(psOptions ? *psOptions |
509 | 0 | : OGRwkbExportOptions()); |
510 | | |
511 | | // Does not make sense for new geometries, so patch it. |
512 | 0 | if (sOptions.eWkbVariant == wkbVariantOldOgc) |
513 | 0 | sOptions.eWkbVariant = wkbVariantIso; |
514 | 0 | return oCC.exportToWkb(this, pabyData, &sOptions); |
515 | 0 | } |
516 | | |
517 | | /************************************************************************/ |
518 | | /* addCurveDirectlyFromWkt() */ |
519 | | /************************************************************************/ |
520 | | |
521 | | OGRErr OGRCurvePolygon::addCurveDirectlyFromWkt(OGRGeometry *poSelf, |
522 | | OGRCurve *poCurve) |
523 | 0 | { |
524 | 0 | OGRCurvePolygon *poCP = poSelf->toCurvePolygon(); |
525 | 0 | return poCP->addRingDirectly(poCurve); |
526 | 0 | } |
527 | | |
528 | | /************************************************************************/ |
529 | | /* importFromWkt() */ |
530 | | /* */ |
531 | | /* Instantiate from well known text format. */ |
532 | | /************************************************************************/ |
533 | | |
534 | | OGRErr OGRCurvePolygon::importFromWkt(const char **ppszInput) |
535 | | |
536 | 0 | { |
537 | 0 | return importCurveCollectionFromWkt(ppszInput, |
538 | 0 | FALSE, // bAllowEmptyComponent |
539 | 0 | TRUE, // bAllowLineString |
540 | 0 | TRUE, // bAllowCurve |
541 | 0 | TRUE, // bAllowCompoundCurve |
542 | 0 | addCurveDirectlyFromWkt); |
543 | 0 | } |
544 | | |
545 | | /************************************************************************/ |
546 | | /* exportToWkt() */ |
547 | | /************************************************************************/ |
548 | | |
549 | | std::string OGRCurvePolygon::exportToWkt(const OGRWktOptions &opts, |
550 | | OGRErr *err) const |
551 | 0 | { |
552 | 0 | return oCC.exportToWkt(this, opts, err); |
553 | 0 | } |
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 | | OGRCurvePolygon::CurvePolyToPoly(double dfMaxAngleStepSizeDegrees, |
579 | | const char *const *papszOptions) const |
580 | 0 | { |
581 | 0 | OGRPolygon *poPoly = new OGRPolygon(); |
582 | 0 | poPoly->assignSpatialReference(getSpatialReference()); |
583 | 0 | for (int iRing = 0; iRing < oCC.nCurveCount; iRing++) |
584 | 0 | { |
585 | 0 | OGRLineString *poLS = oCC.papoCurves[iRing]->CurveToLine( |
586 | 0 | dfMaxAngleStepSizeDegrees, papszOptions); |
587 | 0 | OGRLinearRing *poRing = OGRCurve::CastToLinearRing(poLS); |
588 | 0 | if (poRing == nullptr) |
589 | 0 | { |
590 | 0 | CPLError(CE_Failure, CPLE_IllegalArg, |
591 | 0 | "OGRCurve::CastToLinearRing failed"); |
592 | 0 | break; |
593 | 0 | } |
594 | 0 | poPoly->addRingDirectly(poRing); |
595 | 0 | } |
596 | 0 | return poPoly; |
597 | 0 | } |
598 | | |
599 | | /************************************************************************/ |
600 | | /* hasCurveGeometry() */ |
601 | | /************************************************************************/ |
602 | | |
603 | | OGRBoolean OGRCurvePolygon::hasCurveGeometry(int bLookForNonLinear) const |
604 | 0 | { |
605 | 0 | if (bLookForNonLinear) |
606 | 0 | { |
607 | 0 | return oCC.hasCurveGeometry(bLookForNonLinear); |
608 | 0 | } |
609 | | |
610 | 0 | return TRUE; |
611 | 0 | } |
612 | | |
613 | | /************************************************************************/ |
614 | | /* getLinearGeometry() */ |
615 | | /************************************************************************/ |
616 | | |
617 | | OGRGeometry * |
618 | | OGRCurvePolygon::getLinearGeometry(double dfMaxAngleStepSizeDegrees, |
619 | | const char *const *papszOptions) const |
620 | 0 | { |
621 | 0 | return CurvePolyToPoly(dfMaxAngleStepSizeDegrees, papszOptions); |
622 | 0 | } |
623 | | |
624 | | /************************************************************************/ |
625 | | /* getEnvelope() */ |
626 | | /************************************************************************/ |
627 | | |
628 | | void OGRCurvePolygon::getEnvelope(OGREnvelope *psEnvelope) const |
629 | | |
630 | 0 | { |
631 | 0 | oCC.getEnvelope(psEnvelope); |
632 | 0 | } |
633 | | |
634 | | /************************************************************************/ |
635 | | /* getEnvelope() */ |
636 | | /************************************************************************/ |
637 | | |
638 | | void OGRCurvePolygon::getEnvelope(OGREnvelope3D *psEnvelope) const |
639 | | |
640 | 0 | { |
641 | 0 | oCC.getEnvelope(psEnvelope); |
642 | 0 | } |
643 | | |
644 | | /************************************************************************/ |
645 | | /* Equals() */ |
646 | | /************************************************************************/ |
647 | | |
648 | | OGRBoolean OGRCurvePolygon::Equals(const OGRGeometry *poOther) const |
649 | | |
650 | 0 | { |
651 | 0 | if (poOther == this) |
652 | 0 | return TRUE; |
653 | | |
654 | 0 | if (poOther->getGeometryType() != getGeometryType()) |
655 | 0 | return FALSE; |
656 | | |
657 | 0 | if (IsEmpty() && poOther->IsEmpty()) |
658 | 0 | return TRUE; |
659 | | |
660 | 0 | return oCC.Equals(&(poOther->toCurvePolygon()->oCC)); |
661 | 0 | } |
662 | | |
663 | | /************************************************************************/ |
664 | | /* transform() */ |
665 | | /************************************************************************/ |
666 | | |
667 | | OGRErr OGRCurvePolygon::transform(OGRCoordinateTransformation *poCT) |
668 | | |
669 | 0 | { |
670 | 0 | return oCC.transform(this, poCT); |
671 | 0 | } |
672 | | |
673 | | /************************************************************************/ |
674 | | /* get_Length() */ |
675 | | /************************************************************************/ |
676 | | |
677 | | double OGRCurvePolygon::get_Length() const |
678 | | |
679 | 0 | { |
680 | 0 | double dfLength = 0.0; |
681 | 0 | for (const auto &poCurve : *this) |
682 | 0 | { |
683 | 0 | dfLength += poCurve->get_Length(); |
684 | 0 | } |
685 | |
|
686 | 0 | return dfLength; |
687 | 0 | } |
688 | | |
689 | | /************************************************************************/ |
690 | | /* get_GeodesicLength() */ |
691 | | /************************************************************************/ |
692 | | |
693 | | double OGRCurvePolygon::get_GeodesicLength( |
694 | | const OGRSpatialReference *poSRSOverride) const |
695 | | |
696 | 0 | { |
697 | 0 | if (!poSRSOverride) |
698 | 0 | poSRSOverride = getSpatialReference(); |
699 | |
|
700 | 0 | double dfLength = 0.0; |
701 | 0 | for (const auto &poCurve : *this) |
702 | 0 | { |
703 | 0 | const double dfLocalLength = poCurve->get_GeodesicLength(poSRSOverride); |
704 | 0 | if (dfLocalLength < 0) |
705 | 0 | return dfLocalLength; |
706 | 0 | dfLength += dfLocalLength; |
707 | 0 | } |
708 | | |
709 | 0 | return dfLength; |
710 | 0 | } |
711 | | |
712 | | /************************************************************************/ |
713 | | /* get_Area() */ |
714 | | /************************************************************************/ |
715 | | |
716 | | double OGRCurvePolygon::get_Area() const |
717 | | |
718 | 0 | { |
719 | 0 | if (getExteriorRingCurve() == nullptr) |
720 | 0 | return 0.0; |
721 | | |
722 | 0 | double dfArea = getExteriorRingCurve()->get_Area(); |
723 | |
|
724 | 0 | for (int iRing = 0; iRing < getNumInteriorRings(); iRing++) |
725 | 0 | { |
726 | 0 | dfArea -= getInteriorRingCurve(iRing)->get_Area(); |
727 | 0 | } |
728 | |
|
729 | 0 | return dfArea; |
730 | 0 | } |
731 | | |
732 | | /************************************************************************/ |
733 | | /* get_GeodesicArea() */ |
734 | | /************************************************************************/ |
735 | | |
736 | | double OGRCurvePolygon::get_GeodesicArea( |
737 | | const OGRSpatialReference *poSRSOverride) const |
738 | | |
739 | 0 | { |
740 | 0 | if (getExteriorRingCurve() == nullptr) |
741 | 0 | return 0.0; |
742 | | |
743 | 0 | if (!poSRSOverride) |
744 | 0 | poSRSOverride = getSpatialReference(); |
745 | |
|
746 | 0 | double dfArea = getExteriorRingCurve()->get_GeodesicArea(poSRSOverride); |
747 | 0 | if (dfArea > 0) |
748 | 0 | { |
749 | 0 | for (int iRing = 0; iRing < getNumInteriorRings(); iRing++) |
750 | 0 | { |
751 | 0 | dfArea -= |
752 | 0 | getInteriorRingCurve(iRing)->get_GeodesicArea(poSRSOverride); |
753 | 0 | } |
754 | 0 | } |
755 | |
|
756 | 0 | return dfArea; |
757 | 0 | } |
758 | | |
759 | | /************************************************************************/ |
760 | | /* setCoordinateDimension() */ |
761 | | /************************************************************************/ |
762 | | |
763 | | bool OGRCurvePolygon::setCoordinateDimension(int nNewDimension) |
764 | | |
765 | 0 | { |
766 | 0 | return oCC.setCoordinateDimension(this, nNewDimension); |
767 | 0 | } |
768 | | |
769 | | bool OGRCurvePolygon::set3D(OGRBoolean bIs3D) |
770 | 0 | { |
771 | 0 | return oCC.set3D(this, bIs3D); |
772 | 0 | } |
773 | | |
774 | | bool OGRCurvePolygon::setMeasured(OGRBoolean bIsMeasured) |
775 | 0 | { |
776 | 0 | return oCC.setMeasured(this, bIsMeasured); |
777 | 0 | } |
778 | | |
779 | | /************************************************************************/ |
780 | | /* assignSpatialReference() */ |
781 | | /************************************************************************/ |
782 | | |
783 | | void OGRCurvePolygon::assignSpatialReference(const OGRSpatialReference *poSR) |
784 | 0 | { |
785 | 0 | oCC.assignSpatialReference(this, poSR); |
786 | 0 | } |
787 | | |
788 | | /************************************************************************/ |
789 | | /* IsEmpty() */ |
790 | | /************************************************************************/ |
791 | | |
792 | | OGRBoolean OGRCurvePolygon::IsEmpty() const |
793 | 0 | { |
794 | 0 | return oCC.IsEmpty(); |
795 | 0 | } |
796 | | |
797 | | /************************************************************************/ |
798 | | /* segmentize() */ |
799 | | /************************************************************************/ |
800 | | |
801 | | bool OGRCurvePolygon::segmentize(double dfMaxLength) |
802 | 0 | { |
803 | 0 | if (EQUAL(getGeometryName(), "TRIANGLE")) |
804 | 0 | { |
805 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
806 | 0 | "segmentize() is not valid for Triangle"); |
807 | 0 | return false; |
808 | 0 | } |
809 | 0 | return oCC.segmentize(dfMaxLength); |
810 | 0 | } |
811 | | |
812 | | /************************************************************************/ |
813 | | /* swapXY() */ |
814 | | /************************************************************************/ |
815 | | |
816 | | void OGRCurvePolygon::swapXY() |
817 | 0 | { |
818 | 0 | oCC.swapXY(); |
819 | 0 | } |
820 | | |
821 | | /************************************************************************/ |
822 | | /* ContainsPoint() */ |
823 | | /************************************************************************/ |
824 | | |
825 | | OGRBoolean OGRCurvePolygon::ContainsPoint(const OGRPoint *p) const |
826 | 0 | { |
827 | 0 | if (getExteriorRingCurve() != nullptr && getNumInteriorRings() == 0) |
828 | 0 | { |
829 | 0 | const int nRet = getExteriorRingCurve()->ContainsPoint(p); |
830 | 0 | if (nRet >= 0) |
831 | 0 | return nRet; |
832 | 0 | } |
833 | | |
834 | 0 | return OGRGeometry::Contains(p); |
835 | 0 | } |
836 | | |
837 | | /************************************************************************/ |
838 | | /* IntersectsPoint() */ |
839 | | /************************************************************************/ |
840 | | |
841 | | OGRBoolean OGRCurvePolygon::IntersectsPoint(const OGRPoint *p) const |
842 | 0 | { |
843 | 0 | if (getExteriorRingCurve() != nullptr && getNumInteriorRings() == 0) |
844 | 0 | { |
845 | 0 | const int nRet = getExteriorRingCurve()->IntersectsPoint(p); |
846 | 0 | if (nRet >= 0) |
847 | 0 | return nRet; |
848 | 0 | } |
849 | | |
850 | 0 | return OGRGeometry::Intersects(p); |
851 | 0 | } |
852 | | |
853 | | /************************************************************************/ |
854 | | /* Contains() */ |
855 | | /************************************************************************/ |
856 | | |
857 | | OGRBoolean OGRCurvePolygon::Contains(const OGRGeometry *poOtherGeom) const |
858 | | |
859 | 0 | { |
860 | 0 | if (!IsEmpty() && poOtherGeom != nullptr && |
861 | 0 | wkbFlatten(poOtherGeom->getGeometryType()) == wkbPoint) |
862 | 0 | { |
863 | 0 | return ContainsPoint(poOtherGeom->toPoint()); |
864 | 0 | } |
865 | | |
866 | 0 | return OGRGeometry::Contains(poOtherGeom); |
867 | 0 | } |
868 | | |
869 | | /************************************************************************/ |
870 | | /* Intersects() */ |
871 | | /************************************************************************/ |
872 | | |
873 | | OGRBoolean OGRCurvePolygon::Intersects(const OGRGeometry *poOtherGeom) const |
874 | | |
875 | 0 | { |
876 | 0 | if (!IsEmpty() && poOtherGeom != nullptr && |
877 | 0 | wkbFlatten(poOtherGeom->getGeometryType()) == wkbPoint) |
878 | 0 | { |
879 | 0 | return IntersectsPoint(poOtherGeom->toPoint()); |
880 | 0 | } |
881 | | |
882 | 0 | return OGRGeometry::Intersects(poOtherGeom); |
883 | 0 | } |
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 | | OGRPolygon *OGRCurvePolygon::CastToPolygon(OGRCurvePolygon *poCP) |
905 | 0 | { |
906 | 0 | for (int i = 0; i < poCP->oCC.nCurveCount; i++) |
907 | 0 | { |
908 | 0 | poCP->oCC.papoCurves[i] = |
909 | 0 | OGRCurve::CastToLinearRing(poCP->oCC.papoCurves[i]); |
910 | 0 | if (poCP->oCC.papoCurves[i] == nullptr) |
911 | 0 | { |
912 | 0 | delete poCP; |
913 | 0 | return nullptr; |
914 | 0 | } |
915 | 0 | } |
916 | 0 | OGRPolygon *poPoly = new OGRPolygon(); |
917 | 0 | poPoly->setCoordinateDimension(poCP->getCoordinateDimension()); |
918 | 0 | poPoly->assignSpatialReference(poCP->getSpatialReference()); |
919 | 0 | poPoly->oCC.nCurveCount = poCP->oCC.nCurveCount; |
920 | 0 | poPoly->oCC.papoCurves = poCP->oCC.papoCurves; |
921 | 0 | poCP->oCC.nCurveCount = 0; |
922 | 0 | poCP->oCC.papoCurves = nullptr; |
923 | 0 | delete poCP; |
924 | 0 | return poPoly; |
925 | 0 | } |
926 | | |
927 | | //! @cond Doxygen_Suppress |
928 | | /************************************************************************/ |
929 | | /* GetCasterToPolygon() */ |
930 | | /************************************************************************/ |
931 | | |
932 | | OGRPolygon *OGRCurvePolygon::CasterToPolygon(OGRSurface *poSurface) |
933 | 0 | { |
934 | 0 | OGRCurvePolygon *poCurvePoly = poSurface->toCurvePolygon(); |
935 | 0 | return OGRCurvePolygon::CastToPolygon(poCurvePoly); |
936 | 0 | } |
937 | | |
938 | | OGRSurfaceCasterToPolygon OGRCurvePolygon::GetCasterToPolygon() const |
939 | 0 | { |
940 | 0 | return OGRCurvePolygon::CasterToPolygon; |
941 | 0 | } |
942 | | |
943 | | /************************************************************************/ |
944 | | /* GetCasterToCurvePolygon() */ |
945 | | /************************************************************************/ |
946 | | |
947 | | static OGRCurvePolygon *CasterToCurvePolygon(OGRSurface *poSurface) |
948 | 0 | { |
949 | 0 | return poSurface->toCurvePolygon(); |
950 | 0 | } |
951 | | |
952 | | OGRSurfaceCasterToCurvePolygon OGRCurvePolygon::GetCasterToCurvePolygon() const |
953 | 0 | { |
954 | 0 | return ::CasterToCurvePolygon; |
955 | 0 | } |
956 | | |
957 | | //! @endcond |
958 | | |
959 | | /************************************************************************/ |
960 | | /* hasEmptyParts() */ |
961 | | /************************************************************************/ |
962 | | |
963 | | bool OGRCurvePolygon::hasEmptyParts() const |
964 | 0 | { |
965 | 0 | return oCC.hasEmptyParts(); |
966 | 0 | } |
967 | | |
968 | | /************************************************************************/ |
969 | | /* removeEmptyParts() */ |
970 | | /************************************************************************/ |
971 | | |
972 | | void OGRCurvePolygon::removeEmptyParts() |
973 | 0 | { |
974 | 0 | auto poExteriorRing = getExteriorRingCurve(); |
975 | 0 | if (poExteriorRing && poExteriorRing->IsEmpty()) |
976 | 0 | empty(); |
977 | 0 | else |
978 | 0 | oCC.removeEmptyParts(); |
979 | 0 | } |