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 : * 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 <cstddef>
33 : #include <cstring>
34 : #include <new>
35 :
36 : #include "ogr_core.h"
37 : #include "ogr_p.h"
38 : #include "ogr_spatialref.h"
39 : #include "cpl_conv.h"
40 : #include "cpl_error.h"
41 : #include "cpl_string.h"
42 : #include "cpl_vsi.h"
43 :
44 : //! @cond Doxygen_Suppress
45 :
46 : /************************************************************************/
47 : /* OGRCurveCollection() */
48 : /************************************************************************/
49 :
50 : OGRCurveCollection::OGRCurveCollection() = default;
51 :
52 : /************************************************************************/
53 : /* OGRCurveCollection( const OGRCurveCollection& ) */
54 : /************************************************************************/
55 :
56 : /**
57 : * \brief Copy constructor.
58 : *
59 : * Note: before GDAL 2.1, only the default implementation of the constructor
60 : * existed, which could be unsafe to use.
61 : *
62 : * @since GDAL 2.1
63 : */
64 :
65 106031 : OGRCurveCollection::OGRCurveCollection(const OGRCurveCollection &other)
66 : {
67 106031 : if (other.nCurveCount > 0)
68 : {
69 105730 : nCurveCount = other.nCurveCount;
70 105730 : papoCurves = static_cast<OGRCurve **>(
71 105730 : VSI_CALLOC_VERBOSE(sizeof(void *), nCurveCount));
72 :
73 105730 : if (papoCurves)
74 : {
75 212418 : for (int i = 0; i < nCurveCount; i++)
76 : {
77 106688 : papoCurves[i] = other.papoCurves[i]->clone();
78 : }
79 : }
80 : }
81 106031 : }
82 :
83 : /************************************************************************/
84 : /* ~OGRCurveCollection() */
85 : /************************************************************************/
86 :
87 561172 : OGRCurveCollection::~OGRCurveCollection()
88 :
89 : {
90 280590 : empty(nullptr);
91 280582 : }
92 :
93 : /************************************************************************/
94 : /* operator=( const OGRCurveCollection& ) */
95 : /************************************************************************/
96 :
97 : /**
98 : * \brief Assignment operator.
99 : *
100 : * Note: before GDAL 2.1, only the default implementation of the operator
101 : * existed, which could be unsafe to use.
102 : *
103 : * @since GDAL 2.1
104 : */
105 :
106 : OGRCurveCollection &
107 16 : OGRCurveCollection::operator=(const OGRCurveCollection &other)
108 : {
109 16 : if (this != &other)
110 : {
111 16 : empty(nullptr);
112 :
113 16 : if (other.nCurveCount > 0)
114 : {
115 8 : nCurveCount = other.nCurveCount;
116 8 : papoCurves = static_cast<OGRCurve **>(
117 8 : VSI_MALLOC2_VERBOSE(sizeof(void *), nCurveCount));
118 :
119 8 : if (papoCurves)
120 : {
121 22 : for (int i = 0; i < nCurveCount; i++)
122 : {
123 14 : papoCurves[i] = other.papoCurves[i]->clone();
124 : }
125 : }
126 : }
127 : }
128 16 : return *this;
129 : }
130 :
131 : /************************************************************************/
132 : /* WkbSize() */
133 : /************************************************************************/
134 :
135 938 : size_t OGRCurveCollection::WkbSize() const
136 : {
137 938 : size_t nSize = 9;
138 :
139 1890 : for (auto &&poSubGeom : *this)
140 : {
141 952 : nSize += poSubGeom->WkbSize();
142 : }
143 :
144 938 : return nSize;
145 : }
146 :
147 : /************************************************************************/
148 : /* addCurveDirectly() */
149 : /************************************************************************/
150 :
151 116828 : OGRErr OGRCurveCollection::addCurveDirectly(OGRGeometry *poGeom,
152 : OGRCurve *poCurve, int bNeedRealloc)
153 : {
154 116828 : poGeom->HomogenizeDimensionalityWith(poCurve);
155 :
156 116826 : if (bNeedRealloc)
157 : {
158 115083 : OGRCurve **papoNewCurves = static_cast<OGRCurve **>(VSI_REALLOC_VERBOSE(
159 : papoCurves, sizeof(OGRCurve *) * (nCurveCount + 1)));
160 115083 : if (papoNewCurves == nullptr)
161 0 : return OGRERR_FAILURE;
162 115083 : papoCurves = papoNewCurves;
163 : }
164 :
165 116826 : papoCurves[nCurveCount] = poCurve;
166 :
167 116826 : nCurveCount++;
168 :
169 116826 : return OGRERR_NONE;
170 : }
171 :
172 : /************************************************************************/
173 : /* importPreambleFromWkb() */
174 : /************************************************************************/
175 :
176 42345 : OGRErr OGRCurveCollection::importPreambleFromWkb(
177 : OGRGeometry *poGeom, const unsigned char *pabyData, size_t &nSize,
178 : size_t &nDataOffset, OGRwkbByteOrder &eByteOrder, size_t nMinSubGeomSize,
179 : OGRwkbVariant eWkbVariant)
180 : {
181 42345 : int nCurveCountNew = 0;
182 :
183 42345 : OGRErr eErr = poGeom->importPreambleOfCollectionFromWkb(
184 : pabyData, nSize, nDataOffset, eByteOrder, nMinSubGeomSize,
185 : nCurveCountNew, eWkbVariant);
186 42345 : if (eErr != OGRERR_NONE)
187 391 : return eErr;
188 :
189 41954 : CPLAssert(nCurveCount == 0);
190 41954 : nCurveCount = nCurveCountNew;
191 :
192 : // coverity[tainted_data]
193 41954 : papoCurves = static_cast<OGRCurve **>(
194 41954 : VSI_CALLOC_VERBOSE(sizeof(void *), nCurveCount));
195 41954 : if (nCurveCount != 0 && papoCurves == nullptr)
196 : {
197 0 : nCurveCount = 0;
198 0 : return OGRERR_NOT_ENOUGH_MEMORY;
199 : }
200 :
201 41954 : return OGRERR_NONE;
202 : }
203 :
204 : /************************************************************************/
205 : /* importBodyFromWkb() */
206 : /************************************************************************/
207 :
208 1922 : OGRErr OGRCurveCollection::importBodyFromWkb(
209 : OGRGeometry *poGeom, const unsigned char *pabyData, size_t nSize,
210 : bool bAcceptCompoundCurve,
211 : OGRErr (*pfnAddCurveDirectlyFromWkb)(OGRGeometry *poGeom,
212 : OGRCurve *poCurve),
213 : OGRwkbVariant eWkbVariant, size_t &nBytesConsumedOut)
214 : {
215 1922 : nBytesConsumedOut = 0;
216 : /* -------------------------------------------------------------------- */
217 : /* Get the Geoms. */
218 : /* -------------------------------------------------------------------- */
219 1922 : const int nIter = nCurveCount;
220 1922 : nCurveCount = 0;
221 1922 : size_t nDataOffset = 0;
222 3665 : for (int iGeom = 0; iGeom < nIter; iGeom++)
223 : {
224 1923 : OGRGeometry *poSubGeom = nullptr;
225 :
226 : // Parses sub-geometry.
227 1923 : const unsigned char *pabySubData = pabyData + nDataOffset;
228 1923 : if (nSize < 9 && nSize != static_cast<size_t>(-1))
229 180 : return OGRERR_NOT_ENOUGH_DATA;
230 :
231 1921 : OGRwkbGeometryType eFlattenSubGeomType = wkbUnknown;
232 1921 : if (OGRReadWKBGeometryType(pabySubData, eWkbVariant,
233 1921 : &eFlattenSubGeomType) != OGRERR_NONE)
234 63 : return OGRERR_FAILURE;
235 1858 : eFlattenSubGeomType = wkbFlatten(eFlattenSubGeomType);
236 :
237 1858 : OGRErr eErr = OGRERR_NONE;
238 1858 : size_t nSubGeomBytesConsumedOut = 0;
239 5570 : if ((eFlattenSubGeomType != wkbCompoundCurve &&
240 1861 : OGR_GT_IsCurve(eFlattenSubGeomType)) ||
241 3 : (bAcceptCompoundCurve && eFlattenSubGeomType == wkbCompoundCurve))
242 : {
243 1856 : eErr = OGRGeometryFactory::createFromWkb(
244 : pabySubData, nullptr, &poSubGeom, nSize, eWkbVariant,
245 : nSubGeomBytesConsumedOut);
246 : }
247 : else
248 : {
249 2 : CPLDebug(
250 : "OGR",
251 : "Cannot add geometry of type (%d) to geometry of type (%d)",
252 2 : eFlattenSubGeomType, poGeom->getGeometryType());
253 2 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
254 : }
255 :
256 1856 : if (eErr == OGRERR_NONE)
257 : {
258 1745 : CPLAssert(nSubGeomBytesConsumedOut > 0);
259 1745 : if (nSize != static_cast<size_t>(-1))
260 : {
261 1745 : CPLAssert(nSize >= nSubGeomBytesConsumedOut);
262 1745 : nSize -= nSubGeomBytesConsumedOut;
263 : }
264 :
265 1745 : nDataOffset += nSubGeomBytesConsumedOut;
266 :
267 1745 : OGRCurve *poCurve = poSubGeom->toCurve();
268 1745 : eErr = pfnAddCurveDirectlyFromWkb(poGeom, poCurve);
269 : }
270 1856 : if (eErr != OGRERR_NONE)
271 : {
272 113 : delete poSubGeom;
273 113 : return eErr;
274 : }
275 : }
276 1742 : nBytesConsumedOut = nDataOffset;
277 :
278 1742 : return OGRERR_NONE;
279 : }
280 :
281 : /************************************************************************/
282 : /* exportToWkt() */
283 : /************************************************************************/
284 :
285 213 : std::string OGRCurveCollection::exportToWkt(const OGRGeometry *baseGeom,
286 : const OGRWktOptions &opts,
287 : OGRErr *err) const
288 : {
289 : try
290 : {
291 213 : bool first = true;
292 426 : std::string wkt(baseGeom->getGeometryName());
293 :
294 213 : OGRWktOptions optsModified(opts);
295 213 : optsModified.variant = wkbVariantIso;
296 213 : wkt += baseGeom->wktTypeString(optsModified.variant);
297 :
298 472 : for (int i = 0; i < nCurveCount; ++i)
299 : {
300 259 : OGRGeometry *geom = papoCurves[i];
301 :
302 259 : OGRErr subgeomErr = OGRERR_NONE;
303 259 : std::string tempWkt = geom->exportToWkt(optsModified, &subgeomErr);
304 259 : if (subgeomErr != OGRERR_NONE)
305 : {
306 0 : if (err)
307 0 : *err = subgeomErr;
308 0 : return std::string();
309 : }
310 :
311 : // A curve collection has a list of linestrings (OGRCompoundCurve),
312 : // which should have their leader removed, or a OGRCurvePolygon,
313 : // which has leaders for each of its sub-geometries that aren't
314 : // linestrings.
315 259 : if (tempWkt.compare(0, strlen("LINESTRING"), "LINESTRING") == 0)
316 : {
317 123 : auto pos = tempWkt.find('(');
318 123 : if (pos != std::string::npos)
319 123 : tempWkt = tempWkt.substr(pos);
320 : }
321 :
322 259 : if (tempWkt.find("EMPTY") != std::string::npos)
323 0 : continue;
324 :
325 259 : if (first)
326 186 : wkt += '(';
327 : else
328 73 : wkt += ',';
329 259 : first = false;
330 259 : wkt += tempWkt;
331 : }
332 :
333 213 : if (err)
334 212 : *err = OGRERR_NONE;
335 213 : if (first)
336 27 : wkt += "EMPTY";
337 : else
338 186 : wkt += ')';
339 213 : return wkt;
340 : }
341 0 : catch (const std::bad_alloc &e)
342 : {
343 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
344 0 : if (err)
345 0 : *err = OGRERR_FAILURE;
346 0 : return std::string();
347 : }
348 : }
349 :
350 : /************************************************************************/
351 : /* exportToWkb() */
352 : /************************************************************************/
353 :
354 : OGRErr
355 911 : OGRCurveCollection::exportToWkb(const OGRGeometry *poGeom,
356 : unsigned char *pabyData,
357 : const OGRwkbExportOptions *psOptions) const
358 : {
359 911 : if (psOptions == nullptr)
360 : {
361 : static const OGRwkbExportOptions defaultOptions;
362 0 : psOptions = &defaultOptions;
363 : }
364 :
365 : /* -------------------------------------------------------------------- */
366 : /* Set the byte order. */
367 : /* -------------------------------------------------------------------- */
368 911 : pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER(
369 : static_cast<unsigned char>(psOptions->eByteOrder));
370 :
371 : /* -------------------------------------------------------------------- */
372 : /* Set the geometry feature type, ensuring that 3D flag is */
373 : /* preserved. */
374 : /* -------------------------------------------------------------------- */
375 911 : GUInt32 nGType = poGeom->getIsoGeometryType();
376 911 : if (psOptions->eWkbVariant == wkbVariantPostGIS1)
377 : {
378 0 : const bool bIs3D = wkbHasZ(static_cast<OGRwkbGeometryType>(nGType));
379 0 : nGType = wkbFlatten(nGType);
380 0 : if (nGType == wkbCurvePolygon)
381 0 : nGType = POSTGIS15_CURVEPOLYGON;
382 0 : if (bIs3D)
383 : // Explicitly set wkb25DBit.
384 0 : nGType =
385 0 : static_cast<OGRwkbGeometryType>(nGType | wkb25DBitInternalUse);
386 : }
387 :
388 911 : if (OGR_SWAP(psOptions->eByteOrder))
389 : {
390 0 : nGType = CPL_SWAP32(nGType);
391 : }
392 :
393 911 : memcpy(pabyData + 1, &nGType, 4);
394 :
395 : /* -------------------------------------------------------------------- */
396 : /* Copy in the raw data. */
397 : /* -------------------------------------------------------------------- */
398 911 : if (OGR_SWAP(psOptions->eByteOrder))
399 : {
400 0 : const int nCount = CPL_SWAP32(nCurveCount);
401 0 : memcpy(pabyData + 5, &nCount, 4);
402 : }
403 : else
404 : {
405 911 : memcpy(pabyData + 5, &nCurveCount, 4);
406 : }
407 :
408 : // TODO(schwehr): Where do these 9 values come from?
409 911 : size_t nOffset = 9;
410 :
411 : /* ==================================================================== */
412 : /* Serialize each of the Geoms. */
413 : /* ==================================================================== */
414 1821 : for (auto &&poSubGeom : *this)
415 : {
416 910 : poSubGeom->exportToWkb(pabyData + nOffset, psOptions);
417 :
418 910 : nOffset += poSubGeom->WkbSize();
419 : }
420 :
421 911 : return OGRERR_NONE;
422 : }
423 :
424 : /************************************************************************/
425 : /* empty() */
426 : /************************************************************************/
427 :
428 341251 : void OGRCurveCollection::empty(OGRGeometry *poGeom)
429 : {
430 341251 : if (papoCurves != nullptr)
431 : {
432 557676 : for (auto &&poSubGeom : *this)
433 : {
434 280438 : delete poSubGeom;
435 : }
436 277236 : CPLFree(papoCurves);
437 : }
438 :
439 341250 : nCurveCount = 0;
440 341250 : papoCurves = nullptr;
441 341250 : if (poGeom)
442 60659 : poGeom->setCoordinateDimension(2);
443 341250 : }
444 :
445 : /************************************************************************/
446 : /* getEnvelope() */
447 : /************************************************************************/
448 :
449 187189 : void OGRCurveCollection::getEnvelope(OGREnvelope *psEnvelope) const
450 : {
451 187189 : OGREnvelope3D oEnv3D;
452 187189 : getEnvelope(&oEnv3D);
453 187189 : psEnvelope->MinX = oEnv3D.MinX;
454 187189 : psEnvelope->MinY = oEnv3D.MinY;
455 187189 : psEnvelope->MaxX = oEnv3D.MaxX;
456 187189 : psEnvelope->MaxY = oEnv3D.MaxY;
457 187189 : }
458 :
459 : /************************************************************************/
460 : /* getEnvelope() */
461 : /************************************************************************/
462 :
463 195109 : void OGRCurveCollection::getEnvelope(OGREnvelope3D *psEnvelope) const
464 : {
465 195109 : OGREnvelope3D oGeomEnv;
466 195109 : bool bExtentSet = false;
467 :
468 195109 : *psEnvelope = OGREnvelope3D();
469 391139 : for (int iGeom = 0; iGeom < nCurveCount; iGeom++)
470 : {
471 196030 : if (!papoCurves[iGeom]->IsEmpty())
472 : {
473 196030 : bExtentSet = true;
474 196030 : papoCurves[iGeom]->getEnvelope(&oGeomEnv);
475 196030 : psEnvelope->Merge(oGeomEnv);
476 : }
477 : }
478 :
479 195109 : if (!bExtentSet)
480 : {
481 : // To be backward compatible when called on empty geom
482 7 : psEnvelope->MinX = 0.0;
483 7 : psEnvelope->MinY = 0.0;
484 7 : psEnvelope->MinZ = 0.0;
485 7 : psEnvelope->MaxX = 0.0;
486 7 : psEnvelope->MaxY = 0.0;
487 7 : psEnvelope->MaxZ = 0.0;
488 : }
489 195109 : }
490 :
491 : /************************************************************************/
492 : /* IsEmpty() */
493 : /************************************************************************/
494 :
495 110758 : OGRBoolean OGRCurveCollection::IsEmpty() const
496 : {
497 110783 : for (auto &&poSubGeom : *this)
498 : {
499 110276 : if (!poSubGeom->IsEmpty())
500 110251 : return FALSE;
501 : }
502 507 : return TRUE;
503 : }
504 :
505 : /************************************************************************/
506 : /* Equals() */
507 : /************************************************************************/
508 :
509 42223 : OGRBoolean OGRCurveCollection::Equals(const OGRCurveCollection *poOCC) const
510 : {
511 42223 : if (getNumCurves() != poOCC->getNumCurves())
512 2 : return FALSE;
513 :
514 : // Should eventually test the SRS.
515 :
516 70506 : for (int iGeom = 0; iGeom < nCurveCount; iGeom++)
517 : {
518 42420 : if (!getCurve(iGeom)->Equals(poOCC->getCurve(iGeom)))
519 14135 : return FALSE;
520 : }
521 :
522 28086 : return TRUE;
523 : }
524 :
525 : /************************************************************************/
526 : /* setCoordinateDimension() */
527 : /************************************************************************/
528 :
529 61521 : void OGRCurveCollection::setCoordinateDimension(OGRGeometry *poGeom,
530 : int nNewDimension)
531 : {
532 62413 : for (auto &&poSubGeom : *this)
533 : {
534 892 : poSubGeom->setCoordinateDimension(nNewDimension);
535 : }
536 :
537 61521 : poGeom->OGRGeometry::setCoordinateDimension(nNewDimension);
538 61520 : }
539 :
540 80874 : void OGRCurveCollection::set3D(OGRGeometry *poGeom, OGRBoolean bIs3D)
541 : {
542 84746 : for (auto &&poSubGeom : *this)
543 : {
544 3872 : poSubGeom->set3D(bIs3D);
545 : }
546 :
547 80874 : poGeom->OGRGeometry::set3D(bIs3D);
548 80874 : }
549 :
550 130225 : void OGRCurveCollection::setMeasured(OGRGeometry *poGeom,
551 : OGRBoolean bIsMeasured)
552 : {
553 134087 : for (auto &&poSubGeom : *this)
554 : {
555 3862 : poSubGeom->setMeasured(bIsMeasured);
556 : }
557 :
558 130225 : poGeom->OGRGeometry::setMeasured(bIsMeasured);
559 130226 : }
560 :
561 : /************************************************************************/
562 : /* assignSpatialReference() */
563 : /************************************************************************/
564 :
565 151361 : void OGRCurveCollection::assignSpatialReference(OGRGeometry *poGeom,
566 : const OGRSpatialReference *poSR)
567 : {
568 304779 : for (auto &&poSubGeom : *this)
569 : {
570 153419 : poSubGeom->assignSpatialReference(poSR);
571 : }
572 151363 : poGeom->OGRGeometry::assignSpatialReference(poSR);
573 151363 : }
574 :
575 : /************************************************************************/
576 : /* getNumCurves() */
577 : /************************************************************************/
578 :
579 84446 : int OGRCurveCollection::getNumCurves() const
580 : {
581 84446 : return nCurveCount;
582 : }
583 :
584 : /************************************************************************/
585 : /* getCurve() */
586 : /************************************************************************/
587 :
588 8655 : OGRCurve *OGRCurveCollection::getCurve(int i)
589 : {
590 8655 : if (i < 0 || i >= nCurveCount)
591 111 : return nullptr;
592 8544 : return papoCurves[i];
593 : }
594 :
595 : /************************************************************************/
596 : /* getCurve() */
597 : /************************************************************************/
598 :
599 92769 : const OGRCurve *OGRCurveCollection::getCurve(int i) const
600 : {
601 92769 : if (i < 0 || i >= nCurveCount)
602 3 : return nullptr;
603 92766 : return papoCurves[i];
604 : }
605 :
606 : /************************************************************************/
607 : /* stealCurve() */
608 : /************************************************************************/
609 :
610 5 : OGRCurve *OGRCurveCollection::stealCurve(int i)
611 : {
612 5 : if (i < 0 || i >= nCurveCount)
613 0 : return nullptr;
614 5 : OGRCurve *poRet = papoCurves[i];
615 5 : if (i < nCurveCount - 1)
616 : {
617 2 : memmove(papoCurves + i, papoCurves + i + 1,
618 2 : (nCurveCount - i - 1) * sizeof(OGRCurve *));
619 : }
620 5 : nCurveCount--;
621 5 : return poRet;
622 : }
623 :
624 : /************************************************************************/
625 : /* transform() */
626 : /************************************************************************/
627 :
628 507 : OGRErr OGRCurveCollection::transform(OGRGeometry *poGeom,
629 : OGRCoordinateTransformation *poCT)
630 : {
631 1113 : for (int iGeom = 0; iGeom < nCurveCount; iGeom++)
632 : {
633 606 : const OGRErr eErr = papoCurves[iGeom]->transform(poCT);
634 606 : if (eErr != OGRERR_NONE)
635 : {
636 0 : if (iGeom != 0)
637 : {
638 0 : CPLDebug("OGR", "OGRCurveCollection::transform() failed for a "
639 : "geometry other than the first, meaning some "
640 : "geometries are transformed and some are not!");
641 :
642 0 : return OGRERR_FAILURE;
643 : }
644 :
645 0 : return eErr;
646 : }
647 : }
648 :
649 507 : poGeom->assignSpatialReference(poCT->GetTargetCS());
650 :
651 507 : return OGRERR_NONE;
652 : }
653 :
654 : /************************************************************************/
655 : /* flattenTo2D() */
656 : /************************************************************************/
657 :
658 755 : void OGRCurveCollection::flattenTo2D(OGRGeometry *poGeom)
659 : {
660 1576 : for (auto &&poSubGeom : *this)
661 : {
662 821 : poSubGeom->flattenTo2D();
663 : }
664 :
665 755 : poGeom->setCoordinateDimension(2);
666 755 : }
667 :
668 : /************************************************************************/
669 : /* segmentize() */
670 : /************************************************************************/
671 :
672 37 : void OGRCurveCollection::segmentize(double dfMaxLength)
673 : {
674 74 : for (auto &&poSubGeom : *this)
675 : {
676 37 : poSubGeom->segmentize(dfMaxLength);
677 : }
678 37 : }
679 :
680 : /************************************************************************/
681 : /* swapXY() */
682 : /************************************************************************/
683 :
684 75 : void OGRCurveCollection::swapXY()
685 : {
686 150 : for (auto &&poSubGeom : *this)
687 : {
688 75 : poSubGeom->swapXY();
689 : }
690 75 : }
691 :
692 : /************************************************************************/
693 : /* hasCurveGeometry() */
694 : /************************************************************************/
695 :
696 94 : OGRBoolean OGRCurveCollection::hasCurveGeometry(int bLookForNonLinear) const
697 : {
698 133 : for (auto &&poSubGeom : *this)
699 : {
700 105 : if (poSubGeom->hasCurveGeometry(bLookForNonLinear))
701 66 : return TRUE;
702 : }
703 28 : return FALSE;
704 : }
705 :
706 : /************************************************************************/
707 : /* removeCurve() */
708 : /************************************************************************/
709 :
710 : /**
711 : * \brief Remove a geometry from the container.
712 : *
713 : * Removing a geometry will cause the geometry count to drop by one, and all
714 : * "higher" geometries will shuffle down one in index.
715 : *
716 : * @param iIndex the index of the geometry to delete. A value of -1 is a
717 : * special flag meaning that all geometries should be removed.
718 : *
719 : * @param bDelete if true the geometry will be deallocated, otherwise it will
720 : * not. The default is true as the container is considered to own the
721 : * geometries in it.
722 : *
723 : * @return OGRERR_NONE if successful, or OGRERR_FAILURE if the index is
724 : * out of range.
725 : */
726 :
727 18 : OGRErr OGRCurveCollection::removeCurve(int iIndex, bool bDelete)
728 :
729 : {
730 18 : if (iIndex < -1 || iIndex >= nCurveCount)
731 2 : return OGRERR_FAILURE;
732 :
733 : // Special case.
734 16 : if (iIndex == -1)
735 : {
736 3 : while (nCurveCount > 0)
737 2 : removeCurve(nCurveCount - 1, bDelete);
738 1 : return OGRERR_NONE;
739 : }
740 :
741 15 : if (bDelete)
742 11 : delete papoCurves[iIndex];
743 :
744 15 : memmove(papoCurves + iIndex, papoCurves + iIndex + 1,
745 15 : sizeof(void *) * (nCurveCount - iIndex - 1));
746 :
747 15 : nCurveCount--;
748 :
749 15 : return OGRERR_NONE;
750 : }
751 :
752 : //! @endcond
|