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