1 /******************************************************************************
2  * $Id: ogrcompoundcurve.cpp 27960 2014-11-14 18:31:32Z rouault $
3  *
4  * Project:  OpenGIS Simple Features Reference Implementation
5  * Purpose:  The OGRCompoundCurve geometry class.
6  * Author:   Even Rouault, even dot rouault at spatialys dot com
7  *
8  ******************************************************************************
9  * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot 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 "ogr_geometry.h"
31 #include "ogr_p.h"
32 #include <assert.h>
33 
34 CPL_CVSID("$Id");
35 
36 /************************************************************************/
37 /*                         OGRCompoundCurve()                           */
38 /************************************************************************/
39 
40 /**
41  * \brief Create an empty compound curve.
42  */
43 
OGRCompoundCurve()44 OGRCompoundCurve::OGRCompoundCurve()
45 
46 {
47 }
48 
49 /************************************************************************/
50 /*                         ~OGRCompoundCurve()                          */
51 /************************************************************************/
52 
~OGRCompoundCurve()53 OGRCompoundCurve::~OGRCompoundCurve()
54 
55 {
56 }
57 
58 /************************************************************************/
59 /*                          getGeometryType()                           */
60 /************************************************************************/
61 
getGeometryType() const62 OGRwkbGeometryType OGRCompoundCurve::getGeometryType() const
63 
64 {
65     if( getCoordinateDimension() == 3 )
66         return wkbCompoundCurveZ;
67     else
68         return wkbCompoundCurve;
69 }
70 
71 /************************************************************************/
72 /*                          getGeometryName()                           */
73 /************************************************************************/
74 
getGeometryName() const75 const char * OGRCompoundCurve::getGeometryName() const
76 
77 {
78     return "COMPOUNDCURVE";
79 }
80 
81 /************************************************************************/
82 /*                              WkbSize()                               */
83 /************************************************************************/
WkbSize() const84 int OGRCompoundCurve::WkbSize() const
85 {
86     return oCC.WkbSize();
87 }
88 
89 /************************************************************************/
90 /*                       addCurveDirectlyFromWkt()                      */
91 /************************************************************************/
92 
addCurveDirectlyFromWkb(OGRGeometry * poSelf,OGRCurve * poCurve)93 OGRErr OGRCompoundCurve::addCurveDirectlyFromWkb( OGRGeometry* poSelf,
94                                                   OGRCurve* poCurve )
95 {
96     OGRCompoundCurve* poCC = (OGRCompoundCurve*)poSelf;
97     return poCC->addCurveDirectlyInternal( poCurve, 1e-14, FALSE );
98 }
99 
100 /************************************************************************/
101 /*                           importFromWkb()                            */
102 /************************************************************************/
103 
importFromWkb(unsigned char * pabyData,int nSize,OGRwkbVariant eWkbVariant)104 OGRErr OGRCompoundCurve::importFromWkb( unsigned char * pabyData,
105                                         int nSize,
106                                         OGRwkbVariant eWkbVariant )
107 {
108     OGRwkbByteOrder eByteOrder;
109     int nDataOffset = 0;
110     OGRErr eErr = oCC.importPreambuleFromWkb(this, pabyData, nSize, nDataOffset,
111                                              eByteOrder, 9, eWkbVariant);
112     if( eErr >= 0 )
113         return eErr;
114 
115     return oCC.importBodyFromWkb(this, pabyData, nSize, nDataOffset,
116                                  FALSE /* bAcceptCompoundCurve */, addCurveDirectlyFromWkb,
117                                  eWkbVariant);
118 }
119 
120 /************************************************************************/
121 /*                            exportToWkb()                             */
122 /************************************************************************/
exportToWkb(OGRwkbByteOrder eByteOrder,unsigned char * pabyData,OGRwkbVariant eWkbVariant) const123 OGRErr OGRCompoundCurve::exportToWkb( OGRwkbByteOrder eByteOrder,
124                                       unsigned char * pabyData,
125                                       OGRwkbVariant eWkbVariant  ) const
126 {
127     if( eWkbVariant == wkbVariantOldOgc ) /* does not make sense for new geometries, so patch it */
128         eWkbVariant = wkbVariantIso;
129     return oCC.exportToWkb(this, eByteOrder, pabyData, eWkbVariant);
130 }
131 
132 /************************************************************************/
133 /*                       addCurveDirectlyFromWkt()                      */
134 /************************************************************************/
135 
addCurveDirectlyFromWkt(OGRGeometry * poSelf,OGRCurve * poCurve)136 OGRErr OGRCompoundCurve::addCurveDirectlyFromWkt( OGRGeometry* poSelf, OGRCurve* poCurve )
137 {
138     return ((OGRCompoundCurve*)poSelf)->addCurveDirectly(poCurve);
139 }
140 
141 /************************************************************************/
142 /*                           importFromWkt()                            */
143 /************************************************************************/
144 
importFromWkt(char ** ppszInput)145 OGRErr OGRCompoundCurve::importFromWkt( char ** ppszInput )
146 {
147     return importCurveCollectionFromWkt( ppszInput,
148                                          FALSE, /* bAllowEmptyComponent */
149                                          TRUE, /* bAllowLineString */
150                                          TRUE, /* bAllowCurve */
151                                          FALSE, /* bAllowCompoundCurve */
152                                          addCurveDirectlyFromWkt );
153 }
154 
155 /************************************************************************/
156 /*                            exportToWkt()                             */
157 /************************************************************************/
exportToWkt(char ** ppszDstText,CPL_UNUSED OGRwkbVariant eWkbVariant) const158 OGRErr OGRCompoundCurve::exportToWkt( char ** ppszDstText,
159                                       CPL_UNUSED OGRwkbVariant eWkbVariant ) const
160 
161 {
162     return oCC.exportToWkt(this, ppszDstText);
163 }
164 
165 /************************************************************************/
166 /*                               clone()                                */
167 /************************************************************************/
168 
clone() const169 OGRGeometry *OGRCompoundCurve::clone() const
170 {
171     OGRCompoundCurve       *poNewCC;
172 
173     poNewCC = new OGRCompoundCurve;
174     poNewCC->assignSpatialReference( getSpatialReference() );
175 
176     for( int i = 0; i < oCC.nCurveCount; i++ )
177     {
178         poNewCC->addCurve( oCC.papoCurves[i] );
179     }
180 
181     return poNewCC;
182 }
183 
184 /************************************************************************/
185 /*                               empty()                                */
186 /************************************************************************/
187 
empty()188 void OGRCompoundCurve::empty()
189 {
190     oCC.empty(this);
191 }
192 
193 /************************************************************************/
194 /*                            getEnvelope()                             */
195 /************************************************************************/
196 
getEnvelope(OGREnvelope * psEnvelope) const197 void OGRCompoundCurve::getEnvelope( OGREnvelope * psEnvelope ) const
198 {
199     oCC.getEnvelope(psEnvelope);
200 }
201 
202 /************************************************************************/
203 /*                            getEnvelope()                             */
204 /************************************************************************/
205 
getEnvelope(OGREnvelope3D * psEnvelope) const206 void OGRCompoundCurve::getEnvelope( OGREnvelope3D * psEnvelope ) const
207 {
208     oCC.getEnvelope(psEnvelope);
209 }
210 
211 /************************************************************************/
212 /*                               IsEmpty()                              */
213 /************************************************************************/
214 
IsEmpty() const215 OGRBoolean OGRCompoundCurve::IsEmpty() const
216 {
217     return oCC.IsEmpty();
218 }
219 
220 /************************************************************************/
221 /*                             get_Length()                             */
222 /*                                                                      */
223 /*      For now we return a simple euclidian 2D distance.               */
224 /************************************************************************/
225 
get_Length() const226 double OGRCompoundCurve::get_Length() const
227 {
228     double dfLength = 0.0;
229     for( int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++ )
230         dfLength += oCC.papoCurves[iGeom]->get_Length();
231     return dfLength;
232 }
233 
234 /************************************************************************/
235 /*                             StartPoint()                             */
236 /************************************************************************/
237 
StartPoint(OGRPoint * p) const238 void OGRCompoundCurve::StartPoint(OGRPoint *p) const
239 {
240     CPLAssert(oCC.nCurveCount > 0);
241     oCC.papoCurves[0]->StartPoint(p);
242 }
243 
244 /************************************************************************/
245 /*                              EndPoint()                              */
246 /************************************************************************/
247 
EndPoint(OGRPoint * p) const248 void OGRCompoundCurve::EndPoint(OGRPoint *p) const
249 {
250     CPLAssert(oCC.nCurveCount > 0);
251     oCC.papoCurves[oCC.nCurveCount-1]->EndPoint(p);
252 }
253 
254 /************************************************************************/
255 /*                               Value()                                */
256 /************************************************************************/
257 
Value(double dfDistance,OGRPoint * poPoint) const258 void OGRCompoundCurve::Value( double dfDistance, OGRPoint *poPoint ) const
259 {
260 
261     if( dfDistance < 0 )
262     {
263         StartPoint( poPoint );
264         return;
265     }
266 
267     double dfLength = 0;
268     for( int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++ )
269     {
270         double dfSegLength = oCC.papoCurves[iGeom]->get_Length();
271         if (dfSegLength > 0)
272         {
273             if( (dfLength <= dfDistance) && ((dfLength + dfSegLength) >=
274                                              dfDistance) )
275             {
276                 oCC.papoCurves[iGeom]->Value(dfDistance - dfLength, poPoint);
277 
278                 return;
279             }
280 
281             dfLength += dfSegLength;
282         }
283     }
284 
285     EndPoint( poPoint );
286 }
287 
288 /************************************************************************/
289 /*                         CurveToLineInternal()                        */
290 /************************************************************************/
291 
CurveToLineInternal(double dfMaxAngleStepSizeDegrees,const char * const * papszOptions,int bIsLinearRing) const292 OGRLineString* OGRCompoundCurve::CurveToLineInternal(double dfMaxAngleStepSizeDegrees,
293                                                      const char* const* papszOptions,
294                                                      int bIsLinearRing) const
295 {
296     OGRLineString* poLine;
297     if( bIsLinearRing )
298         poLine = new OGRLinearRing();
299     else
300         poLine = new OGRLineString();
301     poLine->assignSpatialReference(getSpatialReference());
302     for( int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++ )
303     {
304         OGRLineString* poSubLS = oCC.papoCurves[iGeom]->CurveToLine(dfMaxAngleStepSizeDegrees,
305                                                                     papszOptions);
306         poLine->addSubLineString(poSubLS, (iGeom == 0) ? 0 : 1);
307         delete poSubLS;
308     }
309     return poLine;
310 }
311 
312 /************************************************************************/
313 /*                          CurveToLine()                               */
314 /************************************************************************/
315 
CurveToLine(double dfMaxAngleStepSizeDegrees,const char * const * papszOptions) const316 OGRLineString* OGRCompoundCurve::CurveToLine(double dfMaxAngleStepSizeDegrees,
317                                              const char* const* papszOptions) const
318 {
319     return CurveToLineInternal(dfMaxAngleStepSizeDegrees, papszOptions, FALSE);
320 }
321 
322 /************************************************************************/
323 /*                               Equals()                                */
324 /************************************************************************/
325 
Equals(OGRGeometry * poOther) const326 OGRBoolean  OGRCompoundCurve::Equals( OGRGeometry *poOther ) const
327 {
328     OGRCompoundCurve *poOCC = (OGRCompoundCurve *) poOther;
329 
330     if( poOCC == this )
331         return TRUE;
332 
333     if( poOther->getGeometryType() != getGeometryType() )
334         return FALSE;
335 
336     return oCC.Equals(&(poOCC->oCC));
337 }
338 
339 /************************************************************************/
340 /*                       setCoordinateDimension()                       */
341 /************************************************************************/
342 
setCoordinateDimension(int nNewDimension)343 void OGRCompoundCurve::setCoordinateDimension( int nNewDimension )
344 {
345     oCC.setCoordinateDimension( this, nNewDimension );
346 }
347 
348 /************************************************************************/
349 /*                          getNumCurves()                              */
350 /************************************************************************/
351 
352 /**
353  * \brief Return the number of curves.
354  *
355  * Note that the number of curves making this compound curve.
356  *
357  * Relates to the ISO SQL/MM ST_NumCurves() function.
358  *
359  * @return number of curves.
360  */
361 
getNumCurves() const362 int          OGRCompoundCurve::getNumCurves() const
363 {
364     return oCC.nCurveCount;
365 }
366 
367 /************************************************************************/
368 /*                           getCurve()                                 */
369 /************************************************************************/
370 
371 /**
372  * \brief Fetch reference to indicated internal ring.
373  *
374  * Note that the returned curve pointer is to an internal data object of
375  * the OGRCompoundCurve.  It should not be modified or deleted by the application,
376  * and the pointer is only valid till the polygon is next modified.  Use
377  * the OGRGeometry::clone() method to make a separate copy within the
378  * application.
379  *
380  * Relates to the ISO SQL/MM ST_CurveN() function.
381  *
382  * @param iRing curve index from 0 to getNumCurves() - 1.
383  *
384  * @return pointer to curve.  May be NULL.
385  */
386 
getCurve(int i)387 OGRCurve    *OGRCompoundCurve::getCurve( int i )
388 {
389     return oCC.getCurve(i);
390 }
391 
392 /************************************************************************/
393 /*                           getCurve()                                 */
394 /************************************************************************/
395 
396 /**
397  * \brief Fetch reference to indicated internal ring.
398  *
399  * Note that the returned curve pointer is to an internal data object of
400  * the OGRCompoundCurve.  It should not be modified or deleted by the application,
401  * and the pointer is only valid till the polygon is next modified.  Use
402  * the OGRGeometry::clone() method to make a separate copy within the
403  * application.
404  *
405  * Relates to the ISO SQL/MM ST_CurveN() function.
406  *
407  * @param iRing curve index from 0 to getNumCurves() - 1.
408  *
409  * @return pointer to curve.  May be NULL.
410  */
411 
getCurve(int i) const412 const OGRCurve *OGRCompoundCurve::getCurve( int i ) const
413 {
414     return oCC.getCurve(i);
415 }
416 
417 /************************************************************************/
418 /*                           stealCurve()                               */
419 /************************************************************************/
420 
stealCurve(int i)421 OGRCurve* OGRCompoundCurve::stealCurve( int i )
422 {
423     return oCC.stealCurve(i);
424 }
425 
426 /************************************************************************/
427 /*                            addCurve()                                */
428 /************************************************************************/
429 
430 /**
431  * \brief Add a curve to the container.
432  *
433  * The passed geometry is cloned to make an internal copy.
434  *
435  * There is no ISO SQL/MM analog to this method.
436  *
437  * This method is the same as the C function OGR_G_AddGeometry().
438  *
439  * @param poCurve geometry to add to the container.
440  * @param dfToleranceEps tolerance when checking that the first point of a
441  *                       segment matches then end point of the previous one.
442  *                       Default value: 1e-14.
443  *
444  * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
445  * (for example if curves are not contiguous)
446  */
447 
addCurve(OGRCurve * poCurve,double dfToleranceEps)448 OGRErr OGRCompoundCurve::addCurve( OGRCurve* poCurve, double dfToleranceEps )
449 {
450     OGRCurve* poClonedCurve = (OGRCurve*)poCurve->clone();
451     OGRErr eErr = addCurveDirectly( poClonedCurve, dfToleranceEps );
452     if( eErr != OGRERR_NONE )
453         delete poClonedCurve;
454     return eErr;
455 }
456 
457 /************************************************************************/
458 /*                          addCurveDirectly()                          */
459 /************************************************************************/
460 
461 /**
462  * \brief Add a curve directly to the container.
463  *
464  * Ownership of the passed geometry is taken by the container rather than
465  * cloning as addCurve() does.
466  *
467  * There is no ISO SQL/MM analog to this method.
468  *
469  * This method is the same as the C function OGR_G_AddGeometryDirectly().
470  *
471  * @param poCurve geometry to add to the container.
472  * @param dfToleranceEps tolerance when checking that the first point of a
473  *                       segment matches then end point of the previous one.
474  *                       Default value: 1e-14.
475  *
476  * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
477  * (for example if curves are not contiguous)
478  */
addCurveDirectly(OGRCurve * poCurve,double dfToleranceEps)479 OGRErr OGRCompoundCurve::addCurveDirectly( OGRCurve* poCurve,
480                                            double dfToleranceEps )
481 {
482     return addCurveDirectlyInternal(poCurve, dfToleranceEps, TRUE );
483 }
484 
addCurveDirectlyInternal(OGRCurve * poCurve,double dfToleranceEps,int bNeedRealloc)485 OGRErr OGRCompoundCurve::addCurveDirectlyInternal( OGRCurve* poCurve,
486                                                    double dfToleranceEps,
487                                                    int bNeedRealloc )
488 {
489     if( poCurve->getNumPoints() == 1 )
490     {
491         CPLError(CE_Failure, CPLE_AppDefined, "Invalid curve: not enough points");
492         return OGRERR_FAILURE;
493     }
494 
495     OGRwkbGeometryType eCurveType = wkbFlatten(poCurve->getGeometryType());
496     if( EQUAL(poCurve->getGeometryName(), "LINEARRING") )
497     {
498         CPLError(CE_Failure, CPLE_AppDefined, "Linearring not allowed.");
499         return OGRERR_FAILURE;
500     }
501     else if( eCurveType == wkbCompoundCurve )
502     {
503         CPLError(CE_Failure, CPLE_AppDefined, "Cannot add a compound curve inside a compound curve");
504         return OGRERR_FAILURE;
505     }
506 
507     if( oCC.nCurveCount > 0 )
508     {
509         if( oCC.papoCurves[oCC.nCurveCount-1]->IsEmpty() ||
510             poCurve->IsEmpty() )
511         {
512             CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves");
513             return OGRERR_FAILURE;
514         }
515 
516         OGRPoint end, start;
517         oCC.papoCurves[oCC.nCurveCount-1]->EndPoint(&end);
518         poCurve->StartPoint(&start);
519         if( fabs(end.getX() - start.getX()) > dfToleranceEps ||
520             fabs(end.getY() - start.getY()) > dfToleranceEps ||
521             fabs(end.getZ() - start.getZ()) > dfToleranceEps )
522         {
523             CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves");
524             return OGRERR_FAILURE;
525         }
526         ((OGRSimpleCurve*)poCurve)->setPoint(0, &end); /* patch so that it matches exactly */
527     }
528 
529     return oCC.addCurveDirectly(this, poCurve, bNeedRealloc);
530 }
531 
532 /************************************************************************/
533 /*                             transform()                              */
534 /************************************************************************/
535 
transform(OGRCoordinateTransformation * poCT)536 OGRErr  OGRCompoundCurve::transform( OGRCoordinateTransformation *poCT )
537 {
538     return oCC.transform(this, poCT);
539 }
540 
541 /************************************************************************/
542 /*                            flattenTo2D()                             */
543 /************************************************************************/
544 
flattenTo2D()545 void OGRCompoundCurve::flattenTo2D()
546 {
547     oCC.flattenTo2D(this);
548 }
549 
550 /************************************************************************/
551 /*                              segmentize()                            */
552 /************************************************************************/
553 
segmentize(double dfMaxLength)554 void OGRCompoundCurve::segmentize(double dfMaxLength)
555 {
556     oCC.segmentize(dfMaxLength);
557 }
558 
559 /************************************************************************/
560 /*                               swapXY()                               */
561 /************************************************************************/
562 
swapXY()563 void OGRCompoundCurve::swapXY()
564 {
565     oCC.swapXY();
566 }
567 
568 /************************************************************************/
569 /*                         hasCurveGeometry()                           */
570 /************************************************************************/
571 
hasCurveGeometry(int bLookForNonLinear) const572 OGRBoolean OGRCompoundCurve::hasCurveGeometry(int bLookForNonLinear) const
573 {
574     if( bLookForNonLinear )
575     {
576         return oCC.hasCurveGeometry(bLookForNonLinear);
577     }
578     else
579         return TRUE;
580 }
581 
582 /************************************************************************/
583 /*                         getLinearGeometry()                        */
584 /************************************************************************/
585 
getLinearGeometry(double dfMaxAngleStepSizeDegrees,const char * const * papszOptions) const586 OGRGeometry* OGRCompoundCurve::getLinearGeometry(double dfMaxAngleStepSizeDegrees,
587                                                    const char* const* papszOptions) const
588 {
589     return CurveToLine(dfMaxAngleStepSizeDegrees, papszOptions);
590 }
591 
592 /************************************************************************/
593 /*                           getNumPoints()                             */
594 /************************************************************************/
595 
getNumPoints() const596 int OGRCompoundCurve::getNumPoints() const
597 {
598     int nPoints = 0;
599     for( int i = 0; i < oCC.nCurveCount; i++ )
600     {
601         nPoints += oCC.papoCurves[i]->getNumPoints();
602         if( i != 0 )
603             nPoints --;
604     }
605     return nPoints;
606 }
607 
608 /************************************************************************/
609 /*                      OGRCompoundCurvePointIterator                   */
610 /************************************************************************/
611 
612 class OGRCompoundCurvePointIterator: public OGRPointIterator
613 {
614         const OGRCompoundCurve *poCC;
615         int                     iCurCurve;
616         OGRPointIterator       *poCurveIter;
617 
618     public:
OGRCompoundCurvePointIterator(const OGRCompoundCurve * poCC)619         OGRCompoundCurvePointIterator(const OGRCompoundCurve* poCC) :
620                             poCC(poCC), iCurCurve(0), poCurveIter(NULL) {}
~OGRCompoundCurvePointIterator()621        ~OGRCompoundCurvePointIterator() { delete poCurveIter; }
622 
623         virtual OGRBoolean getNextPoint(OGRPoint* p);
624 };
625 
626 /************************************************************************/
627 /*                            getNextPoint()                            */
628 /************************************************************************/
629 
getNextPoint(OGRPoint * p)630 OGRBoolean OGRCompoundCurvePointIterator::getNextPoint(OGRPoint* p)
631 {
632     if( iCurCurve == poCC->getNumCurves() )
633         return FALSE;
634     if( poCurveIter == NULL )
635         poCurveIter = poCC->getCurve(0)->getPointIterator();
636     if( !poCurveIter->getNextPoint(p) )
637     {
638         iCurCurve ++;
639         if( iCurCurve == poCC->getNumCurves() )
640             return FALSE;
641         delete poCurveIter;
642         poCurveIter = poCC->getCurve(iCurCurve)->getPointIterator();
643         /* skip first point */
644         return poCurveIter->getNextPoint(p) &&
645                poCurveIter->getNextPoint(p);
646     }
647     return TRUE;
648 }
649 
650 /************************************************************************/
651 /*                         getPointIterator()                           */
652 /************************************************************************/
653 
getPointIterator() const654 OGRPointIterator* OGRCompoundCurve::getPointIterator() const
655 {
656     return new OGRCompoundCurvePointIterator(this);
657 }
658 
659 /************************************************************************/
660 /*                         CastToLineString()                        */
661 /************************************************************************/
662 
CastToLineString(OGRCompoundCurve * poCC)663 OGRLineString* OGRCompoundCurve::CastToLineString(OGRCompoundCurve* poCC)
664 {
665     for(int i=0;i<poCC->oCC.nCurveCount;i++)
666     {
667         poCC->oCC.papoCurves[i] = OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]);
668         if( poCC->oCC.papoCurves[i] == NULL )
669         {
670             delete poCC;
671             return NULL;
672         }
673     }
674 
675     if( poCC->oCC.nCurveCount == 1 )
676     {
677         OGRLineString* poLS = (OGRLineString*) poCC->oCC.papoCurves[0];
678         poLS->assignSpatialReference(poCC->getSpatialReference());
679         poCC->oCC.papoCurves[0] = NULL;
680         delete poCC;
681         return poLS;
682     }
683 
684     OGRLineString* poLS = poCC->CurveToLineInternal(0, NULL, FALSE);
685     delete poCC;
686     return poLS;
687 }
688 
689 /************************************************************************/
690 /*                           CastToLinearRing()                         */
691 /************************************************************************/
692 
693 /**
694  * \brief Cast to linear ring.
695  *
696  * The passed in geometry is consumed and a new one returned (or NULL in case
697  * of failure)
698  *
699  * @param poCC the input geometry - ownership is passed to the method.
700  * @return new geometry.
701  */
702 
CastToLinearRing(OGRCompoundCurve * poCC)703 OGRLinearRing* OGRCompoundCurve::CastToLinearRing(OGRCompoundCurve* poCC)
704 {
705     for(int i=0;i<poCC->oCC.nCurveCount;i++)
706     {
707         poCC->oCC.papoCurves[i] = OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]);
708         if( poCC->oCC.papoCurves[i] == NULL )
709         {
710             delete poCC;
711             return NULL;
712         }
713     }
714 
715     if( poCC->oCC.nCurveCount == 1 )
716     {
717         OGRLinearRing* poLR = OGRCurve::CastToLinearRing( poCC->oCC.papoCurves[0] );
718         if( poLR != NULL )
719         {
720             poLR->assignSpatialReference(poCC->getSpatialReference());
721         }
722         poCC->oCC.papoCurves[0] = NULL;
723         delete poCC;
724         return poLR;
725     }
726 
727     OGRLinearRing* poLR = (OGRLinearRing*)poCC->CurveToLineInternal(0, NULL, TRUE);
728     delete poCC;
729     return poLR;
730 }
731 
732 /************************************************************************/
733 /*                     GetCasterToLineString()                          */
734 /************************************************************************/
735 
GetCasterToLineString() const736 OGRCurveCasterToLineString OGRCompoundCurve::GetCasterToLineString() const {
737     return (OGRCurveCasterToLineString) OGRCompoundCurve::CastToLineString;
738 }
739 
740 /************************************************************************/
741 /*                        GetCasterToLinearRing()                       */
742 /************************************************************************/
743 
GetCasterToLinearRing() const744 OGRCurveCasterToLinearRing OGRCompoundCurve::GetCasterToLinearRing() const {
745     return (OGRCurveCasterToLinearRing) OGRCompoundCurve::CastToLinearRing;
746 }
747 
748 /************************************************************************/
749 /*                           get_Area()                                 */
750 /************************************************************************/
751 
get_Area() const752 double OGRCompoundCurve::get_Area() const
753 {
754     if( IsEmpty() || !get_IsClosed() )
755         return 0;
756 
757     /* Optimization for convex rings */
758     if( IsConvex() )
759     {
760         /* Compute area of shape without the circular segments */
761         OGRPointIterator* poIter = getPointIterator();
762         OGRLineString oLS;
763         oLS.setNumPoints( getNumPoints() );
764         OGRPoint p;
765         for(int i = 0; poIter->getNextPoint(&p); i++ )
766         {
767             oLS.setPoint( i, p.getX(), p.getY() );
768         }
769         double dfArea = oLS.get_Area();
770         delete poIter;
771 
772         /* Add the area of the spherical segments */
773         dfArea += get_AreaOfCurveSegments();
774 
775         return dfArea;
776     }
777     else
778     {
779         OGRLineString* poLS = CurveToLine();
780         double dfArea = poLS->get_Area();
781         delete poLS;
782 
783         return dfArea;
784     }
785 }
786 
787 /************************************************************************/
788 /*                       get_AreaOfCurveSegments()                      */
789 /************************************************************************/
790 
get_AreaOfCurveSegments() const791 double OGRCompoundCurve::get_AreaOfCurveSegments() const
792 {
793     double dfArea = 0;
794     for( int i = 0; i < getNumCurves(); i++ )
795     {
796         const OGRCurve* poPart = getCurve(i);
797         dfArea += poPart->get_AreaOfCurveSegments();
798     }
799     return dfArea;
800 }
801