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