1 /******************************************************************************
2  *
3  * Project:  OpenGIS Simple Features Reference Implementation
4  * Purpose:  The OGRCompoundCurve geometry class.
5  * Author:   Even Rouault, even dot rouault at spatialys dot com
6  *
7  ******************************************************************************
8  * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  ****************************************************************************/
28 
29 #include "cpl_port.h"
30 #include "ogr_geometry.h"
31 
32 #include <cmath>
33 #include <cstddef>
34 
35 #include "cpl_error.h"
36 #include "ogr_core.h"
37 #include "ogr_geometry.h"
38 #include "ogr_p.h"
39 #include "ogr_spatialref.h"
40 
41 CPL_CVSID("$Id: ogrcompoundcurve.cpp 172dc4ec9270e5e2e951f843b65d466b085d5693 2021-08-06 11:18:12 +0200 Even Rouault $")
42 
43 /************************************************************************/
44 /*                         OGRCompoundCurve()                           */
45 /************************************************************************/
46 
47 /**
48  * \brief Create an empty compound curve.
49  */
50 
51 OGRCompoundCurve::OGRCompoundCurve() = default;
52 
53 /************************************************************************/
54 /*             OGRCompoundCurve( const OGRCompoundCurve& )              */
55 /************************************************************************/
56 
57 /**
58  * \brief Copy constructor.
59  *
60  * Note: before GDAL 2.1, only the default implementation of the constructor
61  * existed, which could be unsafe to use.
62  *
63  * @since GDAL 2.1
64  */
65 
66 OGRCompoundCurve::OGRCompoundCurve( const OGRCompoundCurve& ) = default;
67 
68 /************************************************************************/
69 /*                         ~OGRCompoundCurve()                          */
70 /************************************************************************/
71 
72 OGRCompoundCurve::~OGRCompoundCurve() = default;
73 
74 /************************************************************************/
75 /*                 operator=( const OGRCompoundCurve&)                  */
76 /************************************************************************/
77 
78 /**
79  * \brief Assignment operator.
80  *
81  * Note: before GDAL 2.1, only the default implementation of the operator
82  * existed, which could be unsafe to use.
83  *
84  * @since GDAL 2.1
85  */
86 
operator =(const OGRCompoundCurve & other)87 OGRCompoundCurve& OGRCompoundCurve::operator=( const OGRCompoundCurve& other )
88 {
89     if( this != &other)
90     {
91         OGRCurve::operator=( other );
92 
93         oCC = other.oCC;
94     }
95     return *this;
96 }
97 
98 /************************************************************************/
99 /*                               clone()                                */
100 /************************************************************************/
101 
clone() const102 OGRCompoundCurve *OGRCompoundCurve::clone() const
103 
104 {
105     return new (std::nothrow) OGRCompoundCurve(*this);
106 }
107 
108 /************************************************************************/
109 /*                          getGeometryType()                           */
110 /************************************************************************/
111 
getGeometryType() const112 OGRwkbGeometryType OGRCompoundCurve::getGeometryType() const
113 
114 {
115     if( (flags & OGR_G_3D) && (flags & OGR_G_MEASURED) )
116         return wkbCompoundCurveZM;
117     else if( flags & OGR_G_MEASURED )
118         return wkbCompoundCurveM;
119     else if( flags & OGR_G_3D )
120         return wkbCompoundCurveZ;
121     else
122         return wkbCompoundCurve;
123 }
124 
125 /************************************************************************/
126 /*                          getGeometryName()                           */
127 /************************************************************************/
128 
getGeometryName() const129 const char * OGRCompoundCurve::getGeometryName() const
130 
131 {
132     return "COMPOUNDCURVE";
133 }
134 
135 /************************************************************************/
136 /*                              WkbSize()                               */
137 /************************************************************************/
WkbSize() const138 size_t OGRCompoundCurve::WkbSize() const
139 {
140     return oCC.WkbSize();
141 }
142 
143 /************************************************************************/
144 /*                       addCurveDirectlyFromWkt()                      */
145 /************************************************************************/
146 
addCurveDirectlyFromWkb(OGRGeometry * poSelf,OGRCurve * poCurve)147 OGRErr OGRCompoundCurve::addCurveDirectlyFromWkb( OGRGeometry* poSelf,
148                                                   OGRCurve* poCurve )
149 {
150     OGRCompoundCurve* poCC = poSelf->toCompoundCurve();
151     return poCC->addCurveDirectlyInternal( poCurve, 1e-14, FALSE );
152 }
153 
154 /************************************************************************/
155 /*                           importFromWkb()                            */
156 /************************************************************************/
157 
importFromWkb(const unsigned char * pabyData,size_t nSize,OGRwkbVariant eWkbVariant,size_t & nBytesConsumedOut)158 OGRErr OGRCompoundCurve::importFromWkb( const unsigned char * pabyData,
159                                         size_t nSize,
160                                         OGRwkbVariant eWkbVariant,
161                                         size_t& nBytesConsumedOut )
162 {
163     OGRwkbByteOrder eByteOrder = wkbNDR;
164     size_t nDataOffset = 0;
165     // coverity[tainted_data]
166     OGRErr eErr = oCC.importPreambleFromWkb(this, pabyData, nSize, nDataOffset,
167                                              eByteOrder, 9, eWkbVariant);
168     if( eErr != OGRERR_NONE )
169         return eErr;
170 
171     eErr =  oCC.importBodyFromWkb(this, pabyData + nDataOffset, nSize,
172                                  false,  // bAcceptCompoundCurve
173                                  addCurveDirectlyFromWkb,
174                                  eWkbVariant,
175                                  nBytesConsumedOut);
176     if( eErr == OGRERR_NONE )
177         nBytesConsumedOut += nDataOffset;
178     return eErr;
179 }
180 
181 /************************************************************************/
182 /*                            exportToWkb()                             */
183 /************************************************************************/
exportToWkb(OGRwkbByteOrder eByteOrder,unsigned char * pabyData,OGRwkbVariant eWkbVariant) const184 OGRErr OGRCompoundCurve::exportToWkb( OGRwkbByteOrder eByteOrder,
185                                       unsigned char * pabyData,
186                                       OGRwkbVariant eWkbVariant ) const
187 {
188     // Does not make sense for new geometries, so patch it.
189     if( eWkbVariant == wkbVariantOldOgc )
190         eWkbVariant = wkbVariantIso;
191     return oCC.exportToWkb(this, eByteOrder, pabyData, eWkbVariant);
192 }
193 
194 /************************************************************************/
195 /*                       addCurveDirectlyFromWkt()                      */
196 /************************************************************************/
197 
addCurveDirectlyFromWkt(OGRGeometry * poSelf,OGRCurve * poCurve)198 OGRErr OGRCompoundCurve::addCurveDirectlyFromWkt( OGRGeometry* poSelf,
199                                                   OGRCurve* poCurve )
200 {
201     return poSelf->toCompoundCurve()->addCurveDirectly(poCurve);
202 }
203 
204 /************************************************************************/
205 /*                           importFromWkt()                            */
206 /************************************************************************/
207 
importFromWkt(const char ** ppszInput)208 OGRErr OGRCompoundCurve::importFromWkt( const char ** ppszInput )
209 {
210     return importCurveCollectionFromWkt( ppszInput,
211                                          FALSE, // bAllowEmptyComponent
212                                          TRUE, // bAllowLineString
213                                          TRUE, // bAllowCurve
214                                          FALSE, // bAllowCompoundCurve
215                                          addCurveDirectlyFromWkt );
216 }
217 
218 /************************************************************************/
219 /*                            exportToWkt()                             */
220 /************************************************************************/
exportToWkt(const OGRWktOptions & opts,OGRErr * err) const221 std::string OGRCompoundCurve::exportToWkt(const OGRWktOptions& opts,
222                                           OGRErr *err) const
223 {
224     return oCC.exportToWkt(this, opts, err);
225 }
226 
227 /************************************************************************/
228 /*                               empty()                                */
229 /************************************************************************/
230 
empty()231 void OGRCompoundCurve::empty()
232 {
233     oCC.empty(this);
234 }
235 
236 /************************************************************************/
237 /*                            getEnvelope()                             */
238 /************************************************************************/
239 
getEnvelope(OGREnvelope * psEnvelope) const240 void OGRCompoundCurve::getEnvelope( OGREnvelope * psEnvelope ) const
241 {
242     oCC.getEnvelope(psEnvelope);
243 }
244 
245 /************************************************************************/
246 /*                            getEnvelope()                             */
247 /************************************************************************/
248 
getEnvelope(OGREnvelope3D * psEnvelope) const249 void OGRCompoundCurve::getEnvelope( OGREnvelope3D * psEnvelope ) const
250 {
251     oCC.getEnvelope(psEnvelope);
252 }
253 
254 /************************************************************************/
255 /*                               IsEmpty()                              */
256 /************************************************************************/
257 
IsEmpty() const258 OGRBoolean OGRCompoundCurve::IsEmpty() const
259 {
260     return oCC.IsEmpty();
261 }
262 
263 /************************************************************************/
264 /*                             get_Length()                             */
265 /*                                                                      */
266 /*      For now we return a simple euclidean 2D distance.               */
267 /************************************************************************/
268 
get_Length() const269 double OGRCompoundCurve::get_Length() const
270 {
271     double dfLength = 0.0;
272     for( int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++ )
273         dfLength += oCC.papoCurves[iGeom]->get_Length();
274     return dfLength;
275 }
276 
277 /************************************************************************/
278 /*                             StartPoint()                             */
279 /************************************************************************/
280 
StartPoint(OGRPoint * p) const281 void OGRCompoundCurve::StartPoint(OGRPoint *p) const
282 {
283     CPLAssert(oCC.nCurveCount > 0);
284     oCC.papoCurves[0]->StartPoint(p);
285 }
286 
287 /************************************************************************/
288 /*                              EndPoint()                              */
289 /************************************************************************/
290 
EndPoint(OGRPoint * p) const291 void OGRCompoundCurve::EndPoint(OGRPoint *p) const
292 {
293     CPLAssert(oCC.nCurveCount > 0);
294     oCC.papoCurves[oCC.nCurveCount-1]->EndPoint(p);
295 }
296 
297 /************************************************************************/
298 /*                               Value()                                */
299 /************************************************************************/
300 
Value(double dfDistance,OGRPoint * poPoint) const301 void OGRCompoundCurve::Value( double dfDistance, OGRPoint *poPoint ) const
302 {
303 
304     if( dfDistance < 0 )
305     {
306         StartPoint( poPoint );
307         return;
308     }
309 
310     double dfLength = 0.0;
311     for( int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++ )
312     {
313         const double dfSegLength = oCC.papoCurves[iGeom]->get_Length();
314         if( dfSegLength > 0 )
315         {
316             if( (dfLength <= dfDistance) && ((dfLength + dfSegLength) >=
317                                              dfDistance) )
318             {
319                 oCC.papoCurves[iGeom]->Value(dfDistance - dfLength, poPoint);
320 
321                 return;
322             }
323 
324             dfLength += dfSegLength;
325         }
326     }
327 
328     EndPoint( poPoint );
329 }
330 
331 /************************************************************************/
332 /*                         CurveToLineInternal()                        */
333 /************************************************************************/
334 
335 OGRLineString *
CurveToLineInternal(double dfMaxAngleStepSizeDegrees,const char * const * papszOptions,int bIsLinearRing) const336 OGRCompoundCurve::CurveToLineInternal( double dfMaxAngleStepSizeDegrees,
337                                        const char* const* papszOptions,
338                                        int bIsLinearRing ) const
339 {
340     OGRLineString* const poLine = bIsLinearRing
341         ? new OGRLinearRing()
342         : new OGRLineString();
343     poLine->assignSpatialReference(getSpatialReference());
344     for( int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++ )
345     {
346         OGRLineString* poSubLS =
347             oCC.papoCurves[iGeom]->CurveToLine(dfMaxAngleStepSizeDegrees,
348                                                papszOptions);
349         poLine->addSubLineString(poSubLS, (iGeom == 0) ? 0 : 1);
350         delete poSubLS;
351     }
352     return poLine;
353 }
354 
355 /************************************************************************/
356 /*                          CurveToLine()                               */
357 /************************************************************************/
358 
359 OGRLineString *
CurveToLine(double dfMaxAngleStepSizeDegrees,const char * const * papszOptions) const360 OGRCompoundCurve::CurveToLine( double dfMaxAngleStepSizeDegrees,
361                                const char* const* papszOptions ) const
362 {
363     return CurveToLineInternal(dfMaxAngleStepSizeDegrees, papszOptions, FALSE);
364 }
365 
366 /************************************************************************/
367 /*                               Equals()                                */
368 /************************************************************************/
369 
Equals(const OGRGeometry * poOther) const370 OGRBoolean OGRCompoundCurve::Equals( const OGRGeometry *poOther ) const
371 {
372     if( poOther == this )
373         return TRUE;
374 
375     if( poOther->getGeometryType() != getGeometryType() )
376         return FALSE;
377 
378     return oCC.Equals(&(poOther->toCompoundCurve()->oCC));
379 }
380 
381 /************************************************************************/
382 /*                       setCoordinateDimension()                       */
383 /************************************************************************/
384 
setCoordinateDimension(int nNewDimension)385 void OGRCompoundCurve::setCoordinateDimension( int nNewDimension )
386 {
387     oCC.setCoordinateDimension( this, nNewDimension );
388 }
389 
set3D(OGRBoolean bIs3D)390 void OGRCompoundCurve::set3D( OGRBoolean bIs3D )
391 {
392     oCC.set3D(this, bIs3D);
393 }
394 
setMeasured(OGRBoolean bIsMeasured)395 void OGRCompoundCurve::setMeasured( OGRBoolean bIsMeasured )
396 {
397     oCC.setMeasured(this, bIsMeasured);
398 }
399 
400 /************************************************************************/
401 /*                       assignSpatialReference()                       */
402 /************************************************************************/
403 
assignSpatialReference(OGRSpatialReference * poSR)404 void OGRCompoundCurve::assignSpatialReference( OGRSpatialReference * poSR )
405 {
406     oCC.assignSpatialReference(this, poSR);
407 }
408 
409 /************************************************************************/
410 /*                          getNumCurves()                              */
411 /************************************************************************/
412 
413 /**
414  * \brief Return the number of curves.
415  *
416  * Note that the number of curves making this compound curve.
417  *
418  * Relates to the ISO SQL/MM ST_NumCurves() function.
419  *
420  * @return number of curves.
421  */
422 
getNumCurves() const423 int OGRCompoundCurve::getNumCurves() const
424 {
425     return oCC.nCurveCount;
426 }
427 
428 /************************************************************************/
429 /*                           getCurve()                                 */
430 /************************************************************************/
431 
432 /**
433  * \brief Fetch reference to indicated internal ring.
434  *
435  * Note that the returned curve pointer is to an internal data object of the
436  * OGRCompoundCurve.  It should not be modified or deleted by the application,
437  * and the pointer is only valid till the polygon is next modified.  Use the
438  * OGRGeometry::clone() method to make a separate copy within the application.
439  *
440  * Relates to the ISO SQL/MM ST_CurveN() function.
441  *
442  * @param iRing curve index from 0 to getNumCurves() - 1.
443  *
444  * @return pointer to curve.  May be NULL.
445  */
446 
getCurve(int iRing)447 OGRCurve *OGRCompoundCurve::getCurve( int iRing )
448 {
449     return oCC.getCurve(iRing);
450 }
451 
452 /************************************************************************/
453 /*                           getCurve()                                 */
454 /************************************************************************/
455 
456 /**
457  * \brief Fetch reference to indicated internal ring.
458  *
459  * Note that the returned curve pointer is to an internal data object of the
460  * OGRCompoundCurve.  It should not be modified or deleted by the application,
461  * and the pointer is only valid till the polygon is next modified.  Use the
462  * OGRGeometry::clone() method to make a separate copy within the application.
463  *
464  * Relates to the ISO SQL/MM ST_CurveN() function.
465  *
466  * @param iCurve curve index from 0 to getNumCurves() - 1.
467  *
468  * @return pointer to curve.  May be NULL.
469  */
470 
getCurve(int iCurve) const471 const OGRCurve *OGRCompoundCurve::getCurve( int iCurve ) const
472 {
473     return oCC.getCurve(iCurve);
474 }
475 
476 /************************************************************************/
477 /*                           stealCurve()                               */
478 /************************************************************************/
479 
480 /**
481  * \brief "Steal" reference to curve.
482  *
483  * @param iCurve curve index from 0 to getNumCurves() - 1.
484  *
485  * @return pointer to curve.  May be NULL.
486  */
487 
stealCurve(int iCurve)488 OGRCurve* OGRCompoundCurve::stealCurve( int iCurve )
489 {
490     return oCC.stealCurve(iCurve);
491 }
492 
493 /************************************************************************/
494 /*                            addCurve()                                */
495 /************************************************************************/
496 
497 /**
498  * \brief Add a curve to the container.
499  *
500  * The passed geometry is cloned to make an internal copy.
501  *
502  * There is no ISO SQL/MM analog to this method.
503  *
504  * This method is the same as the C function OGR_G_AddGeometry().
505  *
506  * @param poCurve geometry to add to the container.
507  * @param dfToleranceEps relative tolerance when checking that the first point of a
508  *                       segment matches then end point of the previous one.
509  *                       Default value: 1e-14.
510  *
511  * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
512  * (for example if curves are not contiguous)
513  */
514 
addCurve(OGRCurve * poCurve,double dfToleranceEps)515 OGRErr OGRCompoundCurve::addCurve( OGRCurve* poCurve, double dfToleranceEps )
516 {
517     OGRCurve* poClonedCurve = poCurve->clone();
518     const OGRErr eErr = addCurveDirectly( poClonedCurve, dfToleranceEps );
519     if( eErr != OGRERR_NONE )
520         delete poClonedCurve;
521     return eErr;
522 }
523 
524 /************************************************************************/
525 /*                          addCurveDirectly()                          */
526 /************************************************************************/
527 
528 /**
529  * \brief Add a curve directly to the container.
530  *
531  * Ownership of the passed geometry is taken by the container rather than
532  * cloning as addCurve() does.
533  *
534  * There is no ISO SQL/MM analog to this method.
535  *
536  * This method is the same as the C function OGR_G_AddGeometryDirectly().
537  *
538  * @param poCurve geometry to add to the container.
539  * @param dfToleranceEps relative tolerance when checking that the first point of a
540  *                       segment matches then end point of the previous one.
541  *                       Default value: 1e-14.
542  *
543  * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
544  * (for example if curves are not contiguous)
545  */
addCurveDirectly(OGRCurve * poCurve,double dfToleranceEps)546 OGRErr OGRCompoundCurve::addCurveDirectly( OGRCurve* poCurve,
547                                            double dfToleranceEps )
548 {
549     return addCurveDirectlyInternal(poCurve, dfToleranceEps, TRUE );
550 }
551 
addCurveDirectlyInternal(OGRCurve * poCurve,double dfToleranceEps,int bNeedRealloc)552 OGRErr OGRCompoundCurve::addCurveDirectlyInternal( OGRCurve* poCurve,
553                                                    double dfToleranceEps,
554                                                    int bNeedRealloc )
555 {
556     if( poCurve->getNumPoints() == 1 )
557     {
558         CPLError(CE_Failure, CPLE_AppDefined,
559                  "Invalid curve: not enough points");
560         return OGRERR_FAILURE;
561     }
562 
563     const OGRwkbGeometryType eCurveType =
564         wkbFlatten(poCurve->getGeometryType());
565     if( EQUAL(poCurve->getGeometryName(), "LINEARRING") )
566     {
567         CPLError(CE_Failure, CPLE_AppDefined, "Linearring not allowed.");
568         return OGRERR_FAILURE;
569     }
570     else if( eCurveType == wkbCompoundCurve )
571     {
572         CPLError(CE_Failure, CPLE_AppDefined,
573                  "Cannot add a compound curve inside a compound curve");
574         return OGRERR_FAILURE;
575     }
576 
577     if( oCC.nCurveCount > 0 )
578     {
579         if( oCC.papoCurves[oCC.nCurveCount-1]->IsEmpty() ||
580             poCurve->IsEmpty() )
581         {
582             CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves");
583             return OGRERR_FAILURE;
584         }
585 
586         OGRPoint oEnd;
587         OGRPoint start;
588         oCC.papoCurves[oCC.nCurveCount-1]->EndPoint(&oEnd);
589         poCurve->StartPoint(&start);
590         if( fabs(oEnd.getX() - start.getX()) > dfToleranceEps * fabs(start.getX()) ||
591             fabs(oEnd.getY() - start.getY()) > dfToleranceEps * fabs(start.getY()) ||
592             fabs(oEnd.getZ() - start.getZ()) > dfToleranceEps * fabs(start.getZ()) )
593         {
594             poCurve->EndPoint(&start);
595             if( fabs(oEnd.getX() - start.getX()) > dfToleranceEps * fabs(start.getX()) ||
596                 fabs(oEnd.getY() - start.getY()) > dfToleranceEps * fabs(start.getY()) ||
597                 fabs(oEnd.getZ() - start.getZ()) > dfToleranceEps * fabs(start.getZ()) )
598             {
599                 CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves");
600                 return OGRERR_FAILURE;
601             }
602 
603             CPLDebug("GML", "reversing curve");
604             poCurve->toSimpleCurve()->reversePoints();
605         }
606         // Patch so that it matches exactly.
607         poCurve->toSimpleCurve()->setPoint(0, &oEnd);
608     }
609 
610     return oCC.addCurveDirectly(this, poCurve, bNeedRealloc);
611 }
612 
613 /************************************************************************/
614 /*                             transform()                              */
615 /************************************************************************/
616 
transform(OGRCoordinateTransformation * poCT)617 OGRErr OGRCompoundCurve::transform( OGRCoordinateTransformation *poCT )
618 {
619     return oCC.transform(this, poCT);
620 }
621 
622 /************************************************************************/
623 /*                            flattenTo2D()                             */
624 /************************************************************************/
625 
flattenTo2D()626 void OGRCompoundCurve::flattenTo2D()
627 {
628     oCC.flattenTo2D(this);
629 }
630 
631 /************************************************************************/
632 /*                              segmentize()                            */
633 /************************************************************************/
634 
segmentize(double dfMaxLength)635 void OGRCompoundCurve::segmentize( double dfMaxLength )
636 {
637     oCC.segmentize(dfMaxLength);
638 }
639 
640 /************************************************************************/
641 /*                               swapXY()                               */
642 /************************************************************************/
643 
swapXY()644 void OGRCompoundCurve::swapXY()
645 {
646     oCC.swapXY();
647 }
648 
649 /************************************************************************/
650 /*                         hasCurveGeometry()                           */
651 /************************************************************************/
652 
hasCurveGeometry(int bLookForNonLinear) const653 OGRBoolean OGRCompoundCurve::hasCurveGeometry( int bLookForNonLinear ) const
654 {
655     if( bLookForNonLinear )
656     {
657         return oCC.hasCurveGeometry(bLookForNonLinear);
658     }
659 
660     return TRUE;
661 }
662 
663 /************************************************************************/
664 /*                         getLinearGeometry()                        */
665 /************************************************************************/
666 
667 OGRGeometry *
getLinearGeometry(double dfMaxAngleStepSizeDegrees,const char * const * papszOptions) const668 OGRCompoundCurve::getLinearGeometry( double dfMaxAngleStepSizeDegrees,
669                                      const char* const* papszOptions ) const
670 {
671     return CurveToLine(dfMaxAngleStepSizeDegrees, papszOptions);
672 }
673 
674 /************************************************************************/
675 /*                           getNumPoints()                             */
676 /************************************************************************/
677 
getNumPoints() const678 int OGRCompoundCurve::getNumPoints() const
679 {
680     int nPoints = 0;
681     for( int i = 0; i < oCC.nCurveCount; i++ )
682     {
683         nPoints += oCC.papoCurves[i]->getNumPoints();
684         if( i != 0 )
685             nPoints--;
686     }
687     return nPoints;
688 }
689 
690 /************************************************************************/
691 /*                      OGRCompoundCurvePointIterator                   */
692 /************************************************************************/
693 
694 class OGRCompoundCurvePointIterator final: public OGRPointIterator
695 {
696         CPL_DISALLOW_COPY_ASSIGN(OGRCompoundCurvePointIterator)
697 
698         const OGRCompoundCurve *poCC = nullptr;
699         int                     iCurCurve = 0;
700         OGRPointIterator       *poCurveIter = nullptr;
701 
702     public:
OGRCompoundCurvePointIterator(const OGRCompoundCurve * poCCIn)703         explicit OGRCompoundCurvePointIterator( const OGRCompoundCurve* poCCIn ) :
704             poCC(poCCIn) {}
~OGRCompoundCurvePointIterator()705         ~OGRCompoundCurvePointIterator() override { delete poCurveIter; }
706 
707         OGRBoolean getNextPoint( OGRPoint* p ) override;
708 };
709 
710 /************************************************************************/
711 /*                            getNextPoint()                            */
712 /************************************************************************/
713 
getNextPoint(OGRPoint * p)714 OGRBoolean OGRCompoundCurvePointIterator::getNextPoint( OGRPoint* p )
715 {
716     if( iCurCurve == poCC->getNumCurves() )
717         return FALSE;
718     if( poCurveIter == nullptr )
719         poCurveIter = poCC->getCurve(0)->getPointIterator();
720     if( !poCurveIter->getNextPoint(p) )
721     {
722         iCurCurve++;
723         if( iCurCurve == poCC->getNumCurves() )
724             return FALSE;
725         delete poCurveIter;
726         poCurveIter = poCC->getCurve(iCurCurve)->getPointIterator();
727         // Skip first point.
728         return poCurveIter->getNextPoint(p) &&
729                poCurveIter->getNextPoint(p);
730     }
731     return TRUE;
732 }
733 
734 /************************************************************************/
735 /*                         getPointIterator()                           */
736 /************************************************************************/
737 
getPointIterator() const738 OGRPointIterator* OGRCompoundCurve::getPointIterator() const
739 {
740     return new OGRCompoundCurvePointIterator(this);
741 }
742 
743 /************************************************************************/
744 /*                         CastToLineString()                        */
745 /************************************************************************/
746 
747 //! @cond Doxygen_Suppress
CastToLineString(OGRCompoundCurve * poCC)748 OGRLineString* OGRCompoundCurve::CastToLineString( OGRCompoundCurve* poCC )
749 {
750     for( int i = 0; i < poCC->oCC.nCurveCount; i++ )
751     {
752         poCC->oCC.papoCurves[i] =
753             OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]);
754         if( poCC->oCC.papoCurves[i] == nullptr )
755         {
756             delete poCC;
757             return nullptr;
758         }
759     }
760 
761     if( poCC->oCC.nCurveCount == 1 )
762     {
763         OGRLineString* poLS = poCC->oCC.papoCurves[0]->toLineString();
764         poLS->assignSpatialReference(poCC->getSpatialReference());
765         poCC->oCC.papoCurves[0] = nullptr;
766         delete poCC;
767         return poLS;
768     }
769 
770     OGRLineString* poLS = poCC->CurveToLineInternal(0, nullptr, FALSE);
771     delete poCC;
772     return poLS;
773 }
774 
775 /************************************************************************/
776 /*                           CastToLinearRing()                         */
777 /************************************************************************/
778 
779 /**
780  * \brief Cast to linear ring.
781  *
782  * The passed in geometry is consumed and a new one returned (or NULL in case
783  * of failure)
784  *
785  * @param poCC the input geometry - ownership is passed to the method.
786  * @return new geometry.
787  */
788 
CastToLinearRing(OGRCompoundCurve * poCC)789 OGRLinearRing* OGRCompoundCurve::CastToLinearRing( OGRCompoundCurve* poCC )
790 {
791     for( int i = 0; i < poCC->oCC.nCurveCount; i++ )
792     {
793         poCC->oCC.papoCurves[i] =
794             OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]);
795         if( poCC->oCC.papoCurves[i] == nullptr )
796         {
797             delete poCC;
798             return nullptr;
799         }
800     }
801 
802     if( poCC->oCC.nCurveCount == 1 )
803     {
804         OGRLinearRing* poLR =
805             OGRCurve::CastToLinearRing( poCC->oCC.papoCurves[0] );
806         if( poLR != nullptr )
807         {
808             poLR->assignSpatialReference(poCC->getSpatialReference());
809         }
810         poCC->oCC.papoCurves[0] = nullptr;
811         delete poCC;
812         return poLR;
813     }
814 
815     OGRLinearRing* poLR =
816         poCC->CurveToLineInternal(0, nullptr, TRUE)->toLinearRing();
817     delete poCC;
818     return poLR;
819 }
820 
821 /************************************************************************/
822 /*                     GetCasterToLineString()                          */
823 /************************************************************************/
824 
CasterToLineString(OGRCurve * poCurve)825 OGRLineString* OGRCompoundCurve::CasterToLineString( OGRCurve* poCurve )
826 {
827     OGRCompoundCurve* poCC = poCurve->toCompoundCurve();
828     return OGRCompoundCurve::CastToLineString(poCC);
829 }
830 
GetCasterToLineString() const831 OGRCurveCasterToLineString OGRCompoundCurve::GetCasterToLineString() const {
832     return OGRCompoundCurve::CasterToLineString;
833 }
834 
835 /************************************************************************/
836 /*                        GetCasterToLinearRing()                       */
837 /************************************************************************/
838 
CasterToLinearRing(OGRCurve * poCurve)839 OGRLinearRing* OGRCompoundCurve::CasterToLinearRing( OGRCurve* poCurve )
840 {
841     OGRCompoundCurve* poCC = poCurve->toCompoundCurve();
842     return OGRCompoundCurve::CastToLinearRing(poCC);
843 }
844 
GetCasterToLinearRing() const845 OGRCurveCasterToLinearRing OGRCompoundCurve::GetCasterToLinearRing() const {
846     return OGRCompoundCurve::CasterToLinearRing;
847 }
848 //! @endcond
849 
850 /************************************************************************/
851 /*                           get_Area()                                 */
852 /************************************************************************/
853 
get_Area() const854 double OGRCompoundCurve::get_Area() const
855 {
856     if( IsEmpty() || !get_IsClosed() )
857         return 0;
858 
859     // Optimization for convex rings.
860     if( IsConvex() )
861     {
862         // Compute area of shape without the circular segments.
863         OGRPointIterator* poIter = getPointIterator();
864         OGRLineString oLS;
865         oLS.setNumPoints( getNumPoints() );
866         OGRPoint p;
867         for( int i = 0; poIter->getNextPoint(&p); i++ )
868         {
869             oLS.setPoint( i, p.getX(), p.getY() );
870         }
871         double dfArea = oLS.get_Area();
872         delete poIter;
873 
874         // Add the area of the spherical segments.
875         dfArea += get_AreaOfCurveSegments();
876 
877         return dfArea;
878     }
879 
880     OGRLineString* poLS = CurveToLine();
881     double dfArea = poLS->get_Area();
882     delete poLS;
883 
884     return dfArea;
885 }
886 
887 /************************************************************************/
888 /*                       get_AreaOfCurveSegments()                      */
889 /************************************************************************/
890 
891 /** Return area of curve segments
892  * @return area.
893  */
get_AreaOfCurveSegments() const894 double OGRCompoundCurve::get_AreaOfCurveSegments() const
895 {
896     double dfArea = 0;
897     for( int i = 0; i < getNumCurves(); i++ )
898     {
899         const OGRCurve* poPart = getCurve(i);
900         dfArea += poPart->get_AreaOfCurveSegments();
901     }
902     return dfArea;
903 }
904