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