/src/gdal/ogr/ogrcurvepolygon.cpp
Line | Count | Source |
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 | 0 | OGRCurvePolygon::OGRCurvePolygon(const OGRCurvePolygon &) = default; |
35 | | |
36 | | /************************************************************************/ |
37 | | /* operator=( const OGRCurvePolygon&) */ |
38 | | /************************************************************************/ |
39 | | |
40 | | /** |
41 | | * \brief Assignment operator. |
42 | | */ |
43 | | |
44 | | OGRCurvePolygon &OGRCurvePolygon::operator=(const OGRCurvePolygon &other) |
45 | 0 | { |
46 | 0 | if (this != &other) |
47 | 0 | { |
48 | 0 | OGRSurface::operator=(other); |
49 | |
|
50 | 0 | for (const auto *poRing : other.oCC) |
51 | 0 | { |
52 | 0 | if (!isRingCorrectType(poRing)) |
53 | 0 | { |
54 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
55 | 0 | "Illegal use of OGRCurvePolygon::operator=(): " |
56 | 0 | "trying to assign an incompatible sub-geometry"); |
57 | 0 | return *this; |
58 | 0 | } |
59 | 0 | } |
60 | | |
61 | 0 | oCC = other.oCC; |
62 | 0 | } |
63 | 0 | return *this; |
64 | 0 | } |
65 | | |
66 | | /************************************************************************/ |
67 | | /* clone() */ |
68 | | /************************************************************************/ |
69 | | |
70 | | OGRCurvePolygon *OGRCurvePolygon::clone() const |
71 | | |
72 | 0 | { |
73 | 0 | return new (std::nothrow) OGRCurvePolygon(*this); |
74 | 0 | } |
75 | | |
76 | | /************************************************************************/ |
77 | | /* empty() */ |
78 | | /************************************************************************/ |
79 | | |
80 | | void OGRCurvePolygon::empty() |
81 | | |
82 | 745 | { |
83 | 745 | oCC.empty(this); |
84 | 745 | } |
85 | | |
86 | | /************************************************************************/ |
87 | | /* getGeometryType() */ |
88 | | /************************************************************************/ |
89 | | |
90 | | OGRwkbGeometryType OGRCurvePolygon::getGeometryType() const |
91 | | |
92 | 1 | { |
93 | 1 | if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED)) |
94 | 0 | return wkbCurvePolygonZM; |
95 | 1 | else if (flags & OGR_G_MEASURED) |
96 | 1 | return wkbCurvePolygonM; |
97 | 0 | else if (flags & OGR_G_3D) |
98 | 0 | return wkbCurvePolygonZ; |
99 | 0 | else |
100 | 0 | return wkbCurvePolygon; |
101 | 1 | } |
102 | | |
103 | | /************************************************************************/ |
104 | | /* getDimension() */ |
105 | | /************************************************************************/ |
106 | | |
107 | | int OGRCurvePolygon::getDimension() const |
108 | | |
109 | 0 | { |
110 | 0 | return 2; |
111 | 0 | } |
112 | | |
113 | | /************************************************************************/ |
114 | | /* flattenTo2D() */ |
115 | | /************************************************************************/ |
116 | | |
117 | | void OGRCurvePolygon::flattenTo2D() |
118 | | |
119 | 0 | { |
120 | 0 | oCC.flattenTo2D(this); |
121 | 0 | } |
122 | | |
123 | | /************************************************************************/ |
124 | | /* getGeometryName() */ |
125 | | /************************************************************************/ |
126 | | |
127 | | const char *OGRCurvePolygon::getGeometryName() const |
128 | | |
129 | 107 | { |
130 | 107 | return "CURVEPOLYGON"; |
131 | 107 | } |
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 | | OGRCurve *OGRCurvePolygon::getExteriorRingCurve() |
154 | | |
155 | 6.22k | { |
156 | 6.22k | return oCC.getCurve(0); |
157 | 6.22k | } |
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 | | const OGRCurve *OGRCurvePolygon::getExteriorRingCurve() const |
173 | | |
174 | 0 | { |
175 | 0 | return oCC.getCurve(0); |
176 | 0 | } |
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 | | int OGRCurvePolygon::getNumInteriorRings() const |
191 | | |
192 | 4.23k | { |
193 | 4.23k | if (oCC.nCurveCount > 0) |
194 | 4.23k | return oCC.nCurveCount - 1; |
195 | 0 | else |
196 | 0 | return 0; |
197 | 4.23k | } |
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 | | OGRCurve *OGRCurvePolygon::getInteriorRingCurve(int iRing) |
219 | | |
220 | 307 | { |
221 | 307 | return oCC.getCurve(iRing + 1); |
222 | 307 | } |
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 | | const OGRCurve *OGRCurvePolygon::getInteriorRingCurve(int iRing) const |
240 | | |
241 | 0 | { |
242 | 0 | return oCC.getCurve(iRing + 1); |
243 | 0 | } |
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 | | OGRCurve *OGRCurvePolygon::stealExteriorRingCurve() |
260 | 0 | { |
261 | 0 | if (oCC.nCurveCount == 0) |
262 | 0 | return nullptr; |
263 | 0 | OGRCurve *poRet = oCC.papoCurves[0]; |
264 | 0 | oCC.papoCurves[0] = nullptr; |
265 | 0 | return poRet; |
266 | 0 | } |
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 | | OGRErr OGRCurvePolygon::removeRing(int iIndex, bool bDelete) |
292 | 0 | { |
293 | 0 | return oCC.removeCurve(iIndex, bDelete); |
294 | 0 | } |
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 | | OGRErr OGRCurvePolygon::addRing(const OGRCurve *poNewRing) |
315 | | |
316 | 0 | { |
317 | 0 | OGRCurve *poNewRingCloned = poNewRing->clone(); |
318 | 0 | OGRErr eErr = addRingDirectly(poNewRingCloned); |
319 | 0 | if (eErr != OGRERR_NONE) |
320 | 0 | delete poNewRingCloned; |
321 | 0 | return eErr; |
322 | 0 | } |
323 | | |
324 | | /************************************************************************/ |
325 | | /* isRingCorrectType() */ |
326 | | /************************************************************************/ |
327 | | bool OGRCurvePolygon::isRingCorrectType(const OGRCurve *poRing) const |
328 | 820 | { |
329 | 820 | return poRing && !EQUAL(poRing->getGeometryName(), "LINEARRING"); |
330 | 820 | } |
331 | | |
332 | | /************************************************************************/ |
333 | | /* checkRing() */ |
334 | | /************************************************************************/ |
335 | | |
336 | | bool OGRCurvePolygon::checkRing(const OGRCurve *poNewRing) const |
337 | 820 | { |
338 | 820 | if (!isRingCorrectType(poNewRing)) |
339 | 0 | { |
340 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Linearring not allowed."); |
341 | 0 | return false; |
342 | 0 | } |
343 | | |
344 | 820 | if (!poNewRing->IsEmpty() && !poNewRing->get_IsClosed()) |
345 | 638 | { |
346 | | // This configuration option name must be the same as in |
347 | | // OGRPolygon::checkRing() |
348 | 638 | const char *pszEnvVar = |
349 | 638 | CPLGetConfigOption("OGR_GEOMETRY_ACCEPT_UNCLOSED_RING", nullptr); |
350 | 638 | if (pszEnvVar != nullptr && !CPLTestBool(pszEnvVar)) |
351 | 0 | { |
352 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Non closed ring detected."); |
353 | 0 | return false; |
354 | 0 | } |
355 | 638 | else |
356 | 638 | { |
357 | 638 | CPLError(CE_Warning, CPLE_AppDefined, "Non closed ring detected.%s", |
358 | 638 | pszEnvVar == nullptr |
359 | 638 | ? " To avoid accepting it, set the " |
360 | 638 | "OGR_GEOMETRY_ACCEPT_UNCLOSED_RING configuration " |
361 | 638 | "option to NO" |
362 | 638 | : ""); |
363 | 638 | } |
364 | 638 | } |
365 | | |
366 | 820 | if (wkbFlatten(poNewRing->getGeometryType()) == wkbLineString) |
367 | 820 | { |
368 | 820 | if (poNewRing->getNumPoints() < 4) |
369 | 4 | { |
370 | 4 | return false; |
371 | 4 | } |
372 | 820 | } |
373 | | |
374 | 816 | return true; |
375 | 820 | } |
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 | | OGRErr OGRCurvePolygon::addRingDirectly(OGRCurve *poNewRing) |
396 | 820 | { |
397 | 820 | return addRingDirectlyInternal(poNewRing, TRUE); |
398 | 820 | } |
399 | | |
400 | | OGRErr OGRCurvePolygon::addRingDirectlyInternal(OGRCurve *poNewRing, |
401 | | int bNeedRealloc) |
402 | 820 | { |
403 | 820 | if (!checkRing(poNewRing)) |
404 | 4 | return OGRERR_UNSUPPORTED_GEOMETRY_TYPE; |
405 | | |
406 | 816 | HomogenizeDimensionalityWith(poNewRing); |
407 | | |
408 | 816 | return oCC.addCurveDirectly(this, poNewRing, bNeedRealloc); |
409 | 820 | } |
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 | | OGRErr OGRCurvePolygon::addRing(std::unique_ptr<OGRCurve> poNewRing) |
427 | 0 | { |
428 | 0 | OGRCurve *poNewRingPtr = poNewRing.release(); |
429 | 0 | OGRErr eErr = addRingDirectlyInternal(poNewRingPtr, TRUE); |
430 | 0 | if (eErr != OGRERR_NONE) |
431 | 0 | delete poNewRingPtr; |
432 | 0 | return eErr; |
433 | 0 | } |
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 | | size_t OGRCurvePolygon::WkbSize() const |
443 | | |
444 | 0 | { |
445 | 0 | return oCC.WkbSize(); |
446 | 0 | } |
447 | | |
448 | | /************************************************************************/ |
449 | | /* addCurveDirectlyFromWkb() */ |
450 | | /************************************************************************/ |
451 | | |
452 | | OGRErr OGRCurvePolygon::addCurveDirectlyFromWkb(OGRGeometry *poSelf, |
453 | | OGRCurve *poCurve) |
454 | 0 | { |
455 | 0 | OGRCurvePolygon *poCP = poSelf->toCurvePolygon(); |
456 | 0 | return poCP->addRingDirectlyInternal(poCurve, FALSE); |
457 | 0 | } |
458 | | |
459 | | /************************************************************************/ |
460 | | /* importFromWkb() */ |
461 | | /* */ |
462 | | /* Initialize from serialized stream in well known binary */ |
463 | | /* format. */ |
464 | | /************************************************************************/ |
465 | | |
466 | | OGRErr OGRCurvePolygon::importFromWkb(const unsigned char *pabyData, |
467 | | size_t nSize, OGRwkbVariant eWkbVariant, |
468 | | size_t &nBytesConsumedOut) |
469 | | |
470 | 0 | { |
471 | 0 | nBytesConsumedOut = 0; |
472 | 0 | OGRwkbByteOrder eByteOrder; |
473 | 0 | size_t nDataOffset = 0; |
474 | | // coverity[tainted_data] |
475 | 0 | OGRErr eErr = oCC.importPreambleFromWkb(this, pabyData, nSize, nDataOffset, |
476 | 0 | eByteOrder, 9, eWkbVariant); |
477 | 0 | if (eErr != OGRERR_NONE) |
478 | 0 | return eErr; |
479 | | |
480 | 0 | eErr = oCC.importBodyFromWkb(this, pabyData + nDataOffset, nSize, |
481 | 0 | true, // bAcceptCompoundCurve |
482 | 0 | addCurveDirectlyFromWkb, eWkbVariant, |
483 | 0 | nBytesConsumedOut); |
484 | 0 | if (eErr == OGRERR_NONE) |
485 | 0 | nBytesConsumedOut += nDataOffset; |
486 | 0 | return eErr; |
487 | 0 | } |
488 | | |
489 | | /************************************************************************/ |
490 | | /* exportToWkb() */ |
491 | | /* */ |
492 | | /* Build a well known binary representation of this object. */ |
493 | | /************************************************************************/ |
494 | | |
495 | | OGRErr OGRCurvePolygon::exportToWkb(unsigned char *pabyData, |
496 | | const OGRwkbExportOptions *psOptions) const |
497 | 0 | { |
498 | 0 | OGRwkbExportOptions sOptions(psOptions ? *psOptions |
499 | 0 | : OGRwkbExportOptions()); |
500 | | |
501 | | // Does not make sense for new geometries, so patch it. |
502 | 0 | if (sOptions.eWkbVariant == wkbVariantOldOgc) |
503 | 0 | sOptions.eWkbVariant = wkbVariantIso; |
504 | 0 | return oCC.exportToWkb(this, pabyData, &sOptions); |
505 | 0 | } |
506 | | |
507 | | /************************************************************************/ |
508 | | /* addCurveDirectlyFromWkt() */ |
509 | | /************************************************************************/ |
510 | | |
511 | | OGRErr OGRCurvePolygon::addCurveDirectlyFromWkt(OGRGeometry *poSelf, |
512 | | OGRCurve *poCurve) |
513 | 820 | { |
514 | 820 | OGRCurvePolygon *poCP = poSelf->toCurvePolygon(); |
515 | 820 | return poCP->addRingDirectly(poCurve); |
516 | 820 | } |
517 | | |
518 | | /************************************************************************/ |
519 | | /* importFromWkt() */ |
520 | | /* */ |
521 | | /* Instantiate from well known text format. */ |
522 | | /************************************************************************/ |
523 | | |
524 | | OGRErr OGRCurvePolygon::importFromWkt(const char **ppszInput) |
525 | | |
526 | 107 | { |
527 | 107 | return importCurveCollectionFromWkt(ppszInput, |
528 | 107 | FALSE, // bAllowEmptyComponent |
529 | 107 | TRUE, // bAllowLineString |
530 | 107 | TRUE, // bAllowCurve |
531 | 107 | TRUE, // bAllowCompoundCurve |
532 | 107 | addCurveDirectlyFromWkt); |
533 | 107 | } |
534 | | |
535 | | /************************************************************************/ |
536 | | /* exportToWkt() */ |
537 | | /************************************************************************/ |
538 | | |
539 | | std::string OGRCurvePolygon::exportToWkt(const OGRWktOptions &opts, |
540 | | OGRErr *err) const |
541 | 0 | { |
542 | 0 | return oCC.exportToWkt(this, opts, err); |
543 | 0 | } |
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 | | OGRCurvePolygon::CurvePolyToPoly(double dfMaxAngleStepSizeDegrees, |
567 | | const char *const *papszOptions) const |
568 | 0 | { |
569 | 0 | OGRPolygon *poPoly = new OGRPolygon(); |
570 | 0 | poPoly->assignSpatialReference(getSpatialReference()); |
571 | 0 | for (int iRing = 0; iRing < oCC.nCurveCount; iRing++) |
572 | 0 | { |
573 | 0 | OGRLineString *poLS = oCC.papoCurves[iRing]->CurveToLine( |
574 | 0 | dfMaxAngleStepSizeDegrees, papszOptions); |
575 | 0 | OGRLinearRing *poRing = OGRCurve::CastToLinearRing(poLS); |
576 | 0 | if (poRing == nullptr) |
577 | 0 | { |
578 | 0 | CPLError(CE_Failure, CPLE_IllegalArg, |
579 | 0 | "OGRCurve::CastToLinearRing failed"); |
580 | 0 | break; |
581 | 0 | } |
582 | 0 | poPoly->addRingDirectly(poRing); |
583 | 0 | } |
584 | 0 | return poPoly; |
585 | 0 | } |
586 | | |
587 | | /************************************************************************/ |
588 | | /* hasCurveGeometry() */ |
589 | | /************************************************************************/ |
590 | | |
591 | | OGRBoolean OGRCurvePolygon::hasCurveGeometry(int bLookForNonLinear) const |
592 | 1 | { |
593 | 1 | if (bLookForNonLinear) |
594 | 0 | { |
595 | 0 | return oCC.hasCurveGeometry(bLookForNonLinear); |
596 | 0 | } |
597 | | |
598 | 1 | return TRUE; |
599 | 1 | } |
600 | | |
601 | | /************************************************************************/ |
602 | | /* getLinearGeometry() */ |
603 | | /************************************************************************/ |
604 | | |
605 | | OGRGeometry * |
606 | | OGRCurvePolygon::getLinearGeometry(double dfMaxAngleStepSizeDegrees, |
607 | | const char *const *papszOptions) const |
608 | 0 | { |
609 | 0 | return CurvePolyToPoly(dfMaxAngleStepSizeDegrees, papszOptions); |
610 | 0 | } |
611 | | |
612 | | /************************************************************************/ |
613 | | /* getEnvelope() */ |
614 | | /************************************************************************/ |
615 | | |
616 | | void OGRCurvePolygon::getEnvelope(OGREnvelope *psEnvelope) const |
617 | | |
618 | 0 | { |
619 | 0 | oCC.getEnvelope(psEnvelope); |
620 | 0 | } |
621 | | |
622 | | /************************************************************************/ |
623 | | /* getEnvelope() */ |
624 | | /************************************************************************/ |
625 | | |
626 | | void OGRCurvePolygon::getEnvelope(OGREnvelope3D *psEnvelope) const |
627 | | |
628 | 0 | { |
629 | 0 | oCC.getEnvelope(psEnvelope); |
630 | 0 | } |
631 | | |
632 | | /************************************************************************/ |
633 | | /* Equals() */ |
634 | | /************************************************************************/ |
635 | | |
636 | | OGRBoolean OGRCurvePolygon::Equals(const OGRGeometry *poOther) const |
637 | | |
638 | 0 | { |
639 | 0 | if (poOther == this) |
640 | 0 | return TRUE; |
641 | | |
642 | 0 | if (poOther->getGeometryType() != getGeometryType()) |
643 | 0 | return FALSE; |
644 | | |
645 | 0 | if (IsEmpty() && poOther->IsEmpty()) |
646 | 0 | return TRUE; |
647 | | |
648 | 0 | return oCC.Equals(&(poOther->toCurvePolygon()->oCC)); |
649 | 0 | } |
650 | | |
651 | | /************************************************************************/ |
652 | | /* transform() */ |
653 | | /************************************************************************/ |
654 | | |
655 | | OGRErr OGRCurvePolygon::transform(OGRCoordinateTransformation *poCT) |
656 | | |
657 | 0 | { |
658 | 0 | return oCC.transform(this, poCT); |
659 | 0 | } |
660 | | |
661 | | /************************************************************************/ |
662 | | /* get_Length() */ |
663 | | /************************************************************************/ |
664 | | |
665 | | double OGRCurvePolygon::get_Length() const |
666 | | |
667 | 0 | { |
668 | 0 | double dfLength = 0.0; |
669 | 0 | for (const auto &poCurve : *this) |
670 | 0 | { |
671 | 0 | dfLength += poCurve->get_Length(); |
672 | 0 | } |
673 | |
|
674 | 0 | return dfLength; |
675 | 0 | } |
676 | | |
677 | | /************************************************************************/ |
678 | | /* get_GeodesicLength() */ |
679 | | /************************************************************************/ |
680 | | |
681 | | double OGRCurvePolygon::get_GeodesicLength( |
682 | | const OGRSpatialReference *poSRSOverride) const |
683 | | |
684 | 0 | { |
685 | 0 | if (!poSRSOverride) |
686 | 0 | poSRSOverride = getSpatialReference(); |
687 | |
|
688 | 0 | double dfLength = 0.0; |
689 | 0 | for (const auto &poCurve : *this) |
690 | 0 | { |
691 | 0 | const double dfLocalLength = poCurve->get_GeodesicLength(poSRSOverride); |
692 | 0 | if (dfLocalLength < 0) |
693 | 0 | return dfLocalLength; |
694 | 0 | dfLength += dfLocalLength; |
695 | 0 | } |
696 | | |
697 | 0 | return dfLength; |
698 | 0 | } |
699 | | |
700 | | /************************************************************************/ |
701 | | /* get_Area() */ |
702 | | /************************************************************************/ |
703 | | |
704 | | double OGRCurvePolygon::get_Area() const |
705 | | |
706 | 0 | { |
707 | 0 | if (getExteriorRingCurve() == nullptr) |
708 | 0 | return 0.0; |
709 | | |
710 | 0 | double dfArea = getExteriorRingCurve()->get_Area(); |
711 | |
|
712 | 0 | for (int iRing = 0; iRing < getNumInteriorRings(); iRing++) |
713 | 0 | { |
714 | 0 | dfArea -= getInteriorRingCurve(iRing)->get_Area(); |
715 | 0 | } |
716 | |
|
717 | 0 | return dfArea; |
718 | 0 | } |
719 | | |
720 | | /************************************************************************/ |
721 | | /* get_GeodesicArea() */ |
722 | | /************************************************************************/ |
723 | | |
724 | | double OGRCurvePolygon::get_GeodesicArea( |
725 | | const OGRSpatialReference *poSRSOverride) const |
726 | | |
727 | 0 | { |
728 | 0 | if (getExteriorRingCurve() == nullptr) |
729 | 0 | return 0.0; |
730 | | |
731 | 0 | if (!poSRSOverride) |
732 | 0 | poSRSOverride = getSpatialReference(); |
733 | |
|
734 | 0 | double dfArea = getExteriorRingCurve()->get_GeodesicArea(poSRSOverride); |
735 | 0 | if (dfArea > 0) |
736 | 0 | { |
737 | 0 | for (int iRing = 0; iRing < getNumInteriorRings(); iRing++) |
738 | 0 | { |
739 | 0 | dfArea -= |
740 | 0 | getInteriorRingCurve(iRing)->get_GeodesicArea(poSRSOverride); |
741 | 0 | } |
742 | 0 | } |
743 | |
|
744 | 0 | return dfArea; |
745 | 0 | } |
746 | | |
747 | | /************************************************************************/ |
748 | | /* setCoordinateDimension() */ |
749 | | /************************************************************************/ |
750 | | |
751 | | bool OGRCurvePolygon::setCoordinateDimension(int nNewDimension) |
752 | | |
753 | 745 | { |
754 | 745 | return oCC.setCoordinateDimension(this, nNewDimension); |
755 | 745 | } |
756 | | |
757 | | bool OGRCurvePolygon::set3D(OGRBoolean bIs3D) |
758 | 819 | { |
759 | 819 | return oCC.set3D(this, bIs3D); |
760 | 819 | } |
761 | | |
762 | | bool OGRCurvePolygon::setMeasured(OGRBoolean bIsMeasured) |
763 | 1.71k | { |
764 | 1.71k | return oCC.setMeasured(this, bIsMeasured); |
765 | 1.71k | } |
766 | | |
767 | | /************************************************************************/ |
768 | | /* assignSpatialReference() */ |
769 | | /************************************************************************/ |
770 | | |
771 | | void OGRCurvePolygon::assignSpatialReference(const OGRSpatialReference *poSR) |
772 | 2.51k | { |
773 | 2.51k | oCC.assignSpatialReference(this, poSR); |
774 | 2.51k | } |
775 | | |
776 | | /************************************************************************/ |
777 | | /* IsEmpty() */ |
778 | | /************************************************************************/ |
779 | | |
780 | | OGRBoolean OGRCurvePolygon::IsEmpty() const |
781 | 0 | { |
782 | 0 | return oCC.IsEmpty(); |
783 | 0 | } |
784 | | |
785 | | /************************************************************************/ |
786 | | /* segmentize() */ |
787 | | /************************************************************************/ |
788 | | |
789 | | bool OGRCurvePolygon::segmentize(double dfMaxLength) |
790 | 0 | { |
791 | 0 | if (EQUAL(getGeometryName(), "TRIANGLE")) |
792 | 0 | { |
793 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
794 | 0 | "segmentize() is not valid for Triangle"); |
795 | 0 | return false; |
796 | 0 | } |
797 | 0 | return oCC.segmentize(dfMaxLength); |
798 | 0 | } |
799 | | |
800 | | /************************************************************************/ |
801 | | /* swapXY() */ |
802 | | /************************************************************************/ |
803 | | |
804 | | void OGRCurvePolygon::swapXY() |
805 | 0 | { |
806 | 0 | oCC.swapXY(); |
807 | 0 | } |
808 | | |
809 | | /************************************************************************/ |
810 | | /* ContainsPoint() */ |
811 | | /************************************************************************/ |
812 | | |
813 | | OGRBoolean OGRCurvePolygon::ContainsPoint(const OGRPoint *p) const |
814 | 0 | { |
815 | 0 | if (getExteriorRingCurve() != nullptr && getNumInteriorRings() == 0) |
816 | 0 | { |
817 | 0 | const int nRet = getExteriorRingCurve()->ContainsPoint(p); |
818 | 0 | if (nRet >= 0) |
819 | 0 | return nRet; |
820 | 0 | } |
821 | | |
822 | 0 | return OGRGeometry::Contains(p); |
823 | 0 | } |
824 | | |
825 | | /************************************************************************/ |
826 | | /* IntersectsPoint() */ |
827 | | /************************************************************************/ |
828 | | |
829 | | OGRBoolean OGRCurvePolygon::IntersectsPoint(const OGRPoint *p) const |
830 | 0 | { |
831 | 0 | if (getExteriorRingCurve() != nullptr && getNumInteriorRings() == 0) |
832 | 0 | { |
833 | 0 | const int nRet = getExteriorRingCurve()->IntersectsPoint(p); |
834 | 0 | if (nRet >= 0) |
835 | 0 | return nRet; |
836 | 0 | } |
837 | | |
838 | 0 | return OGRGeometry::Intersects(p); |
839 | 0 | } |
840 | | |
841 | | /************************************************************************/ |
842 | | /* Contains() */ |
843 | | /************************************************************************/ |
844 | | |
845 | | OGRBoolean OGRCurvePolygon::Contains(const OGRGeometry *poOtherGeom) const |
846 | | |
847 | 0 | { |
848 | 0 | if (!IsEmpty() && poOtherGeom != nullptr && |
849 | 0 | wkbFlatten(poOtherGeom->getGeometryType()) == wkbPoint) |
850 | 0 | { |
851 | 0 | return ContainsPoint(poOtherGeom->toPoint()); |
852 | 0 | } |
853 | | |
854 | 0 | return OGRGeometry::Contains(poOtherGeom); |
855 | 0 | } |
856 | | |
857 | | /************************************************************************/ |
858 | | /* Intersects() */ |
859 | | /************************************************************************/ |
860 | | |
861 | | OGRBoolean OGRCurvePolygon::Intersects(const OGRGeometry *poOtherGeom) const |
862 | | |
863 | 0 | { |
864 | 0 | if (!IsEmpty() && poOtherGeom != nullptr && |
865 | 0 | wkbFlatten(poOtherGeom->getGeometryType()) == wkbPoint) |
866 | 0 | { |
867 | 0 | return IntersectsPoint(poOtherGeom->toPoint()); |
868 | 0 | } |
869 | | |
870 | 0 | return OGRGeometry::Intersects(poOtherGeom); |
871 | 0 | } |
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 | | OGRPolygon *OGRCurvePolygon::CastToPolygon(OGRCurvePolygon *poCP) |
893 | 0 | { |
894 | 0 | for (int i = 0; i < poCP->oCC.nCurveCount; i++) |
895 | 0 | { |
896 | 0 | poCP->oCC.papoCurves[i] = |
897 | 0 | OGRCurve::CastToLinearRing(poCP->oCC.papoCurves[i]); |
898 | 0 | if (poCP->oCC.papoCurves[i] == nullptr) |
899 | 0 | { |
900 | 0 | delete poCP; |
901 | 0 | return nullptr; |
902 | 0 | } |
903 | 0 | } |
904 | 0 | OGRPolygon *poPoly = new OGRPolygon(); |
905 | 0 | poPoly->setCoordinateDimension(poCP->getCoordinateDimension()); |
906 | 0 | poPoly->assignSpatialReference(poCP->getSpatialReference()); |
907 | 0 | poPoly->oCC.nCurveCount = poCP->oCC.nCurveCount; |
908 | 0 | poPoly->oCC.papoCurves = poCP->oCC.papoCurves; |
909 | 0 | poCP->oCC.nCurveCount = 0; |
910 | 0 | poCP->oCC.papoCurves = nullptr; |
911 | 0 | delete poCP; |
912 | 0 | return poPoly; |
913 | 0 | } |
914 | | |
915 | | //! @cond Doxygen_Suppress |
916 | | /************************************************************************/ |
917 | | /* GetCasterToPolygon() */ |
918 | | /************************************************************************/ |
919 | | |
920 | | OGRPolygon *OGRCurvePolygon::CasterToPolygon(OGRSurface *poSurface) |
921 | 0 | { |
922 | 0 | OGRCurvePolygon *poCurvePoly = poSurface->toCurvePolygon(); |
923 | 0 | return OGRCurvePolygon::CastToPolygon(poCurvePoly); |
924 | 0 | } |
925 | | |
926 | | OGRSurfaceCasterToPolygon OGRCurvePolygon::GetCasterToPolygon() const |
927 | 0 | { |
928 | 0 | return OGRCurvePolygon::CasterToPolygon; |
929 | 0 | } |
930 | | |
931 | | /************************************************************************/ |
932 | | /* GetCasterToCurvePolygon() */ |
933 | | /************************************************************************/ |
934 | | |
935 | | static OGRCurvePolygon *CasterToCurvePolygon(OGRSurface *poSurface) |
936 | 0 | { |
937 | 0 | return poSurface->toCurvePolygon(); |
938 | 0 | } |
939 | | |
940 | | OGRSurfaceCasterToCurvePolygon OGRCurvePolygon::GetCasterToCurvePolygon() const |
941 | 0 | { |
942 | 0 | return ::CasterToCurvePolygon; |
943 | 0 | } |
944 | | |
945 | | //! @endcond |
946 | | |
947 | | /************************************************************************/ |
948 | | /* hasEmptyParts() */ |
949 | | /************************************************************************/ |
950 | | |
951 | | bool OGRCurvePolygon::hasEmptyParts() const |
952 | 0 | { |
953 | 0 | return oCC.hasEmptyParts(); |
954 | 0 | } |
955 | | |
956 | | /************************************************************************/ |
957 | | /* removeEmptyParts() */ |
958 | | /************************************************************************/ |
959 | | |
960 | | void OGRCurvePolygon::removeEmptyParts() |
961 | 0 | { |
962 | 0 | auto poExteriorRing = getExteriorRingCurve(); |
963 | 0 | if (poExteriorRing && poExteriorRing->IsEmpty()) |
964 | 0 | empty(); |
965 | 0 | else |
966 | 0 | oCC.removeEmptyParts(); |
967 | 0 | } |