Line data Source code
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 : /************************************************************************/
42 : /* OGRCompoundCurve() */
43 : /************************************************************************/
44 :
45 : /**
46 : * \brief Create an empty compound curve.
47 : */
48 :
49 : OGRCompoundCurve::OGRCompoundCurve() = default;
50 :
51 : /************************************************************************/
52 : /* OGRCompoundCurve( const OGRCompoundCurve& ) */
53 : /************************************************************************/
54 :
55 : /**
56 : * \brief Copy constructor.
57 : *
58 : * Note: before GDAL 2.1, only the default implementation of the constructor
59 : * existed, which could be unsafe to use.
60 : *
61 : * @since GDAL 2.1
62 : */
63 :
64 : OGRCompoundCurve::OGRCompoundCurve(const OGRCompoundCurve &) = default;
65 :
66 : /************************************************************************/
67 : /* ~OGRCompoundCurve() */
68 : /************************************************************************/
69 :
70 : OGRCompoundCurve::~OGRCompoundCurve() = default;
71 :
72 : /************************************************************************/
73 : /* operator=( const OGRCompoundCurve&) */
74 : /************************************************************************/
75 :
76 : /**
77 : * \brief Assignment operator.
78 : *
79 : * Note: before GDAL 2.1, only the default implementation of the operator
80 : * existed, which could be unsafe to use.
81 : *
82 : * @since GDAL 2.1
83 : */
84 :
85 5 : OGRCompoundCurve &OGRCompoundCurve::operator=(const OGRCompoundCurve &other)
86 : {
87 5 : if (this != &other)
88 : {
89 4 : OGRCurve::operator=(other);
90 :
91 4 : oCC = other.oCC;
92 : }
93 5 : return *this;
94 : }
95 :
96 : /************************************************************************/
97 : /* clone() */
98 : /************************************************************************/
99 :
100 247 : OGRCompoundCurve *OGRCompoundCurve::clone() const
101 :
102 : {
103 247 : return new (std::nothrow) OGRCompoundCurve(*this);
104 : }
105 :
106 : /************************************************************************/
107 : /* getGeometryType() */
108 : /************************************************************************/
109 :
110 6248 : OGRwkbGeometryType OGRCompoundCurve::getGeometryType() const
111 :
112 : {
113 6248 : if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
114 4659 : return wkbCompoundCurveZM;
115 1589 : else if (flags & OGR_G_MEASURED)
116 11 : return wkbCompoundCurveM;
117 1578 : else if (flags & OGR_G_3D)
118 137 : return wkbCompoundCurveZ;
119 : else
120 1441 : return wkbCompoundCurve;
121 : }
122 :
123 : /************************************************************************/
124 : /* getGeometryName() */
125 : /************************************************************************/
126 :
127 660 : const char *OGRCompoundCurve::getGeometryName() const
128 :
129 : {
130 660 : return "COMPOUNDCURVE";
131 : }
132 :
133 : /************************************************************************/
134 : /* WkbSize() */
135 : /************************************************************************/
136 890 : size_t OGRCompoundCurve::WkbSize() const
137 : {
138 890 : return oCC.WkbSize();
139 : }
140 :
141 : /************************************************************************/
142 : /* addCurveDirectlyFromWkt() */
143 : /************************************************************************/
144 :
145 1724 : OGRErr OGRCompoundCurve::addCurveDirectlyFromWkb(OGRGeometry *poSelf,
146 : OGRCurve *poCurve)
147 : {
148 1724 : OGRCompoundCurve *poCC = poSelf->toCompoundCurve();
149 1724 : return poCC->addCurveDirectlyInternal(poCurve, DEFAULT_TOLERANCE_EPSILON,
150 1724 : FALSE);
151 : }
152 :
153 : /************************************************************************/
154 : /* importFromWkb() */
155 : /************************************************************************/
156 :
157 1955 : OGRErr OGRCompoundCurve::importFromWkb(const unsigned char *pabyData,
158 : size_t nSize, OGRwkbVariant eWkbVariant,
159 : size_t &nBytesConsumedOut)
160 : {
161 1955 : OGRwkbByteOrder eByteOrder = wkbNDR;
162 1955 : size_t nDataOffset = 0;
163 : // coverity[tainted_data]
164 1955 : OGRErr eErr = oCC.importPreambleFromWkb(this, pabyData, nSize, nDataOffset,
165 : eByteOrder, 9, eWkbVariant);
166 1955 : if (eErr != OGRERR_NONE)
167 56 : return eErr;
168 :
169 1899 : eErr = oCC.importBodyFromWkb(this, pabyData + nDataOffset, nSize,
170 : false, // bAcceptCompoundCurve
171 : addCurveDirectlyFromWkb, eWkbVariant,
172 : nBytesConsumedOut);
173 1899 : if (eErr == OGRERR_NONE)
174 1719 : nBytesConsumedOut += nDataOffset;
175 1899 : return eErr;
176 : }
177 :
178 : /************************************************************************/
179 : /* exportToWkb() */
180 : /************************************************************************/
181 :
182 879 : OGRErr OGRCompoundCurve::exportToWkb(unsigned char *pabyData,
183 : const OGRwkbExportOptions *psOptions) const
184 : {
185 : OGRwkbExportOptions sOptions(psOptions ? *psOptions
186 879 : : OGRwkbExportOptions());
187 :
188 : // Does not make sense for new geometries, so patch it.
189 879 : if (sOptions.eWkbVariant == wkbVariantOldOgc)
190 14 : sOptions.eWkbVariant = wkbVariantIso;
191 1758 : return oCC.exportToWkb(this, pabyData, &sOptions);
192 : }
193 :
194 : /************************************************************************/
195 : /* addCurveDirectlyFromWkt() */
196 : /************************************************************************/
197 :
198 463 : OGRErr OGRCompoundCurve::addCurveDirectlyFromWkt(OGRGeometry *poSelf,
199 : OGRCurve *poCurve)
200 : {
201 463 : return poSelf->toCompoundCurve()->addCurveDirectly(poCurve);
202 : }
203 :
204 : /************************************************************************/
205 : /* importFromWkt() */
206 : /************************************************************************/
207 :
208 292 : OGRErr OGRCompoundCurve::importFromWkt(const char **ppszInput)
209 : {
210 292 : return importCurveCollectionFromWkt(ppszInput,
211 : FALSE, // bAllowEmptyComponent
212 : TRUE, // bAllowLineString
213 : TRUE, // bAllowCurve
214 : FALSE, // bAllowCompoundCurve
215 292 : addCurveDirectlyFromWkt);
216 : }
217 :
218 : /************************************************************************/
219 : /* exportToWkt() */
220 : /************************************************************************/
221 101 : std::string OGRCompoundCurve::exportToWkt(const OGRWktOptions &opts,
222 : OGRErr *err) const
223 : {
224 101 : return oCC.exportToWkt(this, opts, err);
225 : }
226 :
227 : /************************************************************************/
228 : /* empty() */
229 : /************************************************************************/
230 :
231 2263 : void OGRCompoundCurve::empty()
232 : {
233 2263 : oCC.empty(this);
234 2263 : }
235 :
236 : /************************************************************************/
237 : /* getEnvelope() */
238 : /************************************************************************/
239 :
240 18 : void OGRCompoundCurve::getEnvelope(OGREnvelope *psEnvelope) const
241 : {
242 18 : oCC.getEnvelope(psEnvelope);
243 18 : }
244 :
245 : /************************************************************************/
246 : /* getEnvelope() */
247 : /************************************************************************/
248 :
249 44 : void OGRCompoundCurve::getEnvelope(OGREnvelope3D *psEnvelope) const
250 : {
251 44 : oCC.getEnvelope(psEnvelope);
252 44 : }
253 :
254 : /************************************************************************/
255 : /* IsEmpty() */
256 : /************************************************************************/
257 :
258 727 : OGRBoolean OGRCompoundCurve::IsEmpty() const
259 : {
260 727 : return oCC.IsEmpty();
261 : }
262 :
263 : /************************************************************************/
264 : /* get_Length() */
265 : /* */
266 : /* For now we return a simple euclidean 2D distance. */
267 : /************************************************************************/
268 :
269 5 : double OGRCompoundCurve::get_Length() const
270 : {
271 5 : double dfLength = 0.0;
272 9 : for (int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++)
273 4 : dfLength += oCC.papoCurves[iGeom]->get_Length();
274 5 : return dfLength;
275 : }
276 :
277 : /************************************************************************/
278 : /* StartPoint() */
279 : /************************************************************************/
280 :
281 397 : void OGRCompoundCurve::StartPoint(OGRPoint *p) const
282 : {
283 397 : CPLAssert(oCC.nCurveCount > 0);
284 397 : oCC.papoCurves[0]->StartPoint(p);
285 397 : }
286 :
287 : /************************************************************************/
288 : /* EndPoint() */
289 : /************************************************************************/
290 :
291 387 : void OGRCompoundCurve::EndPoint(OGRPoint *p) const
292 : {
293 387 : CPLAssert(oCC.nCurveCount > 0);
294 387 : oCC.papoCurves[oCC.nCurveCount - 1]->EndPoint(p);
295 387 : }
296 :
297 : /************************************************************************/
298 : /* Value() */
299 : /************************************************************************/
300 :
301 5 : void OGRCompoundCurve::Value(double dfDistance, OGRPoint *poPoint) const
302 : {
303 :
304 5 : if (dfDistance < 0)
305 : {
306 1 : StartPoint(poPoint);
307 1 : return;
308 : }
309 :
310 4 : double dfLength = 0.0;
311 7 : for (int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++)
312 : {
313 6 : const double dfSegLength = oCC.papoCurves[iGeom]->get_Length();
314 6 : if (dfSegLength > 0)
315 : {
316 6 : if ((dfLength <= dfDistance) &&
317 6 : ((dfLength + dfSegLength) >= dfDistance))
318 : {
319 3 : oCC.papoCurves[iGeom]->Value(dfDistance - dfLength, poPoint);
320 :
321 3 : return;
322 : }
323 :
324 3 : dfLength += dfSegLength;
325 : }
326 : }
327 :
328 1 : EndPoint(poPoint);
329 : }
330 :
331 : /************************************************************************/
332 : /* CurveToLineInternal() */
333 : /************************************************************************/
334 :
335 : OGRLineString *
336 678 : OGRCompoundCurve::CurveToLineInternal(double dfMaxAngleStepSizeDegrees,
337 : const char *const *papszOptions,
338 : int bIsLinearRing) const
339 : {
340 : OGRLineString *const poLine =
341 678 : bIsLinearRing ? new OGRLinearRing() : new OGRLineString();
342 678 : poLine->assignSpatialReference(getSpatialReference());
343 2084 : for (int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++)
344 : {
345 2812 : OGRLineString *poSubLS = oCC.papoCurves[iGeom]->CurveToLine(
346 1406 : dfMaxAngleStepSizeDegrees, papszOptions);
347 1406 : poLine->addSubLineString(poSubLS, (iGeom == 0) ? 0 : 1);
348 1406 : delete poSubLS;
349 : }
350 678 : return poLine;
351 : }
352 :
353 : /************************************************************************/
354 : /* CurveToLine() */
355 : /************************************************************************/
356 :
357 : OGRLineString *
358 665 : OGRCompoundCurve::CurveToLine(double dfMaxAngleStepSizeDegrees,
359 : const char *const *papszOptions) const
360 : {
361 665 : return CurveToLineInternal(dfMaxAngleStepSizeDegrees, papszOptions, FALSE);
362 : }
363 :
364 : /************************************************************************/
365 : /* Equals() */
366 : /************************************************************************/
367 :
368 870 : OGRBoolean OGRCompoundCurve::Equals(const OGRGeometry *poOther) const
369 : {
370 870 : if (poOther == this)
371 1 : return TRUE;
372 :
373 869 : if (poOther->getGeometryType() != getGeometryType())
374 1 : return FALSE;
375 :
376 868 : return oCC.Equals(&(poOther->toCompoundCurve()->oCC));
377 : }
378 :
379 : /************************************************************************/
380 : /* setCoordinateDimension() */
381 : /************************************************************************/
382 :
383 2269 : void OGRCompoundCurve::setCoordinateDimension(int nNewDimension)
384 : {
385 2269 : oCC.setCoordinateDimension(this, nNewDimension);
386 2269 : }
387 :
388 4091 : void OGRCompoundCurve::set3D(OGRBoolean bIs3D)
389 : {
390 4091 : oCC.set3D(this, bIs3D);
391 4091 : }
392 :
393 6263 : void OGRCompoundCurve::setMeasured(OGRBoolean bIsMeasured)
394 : {
395 6263 : oCC.setMeasured(this, bIsMeasured);
396 6263 : }
397 :
398 : /************************************************************************/
399 : /* assignSpatialReference() */
400 : /************************************************************************/
401 :
402 2440 : void OGRCompoundCurve::assignSpatialReference(const OGRSpatialReference *poSR)
403 : {
404 2440 : oCC.assignSpatialReference(this, poSR);
405 2440 : }
406 :
407 : /************************************************************************/
408 : /* getNumCurves() */
409 : /************************************************************************/
410 :
411 : /**
412 : * \brief Return the number of curves.
413 : *
414 : * Note that the number of curves making this compound curve.
415 : *
416 : * Relates to the ISO SQL/MM ST_NumCurves() function.
417 : *
418 : * @return number of curves.
419 : */
420 :
421 986 : int OGRCompoundCurve::getNumCurves() const
422 : {
423 986 : return oCC.nCurveCount;
424 : }
425 :
426 : /************************************************************************/
427 : /* getCurve() */
428 : /************************************************************************/
429 :
430 : /**
431 : * \brief Fetch reference to indicated internal ring.
432 : *
433 : * Note that the returned curve pointer is to an internal data object of the
434 : * OGRCompoundCurve. It should not be modified or deleted by the application,
435 : * and the pointer is only valid till the polygon is next modified. Use the
436 : * OGRGeometry::clone() method to make a separate copy within the application.
437 : *
438 : * Relates to the ISO SQL/MM ST_CurveN() function.
439 : *
440 : * @param iRing curve index from 0 to getNumCurves() - 1.
441 : *
442 : * @return pointer to curve. May be NULL.
443 : */
444 :
445 244 : OGRCurve *OGRCompoundCurve::getCurve(int iRing)
446 : {
447 244 : return oCC.getCurve(iRing);
448 : }
449 :
450 : /************************************************************************/
451 : /* getCurve() */
452 : /************************************************************************/
453 :
454 : /**
455 : * \brief Fetch reference to indicated internal ring.
456 : *
457 : * Note that the returned curve pointer is to an internal data object of the
458 : * OGRCompoundCurve. It should not be modified or deleted by the application,
459 : * and the pointer is only valid till the polygon is next modified. Use the
460 : * OGRGeometry::clone() method to make a separate copy within the application.
461 : *
462 : * Relates to the ISO SQL/MM ST_CurveN() function.
463 : *
464 : * @param iCurve curve index from 0 to getNumCurves() - 1.
465 : *
466 : * @return pointer to curve. May be NULL.
467 : */
468 :
469 229 : const OGRCurve *OGRCompoundCurve::getCurve(int iCurve) const
470 : {
471 229 : return oCC.getCurve(iCurve);
472 : }
473 :
474 : /************************************************************************/
475 : /* stealCurve() */
476 : /************************************************************************/
477 :
478 : /**
479 : * \brief "Steal" reference to curve.
480 : *
481 : * @param iCurve curve index from 0 to getNumCurves() - 1.
482 : *
483 : * @return pointer to curve. May be NULL.
484 : */
485 :
486 5 : OGRCurve *OGRCompoundCurve::stealCurve(int iCurve)
487 : {
488 5 : return oCC.stealCurve(iCurve);
489 : }
490 :
491 : /************************************************************************/
492 : /* addCurve() */
493 : /************************************************************************/
494 :
495 : /**
496 : * \brief Add a curve to the container.
497 : *
498 : * The passed geometry is cloned to make an internal copy.
499 : *
500 : * There is no ISO SQL/MM analog to this method.
501 : *
502 : * This method is the same as the C function OGR_G_AddGeometry().
503 : *
504 : * @param poCurve geometry to add to the container.
505 : * @param dfToleranceEps relative tolerance when checking that the first point
506 : * of a segment matches then end point of the previous one. Default value:
507 : * OGRCompoundCurve::DEFAULT_TOLERANCE_EPSILON.
508 : *
509 : * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
510 : * (for example if curves are not contiguous)
511 : */
512 :
513 23 : OGRErr OGRCompoundCurve::addCurve(const OGRCurve *poCurve,
514 : double dfToleranceEps)
515 : {
516 23 : OGRCurve *poClonedCurve = poCurve->clone();
517 23 : const OGRErr eErr = addCurveDirectly(poClonedCurve, dfToleranceEps);
518 23 : if (eErr != OGRERR_NONE)
519 0 : delete poClonedCurve;
520 23 : return eErr;
521 : }
522 :
523 : /************************************************************************/
524 : /* addCurveDirectly() */
525 : /************************************************************************/
526 :
527 : /**
528 : * \brief Add a curve directly to the container.
529 : *
530 : * Ownership of the passed geometry is taken by the container rather than
531 : * cloning as addCurve() does, but only if the method is successful.
532 : * If the method fails, ownership still belongs to the caller.
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
540 : * of a segment matches then end point of the previous one. Default value:
541 : * OGRCompoundCurve::DEFAULT_TOLERANCE_EPSILON.
542 : *
543 : * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
544 : * (for example if curves are not contiguous)
545 : */
546 1103 : OGRErr OGRCompoundCurve::addCurveDirectly(OGRCurve *poCurve,
547 : double dfToleranceEps)
548 : {
549 1103 : return addCurveDirectlyInternal(poCurve, dfToleranceEps, TRUE);
550 : }
551 :
552 2911 : OGRErr OGRCompoundCurve::addCurveDirectlyInternal(OGRCurve *poCurve,
553 : double dfToleranceEps,
554 : int bNeedRealloc)
555 : {
556 2911 : if (poCurve->getNumPoints() == 1)
557 : {
558 5 : CPLError(CE_Failure, CPLE_AppDefined,
559 : "Invalid curve: not enough points");
560 5 : return OGRERR_FAILURE;
561 : }
562 :
563 : const OGRwkbGeometryType eCurveType =
564 2906 : wkbFlatten(poCurve->getGeometryType());
565 2906 : if (EQUAL(poCurve->getGeometryName(), "LINEARRING"))
566 : {
567 0 : CPLError(CE_Failure, CPLE_AppDefined, "Linearring not allowed.");
568 0 : return OGRERR_FAILURE;
569 : }
570 2906 : else if (eCurveType == wkbCompoundCurve)
571 : {
572 1 : CPLError(CE_Failure, CPLE_AppDefined,
573 : "Cannot add a compound curve inside a compound curve");
574 1 : return OGRERR_FAILURE;
575 : }
576 :
577 2905 : if (oCC.nCurveCount > 0)
578 : {
579 952 : if (oCC.papoCurves[oCC.nCurveCount - 1]->IsEmpty() ||
580 476 : poCurve->IsEmpty())
581 : {
582 0 : CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves");
583 3 : return OGRERR_FAILURE;
584 : }
585 :
586 476 : OGRPoint oEnd;
587 476 : OGRPoint start;
588 476 : oCC.papoCurves[oCC.nCurveCount - 1]->EndPoint(&oEnd);
589 476 : poCurve->StartPoint(&start);
590 476 : if (fabs(oEnd.getX() - start.getX()) >
591 476 : dfToleranceEps * fabs(start.getX()) ||
592 470 : fabs(oEnd.getY() - start.getY()) >
593 1415 : dfToleranceEps * fabs(start.getY()) ||
594 469 : fabs(oEnd.getZ() - start.getZ()) >
595 469 : dfToleranceEps * fabs(start.getZ()))
596 : {
597 7 : poCurve->EndPoint(&start);
598 7 : if (fabs(oEnd.getX() - start.getX()) >
599 7 : dfToleranceEps * fabs(start.getX()) ||
600 4 : fabs(oEnd.getY() - start.getY()) >
601 15 : dfToleranceEps * fabs(start.getY()) ||
602 4 : fabs(oEnd.getZ() - start.getZ()) >
603 4 : dfToleranceEps * fabs(start.getZ()))
604 : {
605 3 : CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves");
606 3 : return OGRERR_FAILURE;
607 : }
608 :
609 4 : CPLDebug("GML", "reversing curve");
610 4 : poCurve->toSimpleCurve()->reversePoints();
611 : }
612 : // Patch so that it matches exactly.
613 473 : poCurve->toSimpleCurve()->setPoint(0, &oEnd);
614 : }
615 :
616 2902 : return oCC.addCurveDirectly(this, poCurve, bNeedRealloc);
617 : }
618 :
619 : /************************************************************************/
620 : /* addCurve() */
621 : /************************************************************************/
622 :
623 : /**
624 : * \brief Add a curve directly to the container.
625 : *
626 : * There is no ISO SQL/MM analog to this method.
627 : *
628 : * This method is the same as the C function OGR_G_AddGeometryDirectly().
629 : *
630 : * @param poCurve geometry to add to the container.
631 : * @param dfToleranceEps relative tolerance when checking that the first point
632 : * of a segment matches then end point of the previous one. Default value:
633 : * OGRCompoundCurve::DEFAULT_TOLERANCE_EPSILON.
634 : *
635 : * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
636 : * (for example if curves are not contiguous)
637 : */
638 84 : OGRErr OGRCompoundCurve::addCurve(std::unique_ptr<OGRCurve> poCurve,
639 : double dfToleranceEps)
640 : {
641 84 : OGRCurve *poCurvePtr = poCurve.release();
642 84 : OGRErr eErr = addCurveDirectlyInternal(poCurvePtr, dfToleranceEps, TRUE);
643 84 : if (eErr != OGRERR_NONE)
644 1 : delete poCurvePtr;
645 84 : return eErr;
646 : }
647 :
648 : /************************************************************************/
649 : /* transform() */
650 : /************************************************************************/
651 :
652 3 : OGRErr OGRCompoundCurve::transform(OGRCoordinateTransformation *poCT)
653 : {
654 3 : return oCC.transform(this, poCT);
655 : }
656 :
657 : /************************************************************************/
658 : /* flattenTo2D() */
659 : /************************************************************************/
660 :
661 2 : void OGRCompoundCurve::flattenTo2D()
662 : {
663 2 : oCC.flattenTo2D(this);
664 2 : }
665 :
666 : /************************************************************************/
667 : /* segmentize() */
668 : /************************************************************************/
669 :
670 1 : void OGRCompoundCurve::segmentize(double dfMaxLength)
671 : {
672 1 : oCC.segmentize(dfMaxLength);
673 1 : }
674 :
675 : /************************************************************************/
676 : /* swapXY() */
677 : /************************************************************************/
678 :
679 1 : void OGRCompoundCurve::swapXY()
680 : {
681 1 : oCC.swapXY();
682 1 : }
683 :
684 : /************************************************************************/
685 : /* hasCurveGeometry() */
686 : /************************************************************************/
687 :
688 2192 : OGRBoolean OGRCompoundCurve::hasCurveGeometry(int bLookForNonLinear) const
689 : {
690 2192 : if (bLookForNonLinear)
691 : {
692 37 : return oCC.hasCurveGeometry(bLookForNonLinear);
693 : }
694 :
695 2155 : return TRUE;
696 : }
697 :
698 : /************************************************************************/
699 : /* getLinearGeometry() */
700 : /************************************************************************/
701 :
702 : OGRGeometry *
703 309 : OGRCompoundCurve::getLinearGeometry(double dfMaxAngleStepSizeDegrees,
704 : const char *const *papszOptions) const
705 : {
706 309 : return CurveToLine(dfMaxAngleStepSizeDegrees, papszOptions);
707 : }
708 :
709 : /************************************************************************/
710 : /* getNumPoints() */
711 : /************************************************************************/
712 :
713 236 : int OGRCompoundCurve::getNumPoints() const
714 : {
715 236 : int nPoints = 0;
716 699 : for (int i = 0; i < oCC.nCurveCount; i++)
717 : {
718 463 : nPoints += oCC.papoCurves[i]->getNumPoints();
719 463 : if (i != 0)
720 234 : nPoints--;
721 : }
722 236 : return nPoints;
723 : }
724 :
725 : /************************************************************************/
726 : /* OGRCompoundCurvePointIterator */
727 : /************************************************************************/
728 :
729 : class OGRCompoundCurvePointIterator final : public OGRPointIterator
730 : {
731 : CPL_DISALLOW_COPY_ASSIGN(OGRCompoundCurvePointIterator)
732 :
733 : const OGRCompoundCurve *poCC = nullptr;
734 : int iCurCurve = 0;
735 : OGRPointIterator *poCurveIter = nullptr;
736 :
737 : public:
738 87 : explicit OGRCompoundCurvePointIterator(const OGRCompoundCurve *poCCIn)
739 87 : : poCC(poCCIn)
740 : {
741 87 : }
742 :
743 174 : ~OGRCompoundCurvePointIterator() override
744 87 : {
745 87 : delete poCurveIter;
746 174 : }
747 :
748 : OGRBoolean getNextPoint(OGRPoint *p) override;
749 : };
750 :
751 : /************************************************************************/
752 : /* getNextPoint() */
753 : /************************************************************************/
754 :
755 513 : OGRBoolean OGRCompoundCurvePointIterator::getNextPoint(OGRPoint *p)
756 : {
757 513 : if (iCurCurve == poCC->getNumCurves())
758 0 : return FALSE;
759 513 : if (poCurveIter == nullptr)
760 87 : poCurveIter = poCC->getCurve(0)->getPointIterator();
761 513 : if (!poCurveIter->getNextPoint(p))
762 : {
763 126 : iCurCurve++;
764 126 : if (iCurCurve == poCC->getNumCurves())
765 56 : return FALSE;
766 70 : delete poCurveIter;
767 70 : poCurveIter = poCC->getCurve(iCurCurve)->getPointIterator();
768 : // Skip first point.
769 70 : return poCurveIter->getNextPoint(p) && poCurveIter->getNextPoint(p);
770 : }
771 387 : return TRUE;
772 : }
773 :
774 : /************************************************************************/
775 : /* getPointIterator() */
776 : /************************************************************************/
777 :
778 87 : OGRPointIterator *OGRCompoundCurve::getPointIterator() const
779 : {
780 87 : return new OGRCompoundCurvePointIterator(this);
781 : }
782 :
783 : /************************************************************************/
784 : /* CastToLineString() */
785 : /************************************************************************/
786 :
787 : //! @cond Doxygen_Suppress
788 9 : OGRLineString *OGRCompoundCurve::CastToLineString(OGRCompoundCurve *poCC)
789 : {
790 30 : for (int i = 0; i < poCC->oCC.nCurveCount; i++)
791 : {
792 42 : poCC->oCC.papoCurves[i] =
793 21 : OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]);
794 21 : if (poCC->oCC.papoCurves[i] == nullptr)
795 : {
796 0 : delete poCC;
797 0 : return nullptr;
798 : }
799 : }
800 :
801 9 : if (poCC->oCC.nCurveCount == 1)
802 : {
803 2 : OGRLineString *poLS = poCC->oCC.papoCurves[0]->toLineString();
804 2 : poLS->assignSpatialReference(poCC->getSpatialReference());
805 2 : poCC->oCC.papoCurves[0] = nullptr;
806 2 : delete poCC;
807 2 : return poLS;
808 : }
809 :
810 7 : OGRLineString *poLS = poCC->CurveToLineInternal(0, nullptr, FALSE);
811 7 : delete poCC;
812 7 : return poLS;
813 : }
814 :
815 : /************************************************************************/
816 : /* CastToLinearRing() */
817 : /************************************************************************/
818 :
819 : /**
820 : * \brief Cast to linear ring.
821 : *
822 : * The passed in geometry is consumed and a new one returned (or NULL in case
823 : * of failure)
824 : *
825 : * @param poCC the input geometry - ownership is passed to the method.
826 : * @return new geometry.
827 : */
828 :
829 20 : OGRLinearRing *OGRCompoundCurve::CastToLinearRing(OGRCompoundCurve *poCC)
830 : {
831 58 : for (int i = 0; i < poCC->oCC.nCurveCount; i++)
832 : {
833 76 : poCC->oCC.papoCurves[i] =
834 38 : OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]);
835 38 : if (poCC->oCC.papoCurves[i] == nullptr)
836 : {
837 0 : delete poCC;
838 0 : return nullptr;
839 : }
840 : }
841 :
842 20 : if (poCC->oCC.nCurveCount == 1)
843 : {
844 : OGRLinearRing *poLR =
845 14 : OGRCurve::CastToLinearRing(poCC->oCC.papoCurves[0]);
846 14 : if (poLR != nullptr)
847 : {
848 14 : poLR->assignSpatialReference(poCC->getSpatialReference());
849 : }
850 14 : poCC->oCC.papoCurves[0] = nullptr;
851 14 : delete poCC;
852 14 : return poLR;
853 : }
854 :
855 : OGRLinearRing *poLR =
856 6 : poCC->CurveToLineInternal(0, nullptr, TRUE)->toLinearRing();
857 6 : delete poCC;
858 6 : return poLR;
859 : }
860 :
861 : /************************************************************************/
862 : /* GetCasterToLineString() */
863 : /************************************************************************/
864 :
865 9 : OGRLineString *OGRCompoundCurve::CasterToLineString(OGRCurve *poCurve)
866 : {
867 9 : OGRCompoundCurve *poCC = poCurve->toCompoundCurve();
868 9 : return OGRCompoundCurve::CastToLineString(poCC);
869 : }
870 :
871 9 : OGRCurveCasterToLineString OGRCompoundCurve::GetCasterToLineString() const
872 : {
873 9 : return OGRCompoundCurve::CasterToLineString;
874 : }
875 :
876 : /************************************************************************/
877 : /* GetCasterToLinearRing() */
878 : /************************************************************************/
879 :
880 20 : OGRLinearRing *OGRCompoundCurve::CasterToLinearRing(OGRCurve *poCurve)
881 : {
882 20 : OGRCompoundCurve *poCC = poCurve->toCompoundCurve();
883 20 : return OGRCompoundCurve::CastToLinearRing(poCC);
884 : }
885 :
886 20 : OGRCurveCasterToLinearRing OGRCompoundCurve::GetCasterToLinearRing() const
887 : {
888 20 : return OGRCompoundCurve::CasterToLinearRing;
889 : }
890 :
891 : //! @endcond
892 :
893 : /************************************************************************/
894 : /* get_Area() */
895 : /************************************************************************/
896 :
897 41 : double OGRCompoundCurve::get_Area() const
898 : {
899 41 : if (IsEmpty() || !get_IsClosed())
900 0 : return 0;
901 :
902 : // Optimization for convex rings.
903 41 : if (IsConvex())
904 : {
905 : // Compute area of shape without the circular segments.
906 27 : OGRPointIterator *poIter = getPointIterator();
907 54 : OGRLineString oLS;
908 27 : oLS.setNumPoints(getNumPoints());
909 27 : OGRPoint p;
910 192 : for (int i = 0; poIter->getNextPoint(&p); i++)
911 : {
912 165 : oLS.setPoint(i, p.getX(), p.getY());
913 : }
914 27 : double dfArea = oLS.get_Area();
915 27 : delete poIter;
916 :
917 : // Add the area of the spherical segments.
918 27 : dfArea += get_AreaOfCurveSegments();
919 :
920 27 : return dfArea;
921 : }
922 :
923 14 : OGRLineString *poLS = CurveToLine();
924 14 : double dfArea = poLS->get_Area();
925 14 : delete poLS;
926 :
927 14 : return dfArea;
928 : }
929 :
930 : /************************************************************************/
931 : /* get_GeodesicArea() */
932 : /************************************************************************/
933 :
934 3 : double OGRCompoundCurve::get_GeodesicArea(
935 : const OGRSpatialReference *poSRSOverride) const
936 : {
937 3 : if (IsEmpty())
938 1 : return 0;
939 :
940 2 : if (!get_IsClosed())
941 : {
942 1 : CPLError(CE_Failure, CPLE_AppDefined, "Non-closed geometry");
943 1 : return -1;
944 : }
945 :
946 1 : if (!poSRSOverride)
947 1 : poSRSOverride = getSpatialReference();
948 :
949 1 : OGRLineString *poLS = CurveToLine();
950 1 : const double dfArea = poLS->get_GeodesicArea(poSRSOverride);
951 1 : delete poLS;
952 :
953 1 : return dfArea;
954 : }
955 :
956 : /************************************************************************/
957 : /* get_AreaOfCurveSegments() */
958 : /************************************************************************/
959 :
960 : /** Return area of curve segments
961 : * @return area.
962 : */
963 27 : double OGRCompoundCurve::get_AreaOfCurveSegments() const
964 : {
965 27 : double dfArea = 0;
966 82 : for (int i = 0; i < getNumCurves(); i++)
967 : {
968 55 : const OGRCurve *poPart = getCurve(i);
969 55 : dfArea += poPart->get_AreaOfCurveSegments();
970 : }
971 27 : return dfArea;
972 : }
|