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