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