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