Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: The OGRCurveCollection 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 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "cpl_port.h"
14 : #include "ogr_geometry.h"
15 :
16 : #include <cstddef>
17 : #include <cstring>
18 : #include <limits>
19 : #include <new>
20 :
21 : #include "ogr_core.h"
22 : #include "ogr_p.h"
23 : #include "ogr_spatialref.h"
24 : #include "cpl_conv.h"
25 : #include "cpl_error.h"
26 : #include "cpl_string.h"
27 : #include "cpl_vsi.h"
28 :
29 : //! @cond Doxygen_Suppress
30 :
31 : /************************************************************************/
32 : /* OGRCurveCollection( const OGRCurveCollection& ) */
33 : /************************************************************************/
34 :
35 : /**
36 : * \brief Copy constructor.
37 : */
38 :
39 1585540 : OGRCurveCollection::OGRCurveCollection(const OGRCurveCollection &other)
40 : {
41 1585540 : if (other.nCurveCount > 0)
42 : {
43 1585260 : nCurveCount = other.nCurveCount;
44 1585260 : papoCurves = static_cast<OGRCurve **>(
45 1585260 : VSI_CALLOC_VERBOSE(sizeof(void *), nCurveCount));
46 :
47 1585260 : if (papoCurves)
48 : {
49 3171990 : for (int i = 0; i < nCurveCount; i++)
50 : {
51 1586730 : papoCurves[i] = other.papoCurves[i]->clone();
52 : }
53 : }
54 : }
55 1585540 : }
56 :
57 : /************************************************************************/
58 : /* OGRCurveCollection( OGRCurveCollection&& ) */
59 : /************************************************************************/
60 :
61 : /**
62 : * \brief Move constructor.
63 : *
64 : * @since GDAL 3.11
65 : */
66 :
67 4 : OGRCurveCollection::OGRCurveCollection(OGRCurveCollection &&other)
68 4 : : nCurveCount(other.nCurveCount), papoCurves(other.papoCurves)
69 : {
70 4 : other.nCurveCount = 0;
71 4 : other.papoCurves = nullptr;
72 4 : }
73 :
74 : /************************************************************************/
75 : /* ~OGRCurveCollection() */
76 : /************************************************************************/
77 :
78 6276650 : OGRCurveCollection::~OGRCurveCollection()
79 :
80 : {
81 3138320 : empty(nullptr);
82 3138330 : }
83 :
84 : /************************************************************************/
85 : /* operator=( const OGRCurveCollection& ) */
86 : /************************************************************************/
87 :
88 : /**
89 : * \brief Assignment operator.
90 : */
91 :
92 : OGRCurveCollection &
93 16 : OGRCurveCollection::operator=(const OGRCurveCollection &other)
94 : {
95 16 : if (this != &other)
96 : {
97 16 : empty(nullptr);
98 :
99 16 : if (other.nCurveCount > 0)
100 : {
101 8 : nCurveCount = other.nCurveCount;
102 8 : papoCurves = static_cast<OGRCurve **>(
103 8 : VSI_MALLOC2_VERBOSE(sizeof(void *), nCurveCount));
104 :
105 8 : if (papoCurves)
106 : {
107 22 : for (int i = 0; i < nCurveCount; i++)
108 : {
109 14 : papoCurves[i] = other.papoCurves[i]->clone();
110 : }
111 : }
112 : }
113 : }
114 16 : return *this;
115 : }
116 :
117 : /************************************************************************/
118 : /* operator=( OGRCurveCollection&& ) */
119 : /************************************************************************/
120 :
121 : /**
122 : * \brief Move assignment operator.
123 : *
124 : * @since GDAL 3.11
125 : */
126 :
127 8 : OGRCurveCollection &OGRCurveCollection::operator=(OGRCurveCollection &&other)
128 : {
129 8 : if (this != &other)
130 : {
131 8 : empty(nullptr);
132 8 : std::swap(nCurveCount, other.nCurveCount);
133 8 : std::swap(papoCurves, other.papoCurves);
134 : }
135 8 : return *this;
136 : }
137 :
138 : /************************************************************************/
139 : /* WkbSize() */
140 : /************************************************************************/
141 :
142 1868 : size_t OGRCurveCollection::WkbSize() const
143 : {
144 1868 : size_t nSize = 9;
145 :
146 4098 : for (auto &&poSubGeom : *this)
147 : {
148 2230 : nSize += poSubGeom->WkbSize();
149 : }
150 :
151 1868 : return nSize;
152 : }
153 :
154 : /************************************************************************/
155 : /* addCurveDirectly() */
156 : /************************************************************************/
157 :
158 1492780 : OGRErr OGRCurveCollection::addCurveDirectly(OGRGeometry *poGeom,
159 : OGRCurve *poCurve, int bNeedRealloc)
160 : {
161 1492780 : poGeom->HomogenizeDimensionalityWith(poCurve);
162 :
163 1492790 : if (bNeedRealloc)
164 : {
165 : #if SIZEOF_VOIDP < 8
166 : if (nCurveCount == std::numeric_limits<int>::max() /
167 : static_cast<int>(sizeof(OGRCurve *)))
168 : {
169 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too many subgeometries");
170 : return OGRERR_FAILURE;
171 : }
172 : #else
173 1491040 : if (nCurveCount == std::numeric_limits<int>::max())
174 : {
175 0 : CPLError(CE_Failure, CPLE_AppDefined, "Too many subgeometries");
176 0 : return OGRERR_FAILURE;
177 : }
178 : #endif
179 :
180 1491040 : OGRCurve **papoNewCurves = static_cast<OGRCurve **>(VSI_REALLOC_VERBOSE(
181 : papoCurves, sizeof(OGRCurve *) * (nCurveCount + 1)));
182 1491040 : if (papoNewCurves == nullptr)
183 0 : return OGRERR_FAILURE;
184 1491040 : papoCurves = papoNewCurves;
185 : }
186 :
187 1492790 : papoCurves[nCurveCount] = poCurve;
188 :
189 1492790 : nCurveCount++;
190 :
191 1492790 : return OGRERR_NONE;
192 : }
193 :
194 : /************************************************************************/
195 : /* importPreambleFromWkb() */
196 : /************************************************************************/
197 :
198 45411 : OGRErr OGRCurveCollection::importPreambleFromWkb(
199 : OGRGeometry *poGeom, const unsigned char *pabyData, size_t &nSize,
200 : size_t &nDataOffset, OGRwkbByteOrder &eByteOrder, size_t nMinSubGeomSize,
201 : OGRwkbVariant eWkbVariant)
202 : {
203 45411 : int nCurveCountNew = 0;
204 :
205 45411 : OGRErr eErr = poGeom->importPreambleOfCollectionFromWkb(
206 : pabyData, nSize, nDataOffset, eByteOrder, nMinSubGeomSize,
207 : nCurveCountNew, eWkbVariant);
208 45410 : if (eErr != OGRERR_NONE)
209 391 : return eErr;
210 :
211 45019 : CPLAssert(nCurveCount == 0);
212 45019 : nCurveCount = nCurveCountNew;
213 :
214 : // coverity[tainted_data]
215 45019 : papoCurves = static_cast<OGRCurve **>(
216 45019 : VSI_CALLOC_VERBOSE(sizeof(void *), nCurveCount));
217 45019 : if (nCurveCount != 0 && papoCurves == nullptr)
218 : {
219 0 : nCurveCount = 0;
220 0 : return OGRERR_NOT_ENOUGH_MEMORY;
221 : }
222 :
223 45019 : return OGRERR_NONE;
224 : }
225 :
226 : /************************************************************************/
227 : /* importBodyFromWkb() */
228 : /************************************************************************/
229 :
230 1924 : OGRErr OGRCurveCollection::importBodyFromWkb(
231 : OGRGeometry *poGeom, const unsigned char *pabyData, size_t nSize,
232 : bool bAcceptCompoundCurve,
233 : OGRErr (*pfnAddCurveDirectlyFromWkb)(OGRGeometry *poGeom,
234 : OGRCurve *poCurve),
235 : OGRwkbVariant eWkbVariant, size_t &nBytesConsumedOut)
236 : {
237 1924 : nBytesConsumedOut = 0;
238 : /* -------------------------------------------------------------------- */
239 : /* Get the Geoms. */
240 : /* -------------------------------------------------------------------- */
241 1924 : const int nIter = nCurveCount;
242 1924 : nCurveCount = 0;
243 1924 : size_t nDataOffset = 0;
244 3669 : for (int iGeom = 0; iGeom < nIter; iGeom++)
245 : {
246 1925 : OGRGeometry *poSubGeom = nullptr;
247 :
248 : // Parses sub-geometry.
249 1925 : const unsigned char *pabySubData = pabyData + nDataOffset;
250 1925 : if (nSize < 9 && nSize != static_cast<size_t>(-1))
251 180 : return OGRERR_NOT_ENOUGH_DATA;
252 :
253 1923 : OGRwkbGeometryType eFlattenSubGeomType = wkbUnknown;
254 1923 : if (OGRReadWKBGeometryType(pabySubData, eWkbVariant,
255 1923 : &eFlattenSubGeomType) != OGRERR_NONE)
256 63 : return OGRERR_FAILURE;
257 1860 : eFlattenSubGeomType = wkbFlatten(eFlattenSubGeomType);
258 :
259 1860 : OGRErr eErr = OGRERR_NONE;
260 1860 : size_t nSubGeomBytesConsumedOut = 0;
261 5576 : if ((eFlattenSubGeomType != wkbCompoundCurve &&
262 1863 : OGR_GT_IsCurve(eFlattenSubGeomType)) ||
263 3 : (bAcceptCompoundCurve && eFlattenSubGeomType == wkbCompoundCurve))
264 : {
265 1858 : eErr = OGRGeometryFactory::createFromWkb(
266 : pabySubData, nullptr, &poSubGeom, nSize, eWkbVariant,
267 : nSubGeomBytesConsumedOut);
268 : }
269 : else
270 : {
271 2 : CPLDebug(
272 : "OGR",
273 : "Cannot add geometry of type (%d) to geometry of type (%d)",
274 2 : eFlattenSubGeomType, poGeom->getGeometryType());
275 2 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
276 : }
277 :
278 1858 : if (eErr == OGRERR_NONE)
279 : {
280 1747 : CPLAssert(nSubGeomBytesConsumedOut > 0);
281 1747 : if (nSize != static_cast<size_t>(-1))
282 : {
283 1747 : CPLAssert(nSize >= nSubGeomBytesConsumedOut);
284 1747 : nSize -= nSubGeomBytesConsumedOut;
285 : }
286 :
287 1747 : nDataOffset += nSubGeomBytesConsumedOut;
288 :
289 1747 : OGRCurve *poCurve = poSubGeom->toCurve();
290 1747 : eErr = pfnAddCurveDirectlyFromWkb(poGeom, poCurve);
291 : }
292 1858 : if (eErr != OGRERR_NONE)
293 : {
294 113 : delete poSubGeom;
295 113 : return eErr;
296 : }
297 : }
298 1744 : nBytesConsumedOut = nDataOffset;
299 :
300 1744 : return OGRERR_NONE;
301 : }
302 :
303 : /************************************************************************/
304 : /* exportToWkt() */
305 : /************************************************************************/
306 :
307 263 : std::string OGRCurveCollection::exportToWkt(const OGRGeometry *baseGeom,
308 : const OGRWktOptions &opts,
309 : OGRErr *err) const
310 : {
311 : try
312 : {
313 263 : bool first = true;
314 526 : std::string wkt(baseGeom->getGeometryName());
315 :
316 263 : OGRWktOptions optsModified(opts);
317 263 : optsModified.variant = wkbVariantIso;
318 263 : wkt += baseGeom->wktTypeString(optsModified.variant);
319 :
320 613 : for (int i = 0; i < nCurveCount; ++i)
321 : {
322 350 : OGRGeometry *geom = papoCurves[i];
323 :
324 350 : OGRErr subgeomErr = OGRERR_NONE;
325 350 : std::string tempWkt = geom->exportToWkt(optsModified, &subgeomErr);
326 350 : if (subgeomErr != OGRERR_NONE)
327 : {
328 0 : if (err)
329 0 : *err = subgeomErr;
330 0 : return std::string();
331 : }
332 :
333 : // A curve collection has a list of linestrings (OGRCompoundCurve),
334 : // which should have their leader removed, or a OGRCurvePolygon,
335 : // which has leaders for each of its sub-geometries that aren't
336 : // linestrings.
337 350 : if (tempWkt.compare(0, strlen("LINESTRING"), "LINESTRING") == 0)
338 : {
339 177 : auto pos = tempWkt.find('(');
340 177 : if (pos != std::string::npos)
341 177 : tempWkt = tempWkt.substr(pos);
342 : }
343 :
344 350 : if (tempWkt.find("EMPTY") != std::string::npos)
345 0 : continue;
346 :
347 350 : if (first)
348 232 : wkt += '(';
349 : else
350 118 : wkt += ',';
351 350 : first = false;
352 350 : wkt += tempWkt;
353 : }
354 :
355 263 : if (err)
356 262 : *err = OGRERR_NONE;
357 263 : if (first)
358 31 : wkt += "EMPTY";
359 : else
360 232 : wkt += ')';
361 263 : return wkt;
362 : }
363 0 : catch (const std::bad_alloc &e)
364 : {
365 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
366 0 : if (err)
367 0 : *err = OGRERR_FAILURE;
368 0 : return std::string();
369 : }
370 : }
371 :
372 : /************************************************************************/
373 : /* exportToWkb() */
374 : /************************************************************************/
375 :
376 : OGRErr
377 913 : OGRCurveCollection::exportToWkb(const OGRGeometry *poGeom,
378 : unsigned char *pabyData,
379 : const OGRwkbExportOptions *psOptions) const
380 : {
381 913 : if (psOptions == nullptr)
382 : {
383 : static const OGRwkbExportOptions defaultOptions;
384 0 : psOptions = &defaultOptions;
385 : }
386 :
387 : /* -------------------------------------------------------------------- */
388 : /* Set the byte order. */
389 : /* -------------------------------------------------------------------- */
390 913 : pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER(
391 : static_cast<unsigned char>(psOptions->eByteOrder));
392 :
393 : /* -------------------------------------------------------------------- */
394 : /* Set the geometry feature type, ensuring that 3D flag is */
395 : /* preserved. */
396 : /* -------------------------------------------------------------------- */
397 913 : GUInt32 nGType = poGeom->getIsoGeometryType();
398 913 : if (psOptions->eWkbVariant == wkbVariantPostGIS1)
399 : {
400 0 : const bool bIs3D = wkbHasZ(static_cast<OGRwkbGeometryType>(nGType));
401 0 : nGType = wkbFlatten(nGType);
402 0 : if (nGType == wkbCurvePolygon)
403 0 : nGType = POSTGIS15_CURVEPOLYGON;
404 0 : if (bIs3D)
405 : // Explicitly set wkb25DBit.
406 0 : nGType =
407 0 : static_cast<OGRwkbGeometryType>(nGType | wkb25DBitInternalUse);
408 : }
409 :
410 913 : if (OGR_SWAP(psOptions->eByteOrder))
411 : {
412 0 : nGType = CPL_SWAP32(nGType);
413 : }
414 :
415 913 : memcpy(pabyData + 1, &nGType, 4);
416 :
417 : /* -------------------------------------------------------------------- */
418 : /* Copy in the raw data. */
419 : /* -------------------------------------------------------------------- */
420 913 : if (OGR_SWAP(psOptions->eByteOrder))
421 : {
422 0 : const int nCount = CPL_SWAP32(nCurveCount);
423 0 : memcpy(pabyData + 5, &nCount, 4);
424 : }
425 : else
426 : {
427 913 : memcpy(pabyData + 5, &nCurveCount, 4);
428 : }
429 :
430 : // TODO(schwehr): Where do these 9 values come from?
431 913 : size_t nOffset = 9;
432 :
433 : /* ==================================================================== */
434 : /* Serialize each of the Geoms. */
435 : /* ==================================================================== */
436 1825 : for (auto &&poSubGeom : *this)
437 : {
438 912 : poSubGeom->exportToWkb(pabyData + nOffset, psOptions);
439 :
440 912 : nOffset += poSubGeom->WkbSize();
441 : }
442 :
443 913 : return OGRERR_NONE;
444 : }
445 :
446 : /************************************************************************/
447 : /* empty() */
448 : /************************************************************************/
449 :
450 3202790 : void OGRCurveCollection::empty(OGRGeometry *poGeom)
451 : {
452 3202790 : if (papoCurves != nullptr)
453 : {
454 6274760 : for (auto &&poSubGeom : *this)
455 : {
456 3139840 : delete poSubGeom;
457 : }
458 3134930 : CPLFree(papoCurves);
459 : }
460 :
461 3202800 : nCurveCount = 0;
462 3202800 : papoCurves = nullptr;
463 3202800 : if (poGeom)
464 64458 : poGeom->setCoordinateDimension(2);
465 3202800 : }
466 :
467 : /************************************************************************/
468 : /* getEnvelope() */
469 : /************************************************************************/
470 :
471 260505 : void OGRCurveCollection::getEnvelope(OGREnvelope *psEnvelope) const
472 : {
473 260505 : OGREnvelope3D oEnv3D;
474 260505 : getEnvelope(&oEnv3D);
475 260505 : psEnvelope->MinX = oEnv3D.MinX;
476 260505 : psEnvelope->MinY = oEnv3D.MinY;
477 260505 : psEnvelope->MaxX = oEnv3D.MaxX;
478 260505 : psEnvelope->MaxY = oEnv3D.MaxY;
479 260505 : }
480 :
481 : /************************************************************************/
482 : /* getEnvelope() */
483 : /************************************************************************/
484 :
485 641643 : void OGRCurveCollection::getEnvelope(OGREnvelope3D *psEnvelope) const
486 : {
487 641643 : OGREnvelope3D oGeomEnv;
488 641643 : bool bExtentSet = false;
489 :
490 641643 : *psEnvelope = OGREnvelope3D();
491 1285030 : for (int iGeom = 0; iGeom < nCurveCount; iGeom++)
492 : {
493 643386 : if (!papoCurves[iGeom]->IsEmpty())
494 : {
495 643386 : bExtentSet = true;
496 643386 : papoCurves[iGeom]->getEnvelope(&oGeomEnv);
497 643386 : psEnvelope->Merge(oGeomEnv);
498 : }
499 : }
500 :
501 641643 : if (!bExtentSet)
502 : {
503 : // To be backward compatible when called on empty geom
504 10 : psEnvelope->MinX = 0.0;
505 10 : psEnvelope->MinY = 0.0;
506 10 : psEnvelope->MinZ = 0.0;
507 10 : psEnvelope->MaxX = 0.0;
508 10 : psEnvelope->MaxY = 0.0;
509 10 : psEnvelope->MaxZ = 0.0;
510 : }
511 641643 : }
512 :
513 : /************************************************************************/
514 : /* IsEmpty() */
515 : /************************************************************************/
516 :
517 574835 : OGRBoolean OGRCurveCollection::IsEmpty() const
518 : {
519 574859 : for (auto &&poSubGeom : *this)
520 : {
521 574148 : if (!poSubGeom->IsEmpty())
522 574124 : return FALSE;
523 : }
524 712 : return TRUE;
525 : }
526 :
527 : /************************************************************************/
528 : /* Equals() */
529 : /************************************************************************/
530 :
531 43559 : OGRBoolean OGRCurveCollection::Equals(const OGRCurveCollection *poOCC) const
532 : {
533 43559 : if (getNumCurves() != poOCC->getNumCurves())
534 2 : return FALSE;
535 :
536 : // Should eventually test the SRS.
537 :
538 73198 : for (int iGeom = 0; iGeom < nCurveCount; iGeom++)
539 : {
540 43782 : if (!getCurve(iGeom)->Equals(poOCC->getCurve(iGeom)))
541 14141 : return FALSE;
542 : }
543 :
544 29416 : return TRUE;
545 : }
546 :
547 : /************************************************************************/
548 : /* setCoordinateDimension() */
549 : /************************************************************************/
550 :
551 65335 : bool OGRCurveCollection::setCoordinateDimension(OGRGeometry *poGeom,
552 : int nNewDimension)
553 : {
554 66264 : for (auto &&poSubGeom : *this)
555 : {
556 929 : if (!poSubGeom->setCoordinateDimension(nNewDimension))
557 0 : return false;
558 : }
559 :
560 65336 : return poGeom->OGRGeometry::setCoordinateDimension(nNewDimension);
561 : }
562 :
563 1463470 : bool OGRCurveCollection::set3D(OGRGeometry *poGeom, OGRBoolean bIs3D)
564 : {
565 1571020 : for (auto &&poSubGeom : *this)
566 : {
567 107555 : if (!poSubGeom->set3D(bIs3D))
568 0 : return false;
569 : }
570 :
571 1463470 : return poGeom->OGRGeometry::set3D(bIs3D);
572 : }
573 :
574 237829 : bool OGRCurveCollection::setMeasured(OGRGeometry *poGeom,
575 : OGRBoolean bIsMeasured)
576 : {
577 345457 : for (auto &&poSubGeom : *this)
578 : {
579 107628 : if (!poSubGeom->setMeasured(bIsMeasured))
580 0 : return false;
581 : }
582 :
583 237830 : return poGeom->OGRGeometry::setMeasured(bIsMeasured);
584 : }
585 :
586 : /************************************************************************/
587 : /* assignSpatialReference() */
588 : /************************************************************************/
589 :
590 1511120 : void OGRCurveCollection::assignSpatialReference(OGRGeometry *poGeom,
591 : const OGRSpatialReference *poSR)
592 : {
593 3024840 : for (auto &&poSubGeom : *this)
594 : {
595 1513720 : poSubGeom->assignSpatialReference(poSR);
596 : }
597 1511120 : poGeom->OGRGeometry::assignSpatialReference(poSR);
598 1511120 : }
599 :
600 : /************************************************************************/
601 : /* getNumCurves() */
602 : /************************************************************************/
603 :
604 87118 : int OGRCurveCollection::getNumCurves() const
605 : {
606 87118 : return nCurveCount;
607 : }
608 :
609 : /************************************************************************/
610 : /* getCurve() */
611 : /************************************************************************/
612 :
613 125491 : OGRCurve *OGRCurveCollection::getCurve(int i)
614 : {
615 125491 : if (i < 0 || i >= nCurveCount)
616 184 : return nullptr;
617 125307 : return papoCurves[i];
618 : }
619 :
620 : /************************************************************************/
621 : /* getCurve() */
622 : /************************************************************************/
623 :
624 211670 : const OGRCurve *OGRCurveCollection::getCurve(int i) const
625 : {
626 211670 : if (i < 0 || i >= nCurveCount)
627 3 : return nullptr;
628 211667 : return papoCurves[i];
629 : }
630 :
631 : /************************************************************************/
632 : /* stealCurve() */
633 : /************************************************************************/
634 :
635 5 : OGRCurve *OGRCurveCollection::stealCurve(int i)
636 : {
637 5 : if (i < 0 || i >= nCurveCount)
638 0 : return nullptr;
639 5 : OGRCurve *poRet = papoCurves[i];
640 5 : if (i < nCurveCount - 1)
641 : {
642 2 : memmove(papoCurves + i, papoCurves + i + 1,
643 2 : (nCurveCount - i - 1) * sizeof(OGRCurve *));
644 : }
645 5 : nCurveCount--;
646 5 : return poRet;
647 : }
648 :
649 : /************************************************************************/
650 : /* transform() */
651 : /************************************************************************/
652 :
653 638 : OGRErr OGRCurveCollection::transform(OGRGeometry *poGeom,
654 : OGRCoordinateTransformation *poCT)
655 : {
656 1498 : for (int iGeom = 0; iGeom < nCurveCount; iGeom++)
657 : {
658 860 : const OGRErr eErr = papoCurves[iGeom]->transform(poCT);
659 860 : if (eErr != OGRERR_NONE)
660 : {
661 0 : if (iGeom != 0)
662 : {
663 0 : CPLDebug("OGR", "OGRCurveCollection::transform() failed for a "
664 : "geometry other than the first, meaning some "
665 : "geometries are transformed and some are not!");
666 :
667 0 : return OGRERR_FAILURE;
668 : }
669 :
670 0 : return eErr;
671 : }
672 : }
673 :
674 638 : poGeom->assignSpatialReference(poCT->GetTargetCS());
675 :
676 638 : return OGRERR_NONE;
677 : }
678 :
679 : /************************************************************************/
680 : /* flattenTo2D() */
681 : /************************************************************************/
682 :
683 792 : void OGRCurveCollection::flattenTo2D(OGRGeometry *poGeom)
684 : {
685 1650 : for (auto &&poSubGeom : *this)
686 : {
687 858 : poSubGeom->flattenTo2D();
688 : }
689 :
690 792 : poGeom->setCoordinateDimension(2);
691 792 : }
692 :
693 : /************************************************************************/
694 : /* segmentize() */
695 : /************************************************************************/
696 :
697 44 : bool OGRCurveCollection::segmentize(double dfMaxLength)
698 : {
699 88 : for (auto &&poSubGeom : *this)
700 : {
701 44 : if (!poSubGeom->segmentize(dfMaxLength))
702 0 : return false;
703 : }
704 44 : return true;
705 : }
706 :
707 : /************************************************************************/
708 : /* swapXY() */
709 : /************************************************************************/
710 :
711 75 : void OGRCurveCollection::swapXY()
712 : {
713 150 : for (auto &&poSubGeom : *this)
714 : {
715 75 : poSubGeom->swapXY();
716 : }
717 75 : }
718 :
719 : /************************************************************************/
720 : /* hasCurveGeometry() */
721 : /************************************************************************/
722 :
723 129 : OGRBoolean OGRCurveCollection::hasCurveGeometry(int bLookForNonLinear) const
724 : {
725 183 : for (auto &&poSubGeom : *this)
726 : {
727 155 : if (poSubGeom->hasCurveGeometry(bLookForNonLinear))
728 101 : return TRUE;
729 : }
730 28 : return FALSE;
731 : }
732 :
733 : /************************************************************************/
734 : /* removeCurve() */
735 : /************************************************************************/
736 :
737 : /**
738 : * \brief Remove a geometry from the container.
739 : *
740 : * Removing a geometry will cause the geometry count to drop by one, and all
741 : * "higher" geometries will shuffle down one in index.
742 : *
743 : * @param iIndex the index of the geometry to delete. A value of -1 is a
744 : * special flag meaning that all geometries should be removed.
745 : *
746 : * @param bDelete if true the geometry will be deallocated, otherwise it will
747 : * not. The default is true as the container is considered to own the
748 : * geometries in it.
749 : *
750 : * @return OGRERR_NONE if successful, or OGRERR_FAILURE if the index is
751 : * out of range.
752 : */
753 :
754 22 : OGRErr OGRCurveCollection::removeCurve(int iIndex, bool bDelete)
755 :
756 : {
757 22 : if (iIndex < -1 || iIndex >= nCurveCount)
758 2 : return OGRERR_FAILURE;
759 :
760 : // Special case.
761 20 : if (iIndex == -1)
762 : {
763 3 : while (nCurveCount > 0)
764 2 : removeCurve(nCurveCount - 1, bDelete);
765 1 : return OGRERR_NONE;
766 : }
767 :
768 19 : if (bDelete)
769 19 : delete papoCurves[iIndex];
770 :
771 19 : memmove(papoCurves + iIndex, papoCurves + iIndex + 1,
772 19 : sizeof(void *) * (nCurveCount - iIndex - 1));
773 :
774 19 : nCurveCount--;
775 :
776 19 : return OGRERR_NONE;
777 : }
778 :
779 : /************************************************************************/
780 : /* hasEmptyParts() */
781 : /************************************************************************/
782 :
783 : /**
784 : * \brief Returns whether a geometry has empty parts/rings.
785 : *
786 : * Returns true if removeEmptyParts() will modify the geometry.
787 : *
788 : * This is different from IsEmpty().
789 : *
790 : * @since GDAL 3.10
791 : */
792 99 : bool OGRCurveCollection::hasEmptyParts() const
793 : {
794 198 : for (int i = 0; i < nCurveCount; ++i)
795 : {
796 103 : if (papoCurves[i]->IsEmpty() || papoCurves[i]->hasEmptyParts())
797 4 : return true;
798 : }
799 95 : return false;
800 : }
801 :
802 : /************************************************************************/
803 : /* removeEmptyParts() */
804 : /************************************************************************/
805 :
806 : /**
807 : * \brief Remove empty parts/rings from this geometry.
808 : *
809 : * @since GDAL 3.10
810 : */
811 9 : void OGRCurveCollection::removeEmptyParts()
812 : {
813 21 : for (int i = nCurveCount - 1; i >= 0; --i)
814 : {
815 12 : papoCurves[i]->removeEmptyParts();
816 12 : if (papoCurves[i]->IsEmpty())
817 4 : removeCurve(i, true);
818 : }
819 9 : }
820 :
821 : /************************************************************************/
822 : /* reversePoints() */
823 : /************************************************************************/
824 :
825 : /**
826 : * \brief Reverse point order.
827 : *
828 : * This method updates the points in this curve in place
829 : * reversing the point ordering (first for last, etc) and component ordering.
830 : *
831 : * @since 3.10
832 : */
833 1 : void OGRCurveCollection::reversePoints()
834 :
835 : {
836 2 : for (int i = 0; i < nCurveCount / 2; ++i)
837 : {
838 1 : std::swap(papoCurves[i], papoCurves[nCurveCount - 1 - i]);
839 : }
840 3 : for (int i = 0; i < nCurveCount; ++i)
841 : {
842 2 : papoCurves[i]->reversePoints();
843 : }
844 1 : }
845 :
846 : //! @endcond
|