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