Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: The OGRPolygon geometry class.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Frank Warmerdam
9 : * Copyright (c) 2008-2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "ogr_geometry.h"
16 :
17 : #include <cstring>
18 : #include <cstddef>
19 : #include <new>
20 :
21 : #include "cpl_conv.h"
22 : #include "cpl_error.h"
23 : #include "cpl_vsi.h"
24 : #include "ogr_api.h"
25 : #include "ogr_core.h"
26 : #include "ogr_geos.h"
27 : #include "ogr_sfcgal.h"
28 : #include "ogr_p.h"
29 :
30 : /************************************************************************/
31 : /* OGRPolygon(double x1, double y1, double x2, double y2) */
32 : /************************************************************************/
33 :
34 : /**
35 : * \brief Construct a rectangular polygon from opposite corner coordinates.
36 : *
37 : * @since GDAL 3.11
38 : */
39 :
40 11 : OGRPolygon::OGRPolygon(double x1, double y1, double x2, double y2)
41 : {
42 22 : auto poLR = std::make_unique<OGRLinearRing>();
43 11 : poLR->addPoint(x1, y1);
44 11 : poLR->addPoint(x1, y2);
45 11 : poLR->addPoint(x2, y2);
46 11 : poLR->addPoint(x2, y1);
47 11 : poLR->addPoint(x1, y1);
48 11 : addRingDirectly(poLR.release());
49 11 : }
50 :
51 : /************************************************************************/
52 : /* OGRPolygon( const OGRPolygon& ) */
53 : /************************************************************************/
54 :
55 : /**
56 : * \brief Copy constructor.
57 : *
58 : * Note: before GDAL 2.1, only the default implementation of the constructor
59 : * existed, which could be unsafe to use.
60 : *
61 : * @since GDAL 2.1
62 : */
63 :
64 : OGRPolygon::OGRPolygon(const OGRPolygon &) = default;
65 :
66 : /************************************************************************/
67 : /* operator=( const OGRPolygon&) */
68 : /************************************************************************/
69 :
70 : /**
71 : * \brief Assignment operator.
72 : *
73 : * Note: before GDAL 2.1, only the default implementation of the operator
74 : * existed, which could be unsafe to use.
75 : *
76 : * @since GDAL 2.1
77 : */
78 :
79 9 : OGRPolygon &OGRPolygon::operator=(const OGRPolygon &other)
80 : {
81 9 : if (this != &other)
82 : {
83 8 : OGRCurvePolygon::operator=(other);
84 : }
85 9 : return *this;
86 : }
87 :
88 : /************************************************************************/
89 : /* clone() */
90 : /************************************************************************/
91 :
92 199090 : OGRPolygon *OGRPolygon::clone() const
93 :
94 : {
95 199090 : auto ret = new (std::nothrow) OGRPolygon(*this);
96 199090 : if (ret)
97 : {
98 199090 : if (ret->WkbSize() != WkbSize())
99 : {
100 0 : delete ret;
101 0 : ret = nullptr;
102 : }
103 : }
104 199090 : return ret;
105 : }
106 :
107 : /************************************************************************/
108 : /* getGeometryType() */
109 : /************************************************************************/
110 :
111 760858 : OGRwkbGeometryType OGRPolygon::getGeometryType() const
112 :
113 : {
114 760858 : if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
115 47469 : return wkbPolygonZM;
116 713389 : else if (flags & OGR_G_MEASURED)
117 811 : return wkbPolygonM;
118 712578 : else if (flags & OGR_G_3D)
119 124075 : return wkbPolygon25D;
120 : else
121 588503 : return wkbPolygon;
122 : }
123 :
124 : /************************************************************************/
125 : /* getGeometryName() */
126 : /************************************************************************/
127 :
128 21575 : const char *OGRPolygon::getGeometryName() const
129 :
130 : {
131 21575 : return "POLYGON";
132 : }
133 :
134 : /************************************************************************/
135 : /* getExteriorRing() */
136 : /************************************************************************/
137 :
138 : /**
139 : * \brief Fetch reference to external polygon ring.
140 : *
141 : * Note that the returned ring pointer is to an internal data object of
142 : * the OGRPolygon. It should not be modified or deleted by the application,
143 : * and the pointer is only valid till the polygon is next modified. Use
144 : * the OGRGeometry::clone() method to make a separate copy within the
145 : * application.
146 : *
147 : * Relates to the SFCOM IPolygon::get_ExteriorRing() method.
148 : *
149 : * @return pointer to external ring. May be NULL if the OGRPolygon is empty.
150 : */
151 :
152 32588 : OGRLinearRing *OGRPolygon::getExteriorRing()
153 :
154 : {
155 32588 : if (oCC.nCurveCount > 0)
156 32532 : return oCC.papoCurves[0]->toLinearRing();
157 :
158 56 : return nullptr;
159 : }
160 :
161 : /**
162 : * \brief Fetch reference to external polygon ring.
163 : *
164 : * Note that the returned ring pointer is to an internal data object of
165 : * the OGRPolygon. It should not be modified or deleted by the application,
166 : * and the pointer is only valid till the polygon is next modified. Use
167 : * the OGRGeometry::clone() method to make a separate copy within the
168 : * application.
169 : *
170 : * Relates to the SFCOM IPolygon::get_ExteriorRing() method.
171 : *
172 : * @return pointer to external ring. May be NULL if the OGRPolygon is empty.
173 : */
174 :
175 158497 : const OGRLinearRing *OGRPolygon::getExteriorRing() const
176 :
177 : {
178 158497 : if (oCC.nCurveCount > 0)
179 158392 : return oCC.papoCurves[0]->toLinearRing();
180 :
181 105 : return nullptr;
182 : }
183 :
184 : /************************************************************************/
185 : /* stealExteriorRing() */
186 : /************************************************************************/
187 :
188 : /**
189 : * \brief "Steal" reference to external polygon ring.
190 : *
191 : * After the call to that function, only call to stealInteriorRing() or
192 : * destruction of the OGRPolygon is valid. Other operations may crash.
193 : *
194 : * @return pointer to external ring. May be NULL if the OGRPolygon is empty.
195 : */
196 :
197 14 : OGRLinearRing *OGRPolygon::stealExteriorRing()
198 : {
199 14 : return stealExteriorRingCurve()->toLinearRing();
200 : }
201 :
202 : /************************************************************************/
203 : /* getInteriorRing() */
204 : /************************************************************************/
205 :
206 : /**
207 : * \brief Fetch reference to indicated internal ring.
208 : *
209 : * Note that the returned ring pointer is to an internal data object of
210 : * the OGRPolygon. It should not be modified or deleted by the application,
211 : * and the pointer is only valid till the polygon is next modified. Use
212 : * the OGRGeometry::clone() method to make a separate copy within the
213 : * application.
214 : *
215 : * Relates to the SFCOM IPolygon::get_InternalRing() method.
216 : *
217 : * @param iRing internal ring index from 0 to getNumInteriorRings() - 1.
218 : *
219 : * @return pointer to interior ring. May be NULL.
220 : */
221 :
222 35 : OGRLinearRing *OGRPolygon::getInteriorRing(int iRing)
223 :
224 : {
225 35 : if (iRing < 0 || iRing >= oCC.nCurveCount - 1)
226 0 : return nullptr;
227 :
228 35 : return oCC.papoCurves[iRing + 1]->toLinearRing();
229 : }
230 :
231 : /**
232 : * \brief Fetch reference to indicated internal ring.
233 : *
234 : * Note that the returned ring pointer is to an internal data object of
235 : * the OGRPolygon. It should not be modified or deleted by the application,
236 : * and the pointer is only valid till the polygon is next modified. Use
237 : * the OGRGeometry::clone() method to make a separate copy within the
238 : * application.
239 : *
240 : * Relates to the SFCOM IPolygon::get_InternalRing() method.
241 : *
242 : * @param iRing internal ring index from 0 to getNumInteriorRings() - 1.
243 : *
244 : * @return pointer to interior ring. May be NULL.
245 : */
246 :
247 700 : const OGRLinearRing *OGRPolygon::getInteriorRing(int iRing) const
248 :
249 : {
250 700 : if (iRing < 0 || iRing >= oCC.nCurveCount - 1)
251 0 : return nullptr;
252 :
253 700 : return oCC.papoCurves[iRing + 1]->toLinearRing();
254 : }
255 :
256 : /************************************************************************/
257 : /* stealInteriorRing() */
258 : /************************************************************************/
259 :
260 : /**
261 : * \brief "Steal" reference to indicated interior ring.
262 : *
263 : * After the call to that function, only call to stealInteriorRing() or
264 : * destruction of the OGRPolygon is valid. Other operations may crash.
265 : *
266 : * @param iRing internal ring index from 0 to getNumInteriorRings() - 1.
267 : * @return pointer to interior ring. May be NULL.
268 : */
269 :
270 8 : OGRLinearRing *OGRPolygon::stealInteriorRing(int iRing)
271 : {
272 8 : if (iRing < 0 || iRing >= oCC.nCurveCount - 1)
273 0 : return nullptr;
274 8 : OGRLinearRing *poRet = oCC.papoCurves[iRing + 1]->toLinearRing();
275 8 : oCC.papoCurves[iRing + 1] = nullptr;
276 8 : return poRet;
277 : }
278 :
279 : /*! @cond Doxygen_Suppress */
280 :
281 : /************************************************************************/
282 : /* isRingCorrectType() */
283 : /************************************************************************/
284 201900 : bool OGRPolygon::isRingCorrectType(const OGRCurve *poRing) const
285 : {
286 201900 : return poRing != nullptr && EQUAL(poRing->getGeometryName(), "LINEARRING");
287 : }
288 :
289 : /************************************************************************/
290 : /* checkRing() */
291 : /************************************************************************/
292 :
293 201892 : bool OGRPolygon::checkRing(const OGRCurve *poNewRing) const
294 : {
295 201892 : if (!isRingCorrectType(poNewRing))
296 : {
297 3 : CPLError(CE_Failure, CPLE_AppDefined,
298 : "Wrong curve type. Expected LINEARRING.");
299 3 : return false;
300 : }
301 :
302 201888 : if (!poNewRing->IsEmpty() && !poNewRing->get_IsClosed())
303 : {
304 : // This configuration option name must be the same as in
305 : // OGRCurvePolygon::checkRing()
306 : const char *pszEnvVar =
307 97 : CPLGetConfigOption("OGR_GEOMETRY_ACCEPT_UNCLOSED_RING", nullptr);
308 97 : if (pszEnvVar != nullptr && !CPLTestBool(pszEnvVar))
309 : {
310 0 : CPLError(CE_Failure, CPLE_AppDefined, "Non closed ring detected.");
311 0 : return false;
312 : }
313 : else
314 : {
315 97 : CPLError(CE_Warning, CPLE_AppDefined, "Non closed ring detected.%s",
316 : pszEnvVar == nullptr
317 : ? " To avoid accepting it, set the "
318 : "OGR_GEOMETRY_ACCEPT_UNCLOSED_RING configuration "
319 : "option to NO"
320 : : "");
321 : }
322 : }
323 :
324 201889 : return true;
325 : }
326 :
327 : /*! @endcond */
328 :
329 : /************************************************************************/
330 : /* WkbSize() */
331 : /* */
332 : /* Return the size of this object in well known binary */
333 : /* representation including the byte order, and type information. */
334 : /************************************************************************/
335 :
336 956158 : size_t OGRPolygon::WkbSize() const
337 :
338 : {
339 956158 : size_t nSize = 9;
340 :
341 1915500 : for (auto &&poRing : *this)
342 : {
343 959338 : nSize += poRing->_WkbSize(flags);
344 : }
345 :
346 956147 : return nSize;
347 : }
348 :
349 : /************************************************************************/
350 : /* importFromWkb() */
351 : /* */
352 : /* Initialize from serialized stream in well known binary */
353 : /* format. */
354 : /************************************************************************/
355 :
356 41558 : OGRErr OGRPolygon::importFromWkb(const unsigned char *pabyData, size_t nSize,
357 : OGRwkbVariant eWkbVariant,
358 : size_t &nBytesConsumedOut)
359 :
360 : {
361 41558 : OGRwkbByteOrder eByteOrder = wkbNDR;
362 41558 : size_t nDataOffset = 0;
363 :
364 41558 : if (oCC.nCurveCount == 1 && flags == 0 && nSize >= 9 &&
365 16 : pabyData[0] == wkbNDR &&
366 16 : memcmp(pabyData + 1, "\x03\x00\x00\x00\x01\x00\x00\x00", 8) == 0)
367 : {
368 : // Optimization to import a Intel-ordered 1-ring polygon on
369 : // top of an existing 1-ring polygon, to save dynamic memory
370 : // allocations.
371 15 : size_t nBytesConsumedRing = 0;
372 15 : nDataOffset = 9;
373 : // cppcheck-suppress knownConditionTrueFalse
374 15 : if (nSize != static_cast<size_t>(-1))
375 13 : nSize -= nDataOffset;
376 : OGRErr eErr =
377 15 : cpl::down_cast<OGRLinearRing *>(oCC.papoCurves[0])
378 30 : ->_importFromWkb(eByteOrder, flags, pabyData + nDataOffset,
379 15 : nSize, nBytesConsumedRing);
380 15 : if (eErr == OGRERR_NONE)
381 : {
382 13 : nBytesConsumedOut = nDataOffset + nBytesConsumedRing;
383 : }
384 : else
385 : {
386 2 : empty();
387 : }
388 :
389 15 : return eErr;
390 : }
391 :
392 41543 : nBytesConsumedOut = 0;
393 :
394 : // coverity[tainted_data]
395 41543 : OGRErr eErr = oCC.importPreambleFromWkb(this, pabyData, nSize, nDataOffset,
396 : eByteOrder, 4, eWkbVariant);
397 41544 : if (eErr != OGRERR_NONE)
398 335 : return eErr;
399 :
400 : /* -------------------------------------------------------------------- */
401 : /* Get the rings. */
402 : /* -------------------------------------------------------------------- */
403 81652 : for (int iRing = 0; iRing < oCC.nCurveCount; iRing++)
404 : {
405 41470 : OGRLinearRing *poLR = new OGRLinearRing();
406 41469 : oCC.papoCurves[iRing] = poLR;
407 41469 : size_t nBytesConsumedRing = 0;
408 82938 : eErr = poLR->_importFromWkb(eByteOrder, flags, pabyData + nDataOffset,
409 41469 : nSize, nBytesConsumedRing);
410 41469 : if (eErr != OGRERR_NONE)
411 : {
412 1027 : delete oCC.papoCurves[iRing];
413 1027 : oCC.nCurveCount = iRing;
414 1027 : return eErr;
415 : }
416 :
417 40442 : CPLAssert(nBytesConsumedRing > 0);
418 40442 : if (nSize != static_cast<size_t>(-1))
419 : {
420 40430 : CPLAssert(nSize >= nBytesConsumedRing);
421 40431 : nSize -= nBytesConsumedRing;
422 : }
423 :
424 40443 : nDataOffset += nBytesConsumedRing;
425 : }
426 40182 : nBytesConsumedOut = nDataOffset;
427 :
428 40182 : return OGRERR_NONE;
429 : }
430 :
431 : /************************************************************************/
432 : /* exportToWkb() */
433 : /* */
434 : /* Build a well known binary representation of this object. */
435 : /************************************************************************/
436 :
437 256836 : OGRErr OGRPolygon::exportToWkb(unsigned char *pabyData,
438 : const OGRwkbExportOptions *psOptions) const
439 :
440 : {
441 256836 : if (psOptions == nullptr)
442 : {
443 : static const OGRwkbExportOptions defaultOptions;
444 0 : psOptions = &defaultOptions;
445 : }
446 :
447 : /* -------------------------------------------------------------------- */
448 : /* Set the byte order. */
449 : /* -------------------------------------------------------------------- */
450 256836 : pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER(
451 : static_cast<unsigned char>(psOptions->eByteOrder));
452 :
453 : /* -------------------------------------------------------------------- */
454 : /* Set the geometry feature type. */
455 : /* -------------------------------------------------------------------- */
456 256836 : GUInt32 nGType = getGeometryType();
457 :
458 256832 : if (psOptions->eWkbVariant == wkbVariantPostGIS1)
459 : {
460 307 : nGType = wkbFlatten(nGType);
461 307 : if (Is3D())
462 : // Explicitly set wkb25DBit.
463 294 : nGType =
464 294 : static_cast<OGRwkbGeometryType>(nGType | wkb25DBitInternalUse);
465 307 : if (IsMeasured())
466 0 : nGType = static_cast<OGRwkbGeometryType>(nGType | 0x40000000);
467 : }
468 256525 : else if (psOptions->eWkbVariant == wkbVariantIso)
469 124880 : nGType = getIsoGeometryType();
470 :
471 256832 : if (OGR_SWAP(psOptions->eByteOrder))
472 : {
473 20 : nGType = CPL_SWAP32(nGType);
474 : }
475 :
476 256832 : memcpy(pabyData + 1, &nGType, 4);
477 :
478 : /* -------------------------------------------------------------------- */
479 : /* Copy in the raw data. */
480 : /* -------------------------------------------------------------------- */
481 256832 : if (OGR_SWAP(psOptions->eByteOrder))
482 : {
483 20 : const int nCount = CPL_SWAP32(oCC.nCurveCount);
484 20 : memcpy(pabyData + 5, &nCount, 4);
485 : }
486 : else
487 : {
488 256812 : memcpy(pabyData + 5, &oCC.nCurveCount, 4);
489 : }
490 :
491 : /* ==================================================================== */
492 : /* Serialize each of the rings. */
493 : /* ==================================================================== */
494 256832 : size_t nOffset = 9;
495 :
496 513883 : for (auto &&poRing : *this)
497 : {
498 257052 : poRing->_exportToWkb(flags, pabyData + nOffset, psOptions);
499 :
500 257048 : nOffset += poRing->_WkbSize(flags);
501 : }
502 :
503 256827 : return OGRERR_NONE;
504 : }
505 :
506 : /************************************************************************/
507 : /* importFromWkt() */
508 : /* */
509 : /* Instantiate from well known text format. Currently this is */
510 : /* `POLYGON ((x y, x y, ...),(x y, ...),...)'. */
511 : /************************************************************************/
512 :
513 16168 : OGRErr OGRPolygon::importFromWkt(const char **ppszInput)
514 :
515 : {
516 16168 : int bHasZ = FALSE;
517 16168 : int bHasM = FALSE;
518 16168 : bool bIsEmpty = false;
519 16168 : OGRErr eErr = importPreambleFromWkt(ppszInput, &bHasZ, &bHasM, &bIsEmpty);
520 16168 : flags = 0;
521 16168 : if (eErr != OGRERR_NONE)
522 5 : return eErr;
523 16163 : if (bHasZ)
524 170 : flags |= OGR_G_3D;
525 16163 : if (bHasM)
526 78 : flags |= OGR_G_MEASURED;
527 16163 : if (bIsEmpty)
528 88 : return OGRERR_NONE;
529 :
530 16075 : OGRRawPoint *paoPoints = nullptr;
531 16075 : int nMaxPoints = 0;
532 16075 : double *padfZ = nullptr;
533 :
534 32150 : eErr = importFromWKTListOnly(ppszInput, bHasZ, bHasM, paoPoints, nMaxPoints,
535 16075 : padfZ);
536 :
537 16075 : CPLFree(paoPoints);
538 16075 : CPLFree(padfZ);
539 :
540 16075 : return eErr;
541 : }
542 :
543 : /*! @cond Doxygen_Suppress */
544 : /************************************************************************/
545 : /* importFromWKTListOnly() */
546 : /* */
547 : /* Instantiate from "((x y, x y, ...),(x y, ...),...)" */
548 : /************************************************************************/
549 :
550 17553 : OGRErr OGRPolygon::importFromWKTListOnly(const char **ppszInput, int bHasZ,
551 : int bHasM, OGRRawPoint *&paoPoints,
552 : int &nMaxPoints, double *&padfZ)
553 :
554 : {
555 17553 : char szToken[OGR_WKT_TOKEN_MAX] = {};
556 17553 : const char *pszInput = *ppszInput;
557 :
558 : // Skip first '('.
559 17553 : pszInput = OGRWktReadToken(pszInput, szToken);
560 17553 : if (EQUAL(szToken, "EMPTY"))
561 : {
562 0 : *ppszInput = pszInput;
563 0 : return OGRERR_NONE;
564 : }
565 17553 : if (!EQUAL(szToken, "("))
566 0 : return OGRERR_CORRUPT_DATA;
567 :
568 : /* ==================================================================== */
569 : /* Read each ring in turn. Note that we try to reuse the same */
570 : /* point list buffer from ring to ring to cut down on */
571 : /* allocate/deallocate overhead. */
572 : /* ==================================================================== */
573 17553 : int nMaxRings = 0;
574 17553 : double *padfM = nullptr;
575 :
576 388 : do
577 : {
578 17941 : const char *pszNext = OGRWktReadToken(pszInput, szToken);
579 17941 : if (EQUAL(szToken, "EMPTY"))
580 : {
581 : /* --------------------------------------------------------------------
582 : */
583 : /* Do we need to grow the ring array? */
584 : /* --------------------------------------------------------------------
585 : */
586 26 : if (oCC.nCurveCount == nMaxRings)
587 : {
588 23 : nMaxRings = nMaxRings * 2 + 1;
589 23 : oCC.papoCurves = static_cast<OGRCurve **>(CPLRealloc(
590 23 : oCC.papoCurves, nMaxRings * sizeof(OGRLinearRing *)));
591 : }
592 26 : oCC.papoCurves[oCC.nCurveCount] = new OGRLinearRing();
593 26 : oCC.nCurveCount++;
594 :
595 26 : pszInput = OGRWktReadToken(pszNext, szToken);
596 26 : if (!EQUAL(szToken, ","))
597 13 : break;
598 :
599 13 : continue;
600 : }
601 :
602 : /* --------------------------------------------------------------------
603 : */
604 : /* Read points for one ring from input. */
605 : /* --------------------------------------------------------------------
606 : */
607 17915 : int nPoints = 0;
608 17915 : int flagsFromInput = flags;
609 17915 : if (flagsFromInput == 0)
610 : {
611 : // Flags was not set, this is not called by us.
612 17652 : if (bHasM)
613 141 : flagsFromInput |= OGR_G_MEASURED;
614 17652 : if (bHasZ)
615 362 : flagsFromInput |= OGR_G_3D;
616 : }
617 :
618 17915 : pszInput = OGRWktReadPointsM(pszInput, &paoPoints, &padfZ, &padfM,
619 : &flagsFromInput, &nMaxPoints, &nPoints);
620 17915 : if (pszInput == nullptr || nPoints == 0)
621 : {
622 33 : CPLFree(padfM);
623 33 : return OGRERR_CORRUPT_DATA;
624 : }
625 17882 : if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
626 : {
627 754 : flags |= OGR_G_3D;
628 754 : bHasZ = TRUE;
629 : }
630 17882 : if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
631 : {
632 141 : flags |= OGR_G_MEASURED;
633 141 : bHasM = TRUE;
634 : }
635 :
636 : /* --------------------------------------------------------------------
637 : */
638 : /* Do we need to grow the ring array? */
639 : /* --------------------------------------------------------------------
640 : */
641 17882 : if (oCC.nCurveCount == nMaxRings)
642 : {
643 17862 : nMaxRings = nMaxRings * 2 + 1;
644 17862 : oCC.papoCurves = static_cast<OGRCurve **>(CPLRealloc(
645 17862 : oCC.papoCurves, nMaxRings * sizeof(OGRLinearRing *)));
646 : }
647 :
648 : /* --------------------------------------------------------------------
649 : */
650 : /* Create the new ring, and assign to ring list. */
651 : /* --------------------------------------------------------------------
652 : */
653 17882 : OGRLinearRing *poLR = new OGRLinearRing();
654 17882 : oCC.papoCurves[oCC.nCurveCount] = poLR;
655 :
656 17882 : if (bHasM && bHasZ)
657 121 : poLR->setPoints(nPoints, paoPoints, padfZ, padfM);
658 17761 : else if (bHasM)
659 109 : poLR->setPointsM(nPoints, paoPoints, padfM);
660 17652 : else if (bHasZ)
661 846 : poLR->setPoints(nPoints, paoPoints, padfZ);
662 : else
663 16806 : poLR->setPoints(nPoints, paoPoints);
664 :
665 17882 : oCC.nCurveCount++;
666 :
667 : /* --------------------------------------------------------------------
668 : */
669 : /* Read the delimiter following the ring. */
670 : /* --------------------------------------------------------------------
671 : */
672 :
673 17882 : pszInput = OGRWktReadToken(pszInput, szToken);
674 17895 : } while (szToken[0] == ',');
675 :
676 17520 : CPLFree(padfM);
677 :
678 : /* -------------------------------------------------------------------- */
679 : /* freak if we don't get a closing bracket. */
680 : /* -------------------------------------------------------------------- */
681 :
682 17520 : if (szToken[0] != ')')
683 5 : return OGRERR_CORRUPT_DATA;
684 :
685 17515 : *ppszInput = pszInput;
686 17515 : return OGRERR_NONE;
687 : }
688 :
689 : /*! @endcond */
690 :
691 : /************************************************************************/
692 : /* exportToWkt() */
693 : /* */
694 : /* Translate this structure into its well known text format */
695 : /* equivalent. This could be made a lot more CPU efficient. */
696 : /************************************************************************/
697 :
698 2273 : std::string OGRPolygon::exportToWkt(const OGRWktOptions &opts,
699 : OGRErr *err) const
700 : {
701 4546 : std::string wkt;
702 : /* -------------------------------------------------------------------- */
703 : /* If we have no valid exterior ring, return POLYGON EMPTY. */
704 : /* -------------------------------------------------------------------- */
705 2273 : wkt = getGeometryName();
706 2273 : wkt += wktTypeString(opts.variant);
707 2273 : if (getExteriorRing() == nullptr || getExteriorRing()->IsEmpty())
708 93 : wkt += "EMPTY";
709 :
710 : /* -------------------------------------------------------------------- */
711 : /* Build a list of strings containing the stuff for each ring. */
712 : /* -------------------------------------------------------------------- */
713 :
714 : else
715 : {
716 : try
717 : {
718 2180 : bool first(true);
719 2180 : wkt += '(';
720 4591 : for (int iRing = 0; iRing < oCC.nCurveCount; iRing++)
721 : {
722 2411 : OGRLinearRing *poLR = oCC.papoCurves[iRing]->toLinearRing();
723 2411 : if (poLR->getNumPoints())
724 : {
725 2399 : if (!first)
726 219 : wkt += ',';
727 2399 : first = false;
728 2399 : OGRErr subgeomErr = OGRERR_NONE;
729 2399 : std::string tempWkt = poLR->exportToWkt(opts, &subgeomErr);
730 2399 : if (subgeomErr != OGRERR_NONE)
731 : {
732 0 : if (err)
733 0 : *err = subgeomErr;
734 0 : return std::string();
735 : }
736 :
737 : // Remove leading "LINEARRING..."
738 2399 : wkt += tempWkt.substr(tempWkt.find_first_of('('));
739 : }
740 : }
741 2180 : wkt += ')';
742 : }
743 0 : catch (const std::bad_alloc &e)
744 : {
745 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
746 0 : if (err)
747 0 : *err = OGRERR_FAILURE;
748 0 : return std::string();
749 : }
750 : }
751 :
752 2273 : if (err)
753 2250 : *err = OGRERR_NONE;
754 2273 : return wkt;
755 : }
756 :
757 : /************************************************************************/
758 : /* IsPointOnSurface() */
759 : /************************************************************************/
760 :
761 : /** Return whether the point is on the surface.
762 : * @return TRUE or FALSE
763 : */
764 5 : OGRBoolean OGRPolygon::IsPointOnSurface(const OGRPoint *pt) const
765 : {
766 5 : if (nullptr == pt)
767 0 : return FALSE;
768 :
769 5 : bool bOnSurface = false;
770 : // The point must be in the outer ring, but not in the inner rings
771 5 : int iRing = 0;
772 8 : for (auto &&poRing : *this)
773 : {
774 5 : if (poRing->isPointInRing(pt))
775 : {
776 3 : if (iRing == 0)
777 : {
778 2 : bOnSurface = true;
779 : }
780 : else
781 : {
782 1 : return false;
783 : }
784 : }
785 : else
786 : {
787 2 : if (iRing == 0)
788 : {
789 1 : return false;
790 : }
791 : }
792 3 : iRing++;
793 : }
794 :
795 3 : return bOnSurface;
796 : }
797 :
798 : /************************************************************************/
799 : /* closeRings() */
800 : /************************************************************************/
801 :
802 1157 : void OGRPolygon::closeRings()
803 :
804 : {
805 2347 : for (auto &&poRing : *this)
806 1190 : poRing->closeRings();
807 1157 : }
808 :
809 : /************************************************************************/
810 : /* CurvePolyToPoly() */
811 : /************************************************************************/
812 :
813 : OGRPolygon *
814 0 : OGRPolygon::CurvePolyToPoly(CPL_UNUSED double dfMaxAngleStepSizeDegrees,
815 : CPL_UNUSED const char *const *papszOptions) const
816 : {
817 0 : return clone();
818 : }
819 :
820 : /************************************************************************/
821 : /* hasCurveGeometry() */
822 : /************************************************************************/
823 :
824 130989 : OGRBoolean OGRPolygon::hasCurveGeometry(CPL_UNUSED int bLookForNonLinear) const
825 : {
826 130989 : return FALSE;
827 : }
828 :
829 : /************************************************************************/
830 : /* getLinearGeometry() */
831 : /************************************************************************/
832 :
833 : OGRGeometry *
834 34 : OGRPolygon::getLinearGeometry(double dfMaxAngleStepSizeDegrees,
835 : const char *const *papszOptions) const
836 : {
837 34 : return OGRGeometry::getLinearGeometry(dfMaxAngleStepSizeDegrees,
838 34 : papszOptions);
839 : }
840 :
841 : /************************************************************************/
842 : /* getCurveGeometry() */
843 : /************************************************************************/
844 :
845 18 : OGRGeometry *OGRPolygon::getCurveGeometry(const char *const *papszOptions) const
846 : {
847 18 : OGRCurvePolygon *poCC = new OGRCurvePolygon();
848 18 : poCC->assignSpatialReference(getSpatialReference());
849 18 : bool bHasCurveGeometry = false;
850 35 : for (auto &&poRing : *this)
851 : {
852 17 : auto poSubGeom = poRing->getCurveGeometry(papszOptions);
853 17 : if (wkbFlatten(poSubGeom->getGeometryType()) != wkbLineString)
854 15 : bHasCurveGeometry = true;
855 17 : poCC->addRingDirectly(poSubGeom->toCurve());
856 : }
857 18 : if (!bHasCurveGeometry)
858 : {
859 3 : delete poCC;
860 3 : return clone();
861 : }
862 15 : return poCC;
863 : }
864 :
865 : /*! @cond Doxygen_Suppress */
866 : /************************************************************************/
867 : /* CastToCurvePolygon() */
868 : /************************************************************************/
869 :
870 : /**
871 : * \brief Cast to curve polygon.
872 : *
873 : * The passed in geometry is consumed and a new one returned .
874 : *
875 : * @param poPoly the input geometry - ownership is passed to the method.
876 : * @return new geometry.
877 : */
878 :
879 20 : OGRCurvePolygon *OGRPolygon::CastToCurvePolygon(OGRPolygon *poPoly)
880 : {
881 20 : OGRCurvePolygon *poCP = new OGRCurvePolygon();
882 20 : poCP->set3D(poPoly->Is3D());
883 20 : poCP->setMeasured(poPoly->IsMeasured());
884 20 : poCP->assignSpatialReference(poPoly->getSpatialReference());
885 20 : poCP->oCC.nCurveCount = poPoly->oCC.nCurveCount;
886 20 : poCP->oCC.papoCurves = poPoly->oCC.papoCurves;
887 20 : poPoly->oCC.nCurveCount = 0;
888 20 : poPoly->oCC.papoCurves = nullptr;
889 :
890 46 : for (auto &&poRing : *poCP)
891 : {
892 26 : poRing = OGRLinearRing::CastToLineString(poRing->toLinearRing());
893 : }
894 :
895 20 : delete poPoly;
896 20 : return poCP;
897 : }
898 :
899 : /************************************************************************/
900 : /* GetCasterToPolygon() */
901 : /************************************************************************/
902 :
903 71 : static OGRPolygon *CasterToPolygon(OGRSurface *poSurface)
904 : {
905 71 : return poSurface->toPolygon();
906 : }
907 :
908 71 : OGRSurfaceCasterToPolygon OGRPolygon::GetCasterToPolygon() const
909 : {
910 71 : return ::CasterToPolygon;
911 : }
912 :
913 : /************************************************************************/
914 : /* OGRSurfaceCasterToCurvePolygon() */
915 : /************************************************************************/
916 :
917 20 : OGRCurvePolygon *OGRPolygon::CasterToCurvePolygon(OGRSurface *poSurface)
918 : {
919 20 : return OGRPolygon::CastToCurvePolygon(poSurface->toPolygon());
920 : }
921 :
922 20 : OGRSurfaceCasterToCurvePolygon OGRPolygon::GetCasterToCurvePolygon() const
923 : {
924 20 : return OGRPolygon::CasterToCurvePolygon;
925 : }
926 :
927 : /*! @endcond */
|