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 1497790 : OGRCurveCollection::OGRCurveCollection(const OGRCurveCollection &other)
40 : {
41 1497790 : if (other.nCurveCount > 0)
42 : {
43 1497460 : nCurveCount = other.nCurveCount;
44 1497460 : papoCurves = static_cast<OGRCurve **>(
45 1497460 : VSI_CALLOC_VERBOSE(sizeof(void *), nCurveCount));
46 :
47 1497460 : if (papoCurves)
48 : {
49 2996420 : for (int i = 0; i < nCurveCount; i++)
50 : {
51 1498960 : papoCurves[i] = other.papoCurves[i]->clone();
52 : }
53 : }
54 : }
55 1497790 : }
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 6130920 : OGRCurveCollection::~OGRCurveCollection()
79 :
80 : {
81 3065460 : empty(nullptr);
82 3065460 : }
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 1842 : size_t OGRCurveCollection::WkbSize() const
143 : {
144 1842 : size_t nSize = 9;
145 :
146 4010 : for (auto &&poSubGeom : *this)
147 : {
148 2168 : nSize += poSubGeom->WkbSize();
149 : }
150 :
151 1842 : return nSize;
152 : }
153 :
154 : /************************************************************************/
155 : /* addCurveDirectly() */
156 : /************************************************************************/
157 :
158 1508750 : OGRErr OGRCurveCollection::addCurveDirectly(OGRGeometry *poGeom,
159 : OGRCurve *poCurve, int bNeedRealloc)
160 : {
161 1508750 : poGeom->HomogenizeDimensionalityWith(poCurve);
162 :
163 1508750 : 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 1507000 : 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 1507000 : OGRCurve **papoNewCurves = static_cast<OGRCurve **>(VSI_REALLOC_VERBOSE(
181 : papoCurves, sizeof(OGRCurve *) * (nCurveCount + 1)));
182 1507000 : if (papoNewCurves == nullptr)
183 0 : return OGRERR_FAILURE;
184 1507000 : papoCurves = papoNewCurves;
185 : }
186 :
187 1508750 : papoCurves[nCurveCount] = poCurve;
188 :
189 1508750 : nCurveCount++;
190 :
191 1508750 : return OGRERR_NONE;
192 : }
193 :
194 : /************************************************************************/
195 : /* importPreambleFromWkb() */
196 : /************************************************************************/
197 :
198 45940 : 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 45940 : int nCurveCountNew = 0;
204 :
205 45940 : OGRErr eErr = poGeom->importPreambleOfCollectionFromWkb(
206 : pabyData, nSize, nDataOffset, eByteOrder, nMinSubGeomSize,
207 : nCurveCountNew, eWkbVariant);
208 45940 : if (eErr != OGRERR_NONE)
209 391 : return eErr;
210 :
211 45549 : CPLAssert(nCurveCount == 0);
212 45549 : nCurveCount = nCurveCountNew;
213 :
214 : // coverity[tainted_data]
215 45549 : papoCurves = static_cast<OGRCurve **>(
216 45549 : VSI_CALLOC_VERBOSE(sizeof(void *), nCurveCount));
217 45549 : if (nCurveCount != 0 && papoCurves == nullptr)
218 : {
219 0 : nCurveCount = 0;
220 0 : return OGRERR_NOT_ENOUGH_MEMORY;
221 : }
222 :
223 45549 : 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 3130690 : void OGRCurveCollection::empty(OGRGeometry *poGeom)
451 : {
452 3130690 : if (papoCurves != nullptr)
453 : {
454 6135760 : for (auto &&poSubGeom : *this)
455 : {
456 3073920 : delete poSubGeom;
457 : }
458 3061840 : CPLFree(papoCurves);
459 : }
460 :
461 3130690 : nCurveCount = 0;
462 3130690 : papoCurves = nullptr;
463 3130690 : if (poGeom)
464 65206 : poGeom->setCoordinateDimension(2);
465 3130690 : }
466 :
467 : /************************************************************************/
468 : /* getEnvelope() */
469 : /************************************************************************/
470 :
471 270741 : void OGRCurveCollection::getEnvelope(OGREnvelope *psEnvelope) const
472 : {
473 270741 : OGREnvelope3D oEnv3D;
474 270741 : getEnvelope(&oEnv3D);
475 270741 : psEnvelope->MinX = oEnv3D.MinX;
476 270741 : psEnvelope->MinY = oEnv3D.MinY;
477 270741 : psEnvelope->MaxX = oEnv3D.MaxX;
478 270741 : psEnvelope->MaxY = oEnv3D.MaxY;
479 270741 : }
480 :
481 : /************************************************************************/
482 : /* getEnvelope() */
483 : /************************************************************************/
484 :
485 652358 : void OGRCurveCollection::getEnvelope(OGREnvelope3D *psEnvelope) const
486 : {
487 652358 : OGREnvelope3D oGeomEnv;
488 652358 : bool bExtentSet = false;
489 :
490 652358 : *psEnvelope = OGREnvelope3D();
491 1306680 : for (int iGeom = 0; iGeom < nCurveCount; iGeom++)
492 : {
493 654320 : if (!papoCurves[iGeom]->IsEmpty())
494 : {
495 654320 : bExtentSet = true;
496 654320 : papoCurves[iGeom]->getEnvelope(&oGeomEnv);
497 654320 : psEnvelope->Merge(oGeomEnv);
498 : }
499 : }
500 :
501 652358 : if (!bExtentSet)
502 : {
503 : // To be backward compatible when called on empty geom
504 8 : psEnvelope->MinX = 0.0;
505 8 : psEnvelope->MinY = 0.0;
506 8 : psEnvelope->MinZ = 0.0;
507 8 : psEnvelope->MaxX = 0.0;
508 8 : psEnvelope->MaxY = 0.0;
509 8 : psEnvelope->MaxZ = 0.0;
510 : }
511 652358 : }
512 :
513 : /************************************************************************/
514 : /* IsEmpty() */
515 : /************************************************************************/
516 :
517 586141 : bool OGRCurveCollection::IsEmpty() const
518 : {
519 586166 : for (auto &&poSubGeom : *this)
520 : {
521 585397 : if (!poSubGeom->IsEmpty())
522 585372 : return FALSE;
523 : }
524 769 : return TRUE;
525 : }
526 :
527 : /************************************************************************/
528 : /* Equals() */
529 : /************************************************************************/
530 :
531 43484 : bool OGRCurveCollection::Equals(const OGRCurveCollection *poOCC) const
532 : {
533 43484 : if (getNumCurves() != poOCC->getNumCurves())
534 2 : return FALSE;
535 :
536 : // Should eventually test the SRS.
537 :
538 73249 : for (int iGeom = 0; iGeom < nCurveCount; iGeom++)
539 : {
540 43735 : if (!getCurve(iGeom)->Equals(poOCC->getCurve(iGeom)))
541 13968 : return FALSE;
542 : }
543 :
544 29514 : return TRUE;
545 : }
546 :
547 : /************************************************************************/
548 : /* setCoordinateDimension() */
549 : /************************************************************************/
550 :
551 66100 : bool OGRCurveCollection::setCoordinateDimension(OGRGeometry *poGeom,
552 : int nNewDimension)
553 : {
554 67045 : for (auto &&poSubGeom : *this)
555 : {
556 945 : if (!poSubGeom->setCoordinateDimension(nNewDimension))
557 0 : return false;
558 : }
559 :
560 66100 : return poGeom->OGRGeometry::setCoordinateDimension(nNewDimension);
561 : }
562 :
563 1463490 : bool OGRCurveCollection::set3D(OGRGeometry *poGeom, bool bIs3D)
564 : {
565 1570950 : for (auto &&poSubGeom : *this)
566 : {
567 107460 : if (!poSubGeom->set3D(bIs3D))
568 0 : return false;
569 : }
570 :
571 1463490 : return poGeom->OGRGeometry::set3D(bIs3D);
572 : }
573 :
574 238544 : bool OGRCurveCollection::setMeasured(OGRGeometry *poGeom, bool bIsMeasured)
575 : {
576 346098 : for (auto &&poSubGeom : *this)
577 : {
578 107554 : if (!poSubGeom->setMeasured(bIsMeasured))
579 0 : return false;
580 : }
581 :
582 238544 : return poGeom->OGRGeometry::setMeasured(bIsMeasured);
583 : }
584 :
585 : /************************************************************************/
586 : /* assignSpatialReference() */
587 : /************************************************************************/
588 :
589 1524260 : void OGRCurveCollection::assignSpatialReference(OGRGeometry *poGeom,
590 : const OGRSpatialReference *poSR)
591 : {
592 3057340 : for (auto &&poSubGeom : *this)
593 : {
594 1533070 : poSubGeom->assignSpatialReference(poSR);
595 : }
596 1524260 : poGeom->OGRGeometry::assignSpatialReference(poSR);
597 1524260 : }
598 :
599 : /************************************************************************/
600 : /* getNumCurves() */
601 : /************************************************************************/
602 :
603 86968 : int OGRCurveCollection::getNumCurves() const
604 : {
605 86968 : return nCurveCount;
606 : }
607 :
608 : /************************************************************************/
609 : /* getCurve() */
610 : /************************************************************************/
611 :
612 208603 : OGRCurve *OGRCurveCollection::getCurve(int i)
613 : {
614 208603 : if (i < 0 || i >= nCurveCount)
615 256 : return nullptr;
616 208347 : return papoCurves[i];
617 : }
618 :
619 : /************************************************************************/
620 : /* getCurve() */
621 : /************************************************************************/
622 :
623 231245 : const OGRCurve *OGRCurveCollection::getCurve(int i) const
624 : {
625 231245 : if (i < 0 || i >= nCurveCount)
626 3 : return nullptr;
627 231242 : return papoCurves[i];
628 : }
629 :
630 : /************************************************************************/
631 : /* stealCurve() */
632 : /************************************************************************/
633 :
634 5 : OGRCurve *OGRCurveCollection::stealCurve(int i)
635 : {
636 5 : if (i < 0 || i >= nCurveCount)
637 0 : return nullptr;
638 5 : OGRCurve *poRet = papoCurves[i];
639 5 : if (i < nCurveCount - 1)
640 : {
641 2 : memmove(papoCurves + i, papoCurves + i + 1,
642 2 : (nCurveCount - i - 1) * sizeof(OGRCurve *));
643 : }
644 5 : nCurveCount--;
645 5 : return poRet;
646 : }
647 :
648 : /************************************************************************/
649 : /* transform() */
650 : /************************************************************************/
651 :
652 653 : OGRErr OGRCurveCollection::transform(OGRGeometry *poGeom,
653 : OGRCoordinateTransformation *poCT)
654 : {
655 1527 : for (int iGeom = 0; iGeom < nCurveCount; iGeom++)
656 : {
657 875 : const OGRErr eErr = papoCurves[iGeom]->transform(poCT);
658 875 : if (eErr != OGRERR_NONE)
659 : {
660 1 : if (iGeom != 0)
661 : {
662 0 : CPLDebug("OGR", "OGRCurveCollection::transform() failed for a "
663 : "geometry other than the first, meaning some "
664 : "geometries are transformed and some are not!");
665 :
666 0 : return OGRERR_FAILURE;
667 : }
668 :
669 1 : return eErr;
670 : }
671 : }
672 :
673 652 : poGeom->assignSpatialReference(poCT->GetTargetCS());
674 :
675 652 : return OGRERR_NONE;
676 : }
677 :
678 : /************************************************************************/
679 : /* flattenTo2D() */
680 : /************************************************************************/
681 :
682 792 : void OGRCurveCollection::flattenTo2D(OGRGeometry *poGeom)
683 : {
684 1650 : for (auto &&poSubGeom : *this)
685 : {
686 858 : poSubGeom->flattenTo2D();
687 : }
688 :
689 792 : poGeom->setCoordinateDimension(2);
690 792 : }
691 :
692 : /************************************************************************/
693 : /* segmentize() */
694 : /************************************************************************/
695 :
696 44 : bool OGRCurveCollection::segmentize(double dfMaxLength)
697 : {
698 88 : for (auto &&poSubGeom : *this)
699 : {
700 44 : if (!poSubGeom->segmentize(dfMaxLength))
701 0 : return false;
702 : }
703 44 : return true;
704 : }
705 :
706 : /************************************************************************/
707 : /* swapXY() */
708 : /************************************************************************/
709 :
710 105 : void OGRCurveCollection::swapXY()
711 : {
712 210 : for (auto &&poSubGeom : *this)
713 : {
714 105 : poSubGeom->swapXY();
715 : }
716 105 : }
717 :
718 : /************************************************************************/
719 : /* hasCurveGeometry() */
720 : /************************************************************************/
721 :
722 130 : bool OGRCurveCollection::hasCurveGeometry(int bLookForNonLinear) const
723 : {
724 185 : for (auto &&poSubGeom : *this)
725 : {
726 156 : if (poSubGeom->hasCurveGeometry(bLookForNonLinear))
727 101 : return TRUE;
728 : }
729 29 : return FALSE;
730 : }
731 :
732 : /************************************************************************/
733 : /* removeCurve() */
734 : /************************************************************************/
735 :
736 : /**
737 : * \brief Remove a geometry from the container.
738 : *
739 : * Removing a geometry will cause the geometry count to drop by one, and all
740 : * "higher" geometries will shuffle down one in index.
741 : *
742 : * @param iIndex the index of the geometry to delete. A value of -1 is a
743 : * special flag meaning that all geometries should be removed.
744 : *
745 : * @param bDelete if true the geometry will be deallocated, otherwise it will
746 : * not. The default is true as the container is considered to own the
747 : * geometries in it.
748 : *
749 : * @return OGRERR_NONE if successful, or OGRERR_FAILURE if the index is
750 : * out of range.
751 : */
752 :
753 28 : OGRErr OGRCurveCollection::removeCurve(int iIndex, bool bDelete)
754 :
755 : {
756 28 : if (iIndex < -1 || iIndex >= nCurveCount)
757 2 : return OGRERR_FAILURE;
758 :
759 : // Special case.
760 26 : if (iIndex == -1)
761 : {
762 3 : while (nCurveCount > 0)
763 2 : removeCurve(nCurveCount - 1, bDelete);
764 1 : return OGRERR_NONE;
765 : }
766 :
767 25 : if (bDelete)
768 23 : delete papoCurves[iIndex];
769 :
770 25 : memmove(papoCurves + iIndex, papoCurves + iIndex + 1,
771 25 : sizeof(void *) * (nCurveCount - iIndex - 1));
772 :
773 25 : nCurveCount--;
774 :
775 25 : return OGRERR_NONE;
776 : }
777 :
778 : /************************************************************************/
779 : /* hasEmptyParts() */
780 : /************************************************************************/
781 :
782 : /**
783 : * \brief Returns whether a geometry has empty parts/rings.
784 : *
785 : * Returns true if removeEmptyParts() will modify the geometry.
786 : *
787 : * This is different from IsEmpty().
788 : *
789 : * @since GDAL 3.10
790 : */
791 99 : bool OGRCurveCollection::hasEmptyParts() const
792 : {
793 198 : for (int i = 0; i < nCurveCount; ++i)
794 : {
795 103 : if (papoCurves[i]->IsEmpty() || papoCurves[i]->hasEmptyParts())
796 4 : return true;
797 : }
798 95 : return false;
799 : }
800 :
801 : /************************************************************************/
802 : /* removeEmptyParts() */
803 : /************************************************************************/
804 :
805 : /**
806 : * \brief Remove empty parts/rings from this geometry.
807 : *
808 : * @since GDAL 3.10
809 : */
810 9 : void OGRCurveCollection::removeEmptyParts()
811 : {
812 21 : for (int i = nCurveCount - 1; i >= 0; --i)
813 : {
814 12 : papoCurves[i]->removeEmptyParts();
815 12 : if (papoCurves[i]->IsEmpty())
816 4 : removeCurve(i, true);
817 : }
818 9 : }
819 :
820 : /************************************************************************/
821 : /* reversePoints() */
822 : /************************************************************************/
823 :
824 : /**
825 : * \brief Reverse point order.
826 : *
827 : * This method updates the points in this curve in place
828 : * reversing the point ordering (first for last, etc) and component ordering.
829 : *
830 : * @since 3.10
831 : */
832 1 : void OGRCurveCollection::reversePoints()
833 :
834 : {
835 2 : for (int i = 0; i < nCurveCount / 2; ++i)
836 : {
837 1 : std::swap(papoCurves[i], papoCurves[nCurveCount - 1 - i]);
838 : }
839 3 : for (int i = 0; i < nCurveCount; ++i)
840 : {
841 2 : papoCurves[i]->reversePoints();
842 : }
843 1 : }
844 :
845 : //! @endcond
|