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