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