Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: The OGRSimpleCurve and OGRLineString geometry classes.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Frank Warmerdam
9 : * Copyright (c) 2008-2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "ogr_geometry.h"
15 : #include "ogr_geos.h"
16 : #include "ogr_p.h"
17 :
18 : #include "geodesic.h" // from PROJ
19 :
20 : #include <cmath>
21 : #include <cstdlib>
22 : #include <algorithm>
23 : #include <limits>
24 : #include <new>
25 :
26 : namespace
27 : {
28 :
29 567 : int DoubleToIntClamp(double dfValue)
30 : {
31 567 : if (std::isnan(dfValue))
32 0 : return 0;
33 567 : if (dfValue >= std::numeric_limits<int>::max())
34 1 : return std::numeric_limits<int>::max();
35 566 : if (dfValue <= std::numeric_limits<int>::min())
36 0 : return std::numeric_limits<int>::min();
37 566 : return static_cast<int>(dfValue);
38 : }
39 :
40 : } // namespace
41 :
42 : /************************************************************************/
43 : /* OGRSimpleCurve( const OGRSimpleCurve& ) */
44 : /************************************************************************/
45 :
46 : /**
47 : * \brief Copy constructor.
48 : *
49 : * Note: before GDAL 2.1, only the default implementation of the constructor
50 : * existed, which could be unsafe to use.
51 : *
52 : * @since GDAL 2.1
53 : */
54 :
55 301281 : OGRSimpleCurve::OGRSimpleCurve(const OGRSimpleCurve &other)
56 : : OGRCurve(other), nPointCount(0), paoPoints(nullptr), padfZ(nullptr),
57 301281 : padfM(nullptr)
58 : {
59 301281 : if (other.nPointCount > 0)
60 301072 : setPoints(other.nPointCount, other.paoPoints, other.padfZ, other.padfM);
61 301281 : }
62 :
63 : /************************************************************************/
64 : /* OGRSimpleCurve( OGRSimpleCurve&& ) */
65 : /************************************************************************/
66 :
67 : /**
68 : * \brief Move constructor.
69 : *
70 : * @since GDAL 3.11
71 : */
72 :
73 : // cppcheck-suppress-begin accessMoved
74 3 : OGRSimpleCurve::OGRSimpleCurve(OGRSimpleCurve &&other)
75 6 : : OGRCurve(std::move(other)), nPointCount(other.nPointCount),
76 3 : m_nPointCapacity(other.m_nPointCapacity), paoPoints(other.paoPoints),
77 3 : padfZ(other.padfZ), padfM(other.padfM)
78 : {
79 3 : other.nPointCount = 0;
80 3 : other.m_nPointCapacity = 0;
81 3 : other.paoPoints = nullptr;
82 3 : other.padfZ = nullptr;
83 3 : other.padfM = nullptr;
84 3 : }
85 :
86 : // cppcheck-suppress-end accessMoved
87 :
88 : /************************************************************************/
89 : /* ~OGRSimpleCurve() */
90 : /************************************************************************/
91 :
92 3769750 : OGRSimpleCurve::~OGRSimpleCurve()
93 :
94 : {
95 3769760 : CPLFree(paoPoints);
96 3769760 : CPLFree(padfZ);
97 3769750 : CPLFree(padfM);
98 3769750 : }
99 :
100 : /************************************************************************/
101 : /* operator=(const OGRSimpleCurve &other) */
102 : /************************************************************************/
103 :
104 : /**
105 : * \brief Assignment operator.
106 : *
107 : * Note: before GDAL 2.1, only the default implementation of the operator
108 : * existed, which could be unsafe to use.
109 : *
110 : * @since GDAL 2.1
111 : */
112 :
113 12 : OGRSimpleCurve &OGRSimpleCurve::operator=(const OGRSimpleCurve &other)
114 : {
115 12 : if (this == &other)
116 0 : return *this;
117 :
118 12 : OGRCurve::operator=(other);
119 :
120 12 : setPoints(other.nPointCount, other.paoPoints, other.padfZ, other.padfM);
121 12 : flags = other.flags;
122 :
123 12 : return *this;
124 : }
125 :
126 : /************************************************************************/
127 : /* operator=(OGRSimpleCurve &&other) */
128 : /************************************************************************/
129 :
130 : /**
131 : * \brief Move assignment operator.
132 : *
133 : * @since GDAL 3.11
134 : */
135 :
136 6 : OGRSimpleCurve &OGRSimpleCurve::operator=(OGRSimpleCurve &&other)
137 : {
138 6 : if (this != &other)
139 : {
140 : // cppcheck-suppress-begin accessMoved
141 6 : OGRCurve::operator=(std::move(other));
142 :
143 6 : nPointCount = other.nPointCount;
144 6 : m_nPointCapacity = other.m_nPointCapacity;
145 6 : CPLFree(paoPoints);
146 6 : paoPoints = other.paoPoints;
147 6 : CPLFree(padfZ);
148 6 : padfZ = other.padfZ;
149 6 : CPLFree(padfM);
150 6 : padfM = other.padfM;
151 6 : flags = other.flags;
152 6 : other.nPointCount = 0;
153 6 : other.m_nPointCapacity = 0;
154 6 : other.paoPoints = nullptr;
155 6 : other.padfZ = nullptr;
156 6 : other.padfM = nullptr;
157 : // cppcheck-suppress-end accessMoved
158 : }
159 :
160 6 : return *this;
161 : }
162 :
163 : /************************************************************************/
164 : /* flattenTo2D() */
165 : /************************************************************************/
166 :
167 1065 : void OGRSimpleCurve::flattenTo2D()
168 :
169 : {
170 1065 : Make2D();
171 1065 : setMeasured(FALSE);
172 1065 : }
173 :
174 : /************************************************************************/
175 : /* empty() */
176 : /************************************************************************/
177 :
178 14266 : void OGRSimpleCurve::empty()
179 :
180 : {
181 14266 : setNumPoints(0);
182 14265 : }
183 :
184 : /************************************************************************/
185 : /* setCoordinateDimension() */
186 : /************************************************************************/
187 :
188 2180 : bool OGRSimpleCurve::setCoordinateDimension(int nNewDimension)
189 :
190 : {
191 2180 : setMeasured(FALSE);
192 2180 : if (nNewDimension == 2)
193 1172 : Make2D();
194 1008 : else if (nNewDimension == 3)
195 1008 : return Make3D();
196 1172 : return true;
197 : }
198 :
199 119699 : bool OGRSimpleCurve::set3D(OGRBoolean bIs3D)
200 :
201 : {
202 119699 : if (bIs3D)
203 117233 : return Make3D();
204 : else
205 2466 : Make2D();
206 2466 : return true;
207 : }
208 :
209 119366 : bool OGRSimpleCurve::setMeasured(OGRBoolean bIsMeasured)
210 :
211 : {
212 119366 : if (bIsMeasured)
213 8192 : return AddM();
214 : else
215 111174 : RemoveM();
216 111174 : return true;
217 : }
218 :
219 : /************************************************************************/
220 : /* WkbSize() */
221 : /* */
222 : /* Return the size of this object in well known binary */
223 : /* representation including the byte order, and type information. */
224 : /************************************************************************/
225 :
226 14805 : size_t OGRSimpleCurve::WkbSize() const
227 :
228 : {
229 14805 : return 5 + 4 + 8 * static_cast<size_t>(nPointCount) * CoordinateDimension();
230 : }
231 :
232 : //! @cond Doxygen_Suppress
233 :
234 : /************************************************************************/
235 : /* Make2D() */
236 : /************************************************************************/
237 :
238 49287 : void OGRSimpleCurve::Make2D()
239 :
240 : {
241 49287 : if (padfZ != nullptr)
242 : {
243 1872 : CPLFree(padfZ);
244 1872 : padfZ = nullptr;
245 : }
246 49287 : flags &= ~OGR_G_3D;
247 49287 : }
248 :
249 : /************************************************************************/
250 : /* Make3D() */
251 : /************************************************************************/
252 :
253 2776440 : bool OGRSimpleCurve::Make3D()
254 :
255 : {
256 2776440 : if (padfZ == nullptr)
257 : {
258 2661660 : padfZ = static_cast<double *>(
259 2661660 : VSI_CALLOC_VERBOSE(sizeof(double), std::max(1, m_nPointCapacity)));
260 2661660 : if (padfZ == nullptr)
261 : {
262 0 : flags &= ~OGR_G_3D;
263 0 : CPLError(CE_Failure, CPLE_AppDefined,
264 : "OGRSimpleCurve::Make3D() failed");
265 0 : return false;
266 : }
267 : }
268 2776440 : flags |= OGR_G_3D;
269 2776440 : return true;
270 : }
271 :
272 : /************************************************************************/
273 : /* RemoveM() */
274 : /************************************************************************/
275 :
276 125590 : void OGRSimpleCurve::RemoveM()
277 :
278 : {
279 125590 : if (padfM != nullptr)
280 : {
281 521 : CPLFree(padfM);
282 521 : padfM = nullptr;
283 : }
284 125590 : flags &= ~OGR_G_MEASURED;
285 125590 : }
286 :
287 : /************************************************************************/
288 : /* AddM() */
289 : /************************************************************************/
290 :
291 39218 : bool OGRSimpleCurve::AddM()
292 :
293 : {
294 39218 : if (padfM == nullptr)
295 : {
296 34705 : padfM = static_cast<double *>(
297 34705 : VSI_CALLOC_VERBOSE(sizeof(double), std::max(1, m_nPointCapacity)));
298 34705 : if (padfM == nullptr)
299 : {
300 0 : flags &= ~OGR_G_MEASURED;
301 0 : CPLError(CE_Failure, CPLE_AppDefined,
302 : "OGRSimpleCurve::AddM() failed");
303 0 : return false;
304 : }
305 : }
306 39218 : flags |= OGR_G_MEASURED;
307 39218 : return true;
308 : }
309 :
310 : //! @endcond
311 :
312 : /************************************************************************/
313 : /* getPoint() */
314 : /************************************************************************/
315 :
316 : /**
317 : * \brief Fetch a point in line string.
318 : *
319 : * This method relates to the SFCOM ILineString::get_Point() method.
320 : *
321 : * @param i the vertex to fetch, from 0 to getNumPoints()-1.
322 : * @param poPoint a point to initialize with the fetched point.
323 : */
324 :
325 1156340 : void OGRSimpleCurve::getPoint(int i, OGRPoint *poPoint) const
326 :
327 : {
328 1156340 : CPLAssert(i >= 0);
329 1156340 : CPLAssert(i < nPointCount);
330 1156340 : CPLAssert(poPoint != nullptr);
331 :
332 1156340 : poPoint->setX(paoPoints[i].x);
333 1156340 : poPoint->setY(paoPoints[i].y);
334 :
335 1156340 : if ((flags & OGR_G_3D) && padfZ != nullptr)
336 46025 : poPoint->setZ(padfZ[i]);
337 1156340 : if ((flags & OGR_G_MEASURED) && padfM != nullptr)
338 28415 : poPoint->setM(padfM[i]);
339 1156340 : }
340 :
341 : /**
342 : * \fn int OGRSimpleCurve::getNumPoints() const;
343 : *
344 : * \brief Fetch vertex count.
345 : *
346 : * Returns the number of vertices in the line string.
347 : *
348 : * @return vertex count.
349 : */
350 :
351 : /**
352 : * \fn double OGRSimpleCurve::getX( int iVertex ) const;
353 : *
354 : * \brief Get X at vertex.
355 : *
356 : * Returns the X value at the indicated vertex. If iVertex is out of range a
357 : * crash may occur, no internal range checking is performed.
358 : *
359 : * @param iVertex the vertex to return, between 0 and getNumPoints()-1.
360 : *
361 : * @return X value.
362 : */
363 :
364 : /**
365 : * \fn double OGRSimpleCurve::getY( int iVertex ) const;
366 : *
367 : * \brief Get Y at vertex.
368 : *
369 : * Returns the Y value at the indicated vertex. If iVertex is out of range a
370 : * crash may occur, no internal range checking is performed.
371 : *
372 : * @param iVertex the vertex to return, between 0 and getNumPoints()-1.
373 : *
374 : * @return X value.
375 : */
376 :
377 : /************************************************************************/
378 : /* getZ() */
379 : /************************************************************************/
380 :
381 : /**
382 : * \brief Get Z at vertex.
383 : *
384 : * Returns the Z (elevation) value at the indicated vertex. If no Z
385 : * value is available, 0.0 is returned. If iVertex is out of range a
386 : * crash may occur, no internal range checking is performed.
387 : *
388 : * @param iVertex the vertex to return, between 0 and getNumPoints()-1.
389 : *
390 : * @return Z value.
391 : */
392 :
393 692303 : double OGRSimpleCurve::getZ(int iVertex) const
394 :
395 : {
396 692303 : if (padfZ != nullptr && iVertex >= 0 && iVertex < nPointCount &&
397 253422 : (flags & OGR_G_3D))
398 253422 : return (padfZ[iVertex]);
399 : else
400 438881 : return 0.0;
401 : }
402 :
403 : /************************************************************************/
404 : /* getM() */
405 : /************************************************************************/
406 :
407 : /**
408 : * \brief Get measure at vertex.
409 : *
410 : * Returns the M (measure) value at the indicated vertex. If no M
411 : * value is available, 0.0 is returned.
412 : *
413 : * @param iVertex the vertex to return, between 0 and getNumPoints()-1.
414 : *
415 : * @return M value.
416 : */
417 :
418 2660 : double OGRSimpleCurve::getM(int iVertex) const
419 :
420 : {
421 2660 : if (padfM != nullptr && iVertex >= 0 && iVertex < nPointCount &&
422 2660 : (flags & OGR_G_MEASURED))
423 2660 : return (padfM[iVertex]);
424 : else
425 0 : return 0.0;
426 : }
427 :
428 : /************************************************************************/
429 : /* setNumPoints() */
430 : /************************************************************************/
431 :
432 : /**
433 : * \brief Set number of points in geometry.
434 : *
435 : * This method primary exists to preset the number of points in a linestring
436 : * geometry before setPoint() is used to assign them to avoid reallocating
437 : * the array larger with each call to addPoint().
438 : *
439 : * This method has no SFCOM analog.
440 : *
441 : * @param nNewPointCount the new number of points for geometry.
442 : * @param bZeroizeNewContent whether to set to zero the new elements of arrays
443 : * that are extended.
444 : * @return (since 3.10) true in case of success, false in case of memory allocation error
445 : */
446 :
447 21579000 : bool OGRSimpleCurve::setNumPoints(int nNewPointCount, int bZeroizeNewContent)
448 :
449 : {
450 21579000 : CPLAssert(nNewPointCount >= 0);
451 :
452 21579000 : if (nNewPointCount > m_nPointCapacity)
453 : {
454 : // Overflow of sizeof(OGRRawPoint) * nNewPointCount can only occur on
455 : // 32 bit, but we don't really want to allocate 2 billion points even on
456 : // 64 bit...
457 8667390 : if (nNewPointCount > std::numeric_limits<int>::max() /
458 : static_cast<int>(sizeof(OGRRawPoint)))
459 : {
460 2 : CPLError(CE_Failure, CPLE_IllegalArg,
461 : "Too many points on line/curve (%d points exceeds the "
462 : "limit of %d points)",
463 : nNewPointCount,
464 8 : std::numeric_limits<int>::max() /
465 : static_cast<int>(sizeof(OGRRawPoint)));
466 2 : return false;
467 : }
468 :
469 : // If first allocation, just aim for nNewPointCount
470 : // Otherwise aim for nNewPointCount + nNewPointCount / 3 to have
471 : // exponential growth.
472 : const int nNewCapacity =
473 13573100 : (nPointCount == 0 ||
474 4905750 : nNewPointCount > std::numeric_limits<int>::max() /
475 4905750 : static_cast<int>(sizeof(OGRRawPoint)) -
476 4905750 : nNewPointCount / 3)
477 8667390 : ? nNewPointCount
478 4905750 : : nNewPointCount + nNewPointCount / 3;
479 :
480 8667390 : if (nPointCount == 0 && paoPoints)
481 : {
482 : // If there was an allocated array, but the old number of points is
483 : // 0, then free the arrays before allocating them, to avoid
484 : // potential costly recopy of useless data.
485 10 : VSIFree(paoPoints);
486 10 : paoPoints = nullptr;
487 10 : VSIFree(padfZ);
488 10 : padfZ = nullptr;
489 10 : VSIFree(padfM);
490 10 : padfM = nullptr;
491 10 : m_nPointCapacity = 0;
492 : }
493 :
494 : OGRRawPoint *paoNewPoints = static_cast<OGRRawPoint *>(
495 8667390 : VSI_REALLOC_VERBOSE(paoPoints, sizeof(OGRRawPoint) * nNewCapacity));
496 8667400 : if (paoNewPoints == nullptr)
497 : {
498 0 : return false;
499 : }
500 8667400 : paoPoints = paoNewPoints;
501 :
502 8667400 : if (flags & OGR_G_3D)
503 : {
504 : double *padfNewZ = static_cast<double *>(
505 3865280 : VSI_REALLOC_VERBOSE(padfZ, sizeof(double) * nNewCapacity));
506 3865280 : if (padfNewZ == nullptr)
507 : {
508 0 : return false;
509 : }
510 3865280 : padfZ = padfNewZ;
511 : }
512 :
513 8667400 : if (flags & OGR_G_MEASURED)
514 : {
515 : double *padfNewM = static_cast<double *>(
516 4522 : VSI_REALLOC_VERBOSE(padfM, sizeof(double) * nNewCapacity));
517 4522 : if (padfNewM == nullptr)
518 : {
519 0 : return false;
520 : }
521 4522 : padfM = padfNewM;
522 : }
523 :
524 8667400 : m_nPointCapacity = nNewCapacity;
525 : }
526 :
527 21579000 : if (nNewPointCount > nPointCount && bZeroizeNewContent)
528 : {
529 : // gcc 8.0 (dev) complains about -Wclass-memaccess since
530 : // OGRRawPoint() has a constructor. So use a void* pointer. Doing
531 : // the memset() here is correct since the constructor sets to 0. We
532 : // could instead use a std::fill(), but at every other place, we
533 : // treat this class as a regular POD (see above use of realloc())
534 19503400 : void *dest = static_cast<void *>(paoPoints + nPointCount);
535 19503400 : memset(dest, 0, sizeof(OGRRawPoint) * (nNewPointCount - nPointCount));
536 :
537 19503400 : if ((flags & OGR_G_3D) && padfZ)
538 5503410 : memset(padfZ + nPointCount, 0,
539 5503410 : sizeof(double) * (nNewPointCount - nPointCount));
540 :
541 19503400 : if ((flags & OGR_G_MEASURED) && padfM)
542 409 : memset(padfM + nPointCount, 0,
543 409 : sizeof(double) * (nNewPointCount - nPointCount));
544 : }
545 :
546 21579000 : nPointCount = nNewPointCount;
547 21579000 : return true;
548 : }
549 :
550 : /************************************************************************/
551 : /* setPoint() */
552 : /************************************************************************/
553 :
554 : /**
555 : * \brief Set the location of a vertex in line string.
556 : *
557 : * If iPoint is larger than the number of necessary the number of existing
558 : * points in the line string, the point count will be increased to
559 : * accommodate the request.
560 : *
561 : * There is no SFCOM analog to this method.
562 : *
563 : * @param iPoint the index of the vertex to assign (zero based).
564 : * @param poPoint the value to assign to the vertex.
565 : * @return (since 3.10) true in case of success, false in case of memory allocation error
566 : */
567 :
568 1605 : bool OGRSimpleCurve::setPoint(int iPoint, OGRPoint *poPoint)
569 :
570 : {
571 1605 : if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
572 59 : return setPoint(iPoint, poPoint->getX(), poPoint->getY(),
573 59 : poPoint->getZ(), poPoint->getM());
574 1546 : else if (flags & OGR_G_3D)
575 863 : return setPoint(iPoint, poPoint->getX(), poPoint->getY(),
576 863 : poPoint->getZ());
577 683 : else if (flags & OGR_G_MEASURED)
578 3 : return setPointM(iPoint, poPoint->getX(), poPoint->getY(),
579 3 : poPoint->getM());
580 : else
581 680 : return setPoint(iPoint, poPoint->getX(), poPoint->getY());
582 : }
583 :
584 : /************************************************************************/
585 : /* CheckPointCount() */
586 : /************************************************************************/
587 :
588 19484000 : static inline bool CheckPointCount(int iPoint)
589 : {
590 19484000 : if (iPoint == std::numeric_limits<int>::max())
591 : {
592 1 : CPLError(CE_Failure, CPLE_AppDefined, "Too big point count.");
593 1 : return false;
594 : }
595 19484000 : return true;
596 : }
597 :
598 : /************************************************************************/
599 : /* setPoint() */
600 : /************************************************************************/
601 :
602 : /**
603 : * \brief Set the location of a vertex in line string.
604 : *
605 : * If iPoint is larger than the number of necessary the number of existing
606 : * points in the line string, the point count will be increased to
607 : * accommodate the request.
608 : *
609 : * There is no SFCOM analog to this method.
610 : *
611 : * @param iPoint the index of the vertex to assign (zero based).
612 : * @param xIn input X coordinate to assign.
613 : * @param yIn input Y coordinate to assign.
614 : * @param zIn input Z coordinate to assign (defaults to zero).
615 : * @return (since 3.10) true in case of success, false in case of memory allocation error
616 : */
617 :
618 5562730 : bool OGRSimpleCurve::setPoint(int iPoint, double xIn, double yIn, double zIn)
619 :
620 : {
621 5562730 : if (!(flags & OGR_G_3D))
622 : {
623 1263480 : if (!Make3D())
624 0 : return false;
625 : }
626 :
627 5562730 : if (iPoint >= nPointCount)
628 : {
629 5503150 : if (!CheckPointCount(iPoint) || !setNumPoints(iPoint + 1))
630 1 : return false;
631 : }
632 : #ifdef DEBUG
633 5562730 : if (paoPoints == nullptr)
634 0 : return false;
635 : #endif
636 :
637 5562730 : paoPoints[iPoint].x = xIn;
638 5562730 : paoPoints[iPoint].y = yIn;
639 :
640 5562730 : if (padfZ != nullptr)
641 : {
642 5562730 : padfZ[iPoint] = zIn;
643 : }
644 5562730 : return true;
645 : }
646 :
647 : /**
648 : * \brief Set the location of a vertex in line string.
649 : *
650 : * If iPoint is larger than the number of necessary the number of existing
651 : * points in the line string, the point count will be increased to
652 : * accommodate the request.
653 : *
654 : * There is no SFCOM analog to this method.
655 : *
656 : * @param iPoint the index of the vertex to assign (zero based).
657 : * @param xIn input X coordinate to assign.
658 : * @param yIn input Y coordinate to assign.
659 : * @param mIn input M coordinate to assign (defaults to zero).
660 : * @return (since 3.10) true in case of success, false in case of memory allocation error
661 : */
662 :
663 443 : bool OGRSimpleCurve::setPointM(int iPoint, double xIn, double yIn, double mIn)
664 :
665 : {
666 443 : if (!(flags & OGR_G_MEASURED))
667 : {
668 108 : if (!AddM())
669 0 : return false;
670 : }
671 :
672 443 : if (iPoint >= nPointCount)
673 : {
674 6 : if (!CheckPointCount(iPoint) || !setNumPoints(iPoint + 1))
675 0 : return false;
676 : }
677 : #ifdef DEBUG
678 443 : if (paoPoints == nullptr)
679 0 : return false;
680 : #endif
681 :
682 443 : paoPoints[iPoint].x = xIn;
683 443 : paoPoints[iPoint].y = yIn;
684 :
685 443 : if (padfM != nullptr)
686 : {
687 443 : padfM[iPoint] = mIn;
688 : }
689 443 : return true;
690 : }
691 :
692 : /**
693 : * \brief Set the location of a vertex in line string.
694 : *
695 : * If iPoint is larger than the number of necessary the number of existing
696 : * points in the line string, the point count will be increased to
697 : * accommodate the request.
698 : *
699 : * There is no SFCOM analog to this method.
700 : *
701 : * @param iPoint the index of the vertex to assign (zero based).
702 : * @param xIn input X coordinate to assign.
703 : * @param yIn input Y coordinate to assign.
704 : * @param zIn input Z coordinate to assign (defaults to zero).
705 : * @param mIn input M coordinate to assign (defaults to zero).
706 : * @return (since 3.10) true in case of success, false in case of memory allocation error
707 : */
708 :
709 852 : bool OGRSimpleCurve::setPoint(int iPoint, double xIn, double yIn, double zIn,
710 : double mIn)
711 :
712 : {
713 852 : if (!(flags & OGR_G_3D))
714 : {
715 271 : if (!Make3D())
716 0 : return false;
717 : }
718 852 : if (!(flags & OGR_G_MEASURED))
719 : {
720 284 : if (!AddM())
721 0 : return false;
722 : }
723 :
724 852 : if (iPoint >= nPointCount)
725 : {
726 261 : if (!CheckPointCount(iPoint) || !setNumPoints(iPoint + 1))
727 0 : return false;
728 : }
729 : #ifdef DEBUG
730 852 : if (paoPoints == nullptr)
731 0 : return false;
732 : #endif
733 :
734 852 : paoPoints[iPoint].x = xIn;
735 852 : paoPoints[iPoint].y = yIn;
736 :
737 852 : if (padfZ != nullptr)
738 : {
739 852 : padfZ[iPoint] = zIn;
740 : }
741 852 : if (padfM != nullptr)
742 : {
743 852 : padfM[iPoint] = mIn;
744 : }
745 852 : return true;
746 : }
747 :
748 : /**
749 : * \brief Set the location of a vertex in line string.
750 : *
751 : * If iPoint is larger than the number of necessary the number of existing
752 : * points in the line string, the point count will be increased to
753 : * accommodate the request.
754 : *
755 : * There is no SFCOM analog to this method.
756 : *
757 : * @param iPoint the index of the vertex to assign (zero based).
758 : * @param xIn input X coordinate to assign.
759 : * @param yIn input Y coordinate to assign.
760 : * @return (since 3.10) true in case of success, false in case of memory allocation error
761 : */
762 :
763 27647200 : bool OGRSimpleCurve::setPoint(int iPoint, double xIn, double yIn)
764 :
765 : {
766 27647200 : if (iPoint >= nPointCount)
767 : {
768 13980600 : if (!CheckPointCount(iPoint) || !setNumPoints(iPoint + 1) || !paoPoints)
769 2 : return false;
770 : }
771 :
772 27647200 : paoPoints[iPoint].x = xIn;
773 27647200 : paoPoints[iPoint].y = yIn;
774 27647200 : return true;
775 : }
776 :
777 : /************************************************************************/
778 : /* setZ() */
779 : /************************************************************************/
780 :
781 : /**
782 : * \brief Set the Z of a vertex in line string.
783 : *
784 : * If iPoint is larger than the number of necessary the number of existing
785 : * points in the line string, the point count will be increased to
786 : * accommodate the request.
787 : *
788 : * There is no SFCOM analog to this method.
789 : *
790 : * @param iPoint the index of the vertex to assign (zero based).
791 : * @param zIn input Z coordinate to assign.
792 : * @return (since 3.10) true in case of success, false in case of memory allocation error
793 : */
794 :
795 7010 : bool OGRSimpleCurve::setZ(int iPoint, double zIn)
796 : {
797 7010 : if (getCoordinateDimension() == 2)
798 : {
799 840 : if (!Make3D())
800 0 : return false;
801 : }
802 :
803 7010 : if (iPoint >= nPointCount)
804 : {
805 0 : if (!CheckPointCount(iPoint) || !setNumPoints(iPoint + 1))
806 0 : return false;
807 : }
808 :
809 7010 : if (padfZ != nullptr)
810 7010 : padfZ[iPoint] = zIn;
811 7010 : return true;
812 : }
813 :
814 : /************************************************************************/
815 : /* setM() */
816 : /************************************************************************/
817 :
818 : /**
819 : * \brief Set the M of a vertex in line string.
820 : *
821 : * If iPoint is larger than the number of necessary the number of existing
822 : * points in the line string, the point count will be increased to
823 : * accommodate the request.
824 : *
825 : * There is no SFCOM analog to this method.
826 : *
827 : * @param iPoint the index of the vertex to assign (zero based).
828 : * @param mIn input M coordinate to assign.
829 : * @return (since 3.10) true in case of success, false in case of memory allocation error
830 : */
831 :
832 835 : bool OGRSimpleCurve::setM(int iPoint, double mIn)
833 : {
834 835 : if (!(flags & OGR_G_MEASURED))
835 : {
836 103 : if (!AddM())
837 0 : return false;
838 : }
839 :
840 835 : if (iPoint >= nPointCount)
841 : {
842 0 : if (!CheckPointCount(iPoint) || !setNumPoints(iPoint + 1))
843 0 : return false;
844 : }
845 :
846 835 : if (padfM != nullptr)
847 835 : padfM[iPoint] = mIn;
848 835 : return true;
849 : }
850 :
851 : /************************************************************************/
852 : /* addPoint() */
853 : /************************************************************************/
854 :
855 : /**
856 : * \brief Add a point to a line string.
857 : *
858 : * The vertex count of the line string is increased by one, and assigned from
859 : * the passed location value.
860 : *
861 : * There is no SFCOM analog to this method.
862 : *
863 : * @param poPoint the point to assign to the new vertex.
864 : * @return (since 3.10) true in case of success, false in case of memory allocation error
865 : */
866 :
867 5021170 : bool OGRSimpleCurve::addPoint(const OGRPoint *poPoint)
868 :
869 : {
870 5021170 : if (poPoint->Is3D() && poPoint->IsMeasured())
871 250 : return setPoint(nPointCount, poPoint->getX(), poPoint->getY(),
872 250 : poPoint->getZ(), poPoint->getM());
873 5020920 : else if (poPoint->Is3D())
874 4986920 : return setPoint(nPointCount, poPoint->getX(), poPoint->getY(),
875 4986920 : poPoint->getZ());
876 33997 : else if (poPoint->IsMeasured())
877 0 : return setPointM(nPointCount, poPoint->getX(), poPoint->getY(),
878 0 : poPoint->getM());
879 : else
880 33999 : return setPoint(nPointCount, poPoint->getX(), poPoint->getY());
881 : }
882 :
883 : /************************************************************************/
884 : /* addPoint() */
885 : /************************************************************************/
886 :
887 : /**
888 : * \brief Add a point to a line string.
889 : *
890 : * The vertex count of the line string is increased by one, and assigned from
891 : * the passed location value.
892 : *
893 : * There is no SFCOM analog to this method.
894 : *
895 : * @param x the X coordinate to assign to the new point.
896 : * @param y the Y coordinate to assign to the new point.
897 : * @param z the Z coordinate to assign to the new point (defaults to zero).
898 : * @param m the M coordinate to assign to the new point (defaults to zero).
899 : * @return (since 3.10) true in case of success, false in case of memory allocation error
900 : */
901 :
902 11 : bool OGRSimpleCurve::addPoint(double x, double y, double z, double m)
903 :
904 : {
905 11 : return setPoint(nPointCount, x, y, z, m);
906 : }
907 :
908 : /**
909 : * \brief Add a point to a line string.
910 : *
911 : * The vertex count of the line string is increased by one, and assigned from
912 : * the passed location value.
913 : *
914 : * There is no SFCOM analog to this method.
915 : *
916 : * @param x the X coordinate to assign to the new point.
917 : * @param y the Y coordinate to assign to the new point.
918 : * @param z the Z coordinate to assign to the new point (defaults to zero).
919 : * @return (since 3.10) true in case of success, false in case of memory allocation error
920 : */
921 :
922 507151 : bool OGRSimpleCurve::addPoint(double x, double y, double z)
923 :
924 : {
925 507151 : return setPoint(nPointCount, x, y, z);
926 : }
927 :
928 : /**
929 : * \brief Add a point to a line string.
930 : *
931 : * The vertex count of the line string is increased by one, and assigned from
932 : * the passed location value.
933 : *
934 : * There is no SFCOM analog to this method.
935 : *
936 : * @param x the X coordinate to assign to the new point.
937 : * @param y the Y coordinate to assign to the new point.
938 : * @return (since 3.10) true in case of success, false in case of memory allocation error
939 : */
940 :
941 13893700 : bool OGRSimpleCurve::addPoint(double x, double y)
942 :
943 : {
944 13893700 : return setPoint(nPointCount, x, y);
945 : }
946 :
947 : /**
948 : * \brief Add a point to a line string.
949 : *
950 : * The vertex count of the line string is increased by one, and assigned from
951 : * the passed location value.
952 : *
953 : * There is no SFCOM analog to this method.
954 : *
955 : * @param x the X coordinate to assign to the new point.
956 : * @param y the Y coordinate to assign to the new point.
957 : * @param m the M coordinate to assign to the new point.
958 : * @return (since 3.10) true in case of success, false in case of memory allocation error
959 : */
960 :
961 6 : bool OGRSimpleCurve::addPointM(double x, double y, double m)
962 :
963 : {
964 6 : return setPointM(nPointCount, x, y, m);
965 : }
966 :
967 : /************************************************************************/
968 : /* removePoint() */
969 : /************************************************************************/
970 :
971 : /**
972 : * \brief Remove a point from a line string.
973 : *
974 : * There is no SFCOM analog to this method.
975 : *
976 : * @param nIndex Point index
977 : * @since GDAL 3.3
978 : */
979 :
980 15 : bool OGRSimpleCurve::removePoint(int nIndex)
981 : {
982 15 : if (nIndex < 0 || nIndex >= nPointCount)
983 4 : return false;
984 11 : if (nIndex < nPointCount - 1)
985 : {
986 7 : memmove(paoPoints + nIndex, paoPoints + nIndex + 1,
987 7 : sizeof(OGRRawPoint) * (nPointCount - 1 - nIndex));
988 7 : if (padfZ)
989 : {
990 1 : memmove(padfZ + nIndex, padfZ + nIndex + 1,
991 1 : sizeof(double) * (nPointCount - 1 - nIndex));
992 : }
993 7 : if (padfM)
994 : {
995 1 : memmove(padfM + nIndex, padfM + nIndex + 1,
996 1 : sizeof(double) * (nPointCount - 1 - nIndex));
997 : }
998 : }
999 11 : nPointCount--;
1000 11 : return true;
1001 : }
1002 :
1003 : /************************************************************************/
1004 : /* setPointsM() */
1005 : /************************************************************************/
1006 :
1007 : /**
1008 : * \brief Assign all points in a line string.
1009 : *
1010 : * This method clears any existing points assigned to this line string,
1011 : * and assigns a whole new set. It is the most efficient way of assigning
1012 : * the value of a line string.
1013 : *
1014 : * There is no SFCOM analog to this method.
1015 : *
1016 : * @param nPointsIn number of points being passed in paoPointsIn
1017 : * @param paoPointsIn list of points being assigned.
1018 : * @param padfMIn the M values that go with the points.
1019 : * @return (since 3.10) true in case of success, false in case of memory allocation error
1020 : */
1021 :
1022 190 : bool OGRSimpleCurve::setPointsM(int nPointsIn, const OGRRawPoint *paoPointsIn,
1023 : const double *padfMIn)
1024 :
1025 : {
1026 190 : if (!setNumPoints(nPointsIn, FALSE)
1027 : #ifdef DEBUG
1028 190 : || paoPoints == nullptr
1029 : #endif
1030 : )
1031 0 : return false;
1032 :
1033 190 : if (nPointsIn)
1034 190 : memcpy(paoPoints, paoPointsIn, sizeof(OGRRawPoint) * nPointsIn);
1035 :
1036 : /* -------------------------------------------------------------------- */
1037 : /* Check measures. */
1038 : /* -------------------------------------------------------------------- */
1039 190 : if (padfMIn == nullptr && (flags & OGR_G_MEASURED))
1040 : {
1041 0 : RemoveM();
1042 : }
1043 190 : else if (padfMIn)
1044 : {
1045 190 : if (!AddM())
1046 0 : return false;
1047 190 : if (padfM && nPointsIn)
1048 190 : memcpy(padfM, padfMIn, sizeof(double) * nPointsIn);
1049 : }
1050 190 : return true;
1051 : }
1052 :
1053 : /************************************************************************/
1054 : /* setPoints() */
1055 : /************************************************************************/
1056 :
1057 : /**
1058 : * \brief Assign all points in a line string.
1059 : *
1060 : * This method clears any existing points assigned to this line string,
1061 : * and assigns a whole new set. It is the most efficient way of assigning
1062 : * the value of a line string.
1063 : *
1064 : * There is no SFCOM analog to this method.
1065 : *
1066 : * @param nPointsIn number of points being passed in paoPointsIn
1067 : * @param paoPointsIn list of points being assigned.
1068 : * @param padfZIn the Z values that go with the points.
1069 : * @param padfMIn the M values that go with the points.
1070 : * @return (since 3.10) true in case of success, false in case of memory allocation error
1071 : */
1072 :
1073 1900810 : bool OGRSimpleCurve::setPoints(int nPointsIn, const OGRRawPoint *paoPointsIn,
1074 : const double *padfZIn, const double *padfMIn)
1075 :
1076 : {
1077 1900810 : if (!setNumPoints(nPointsIn, FALSE)
1078 : #ifdef DEBUG
1079 1900810 : || paoPoints == nullptr
1080 : #endif
1081 : )
1082 89 : return false;
1083 :
1084 1900720 : if (nPointsIn)
1085 1900720 : memcpy(paoPoints, paoPointsIn, sizeof(OGRRawPoint) * nPointsIn);
1086 :
1087 : /* -------------------------------------------------------------------- */
1088 : /* Check 2D/3D. */
1089 : /* -------------------------------------------------------------------- */
1090 1900720 : if (padfZIn == nullptr && getCoordinateDimension() > 2)
1091 : {
1092 0 : Make2D();
1093 : }
1094 1900720 : else if (padfZIn)
1095 : {
1096 1352750 : if (!Make3D())
1097 0 : return false;
1098 1352750 : if (padfZ && nPointsIn)
1099 1352750 : memcpy(padfZ, padfZIn, sizeof(double) * nPointsIn);
1100 : }
1101 :
1102 : /* -------------------------------------------------------------------- */
1103 : /* Check measures. */
1104 : /* -------------------------------------------------------------------- */
1105 1900720 : if (padfMIn == nullptr && (flags & OGR_G_MEASURED))
1106 : {
1107 0 : RemoveM();
1108 : }
1109 1900720 : else if (padfMIn)
1110 : {
1111 804 : if (!AddM())
1112 0 : return false;
1113 804 : if (padfM && nPointsIn)
1114 804 : memcpy(padfM, padfMIn, sizeof(double) * nPointsIn);
1115 : }
1116 1900720 : return true;
1117 : }
1118 :
1119 : /************************************************************************/
1120 : /* setPoints() */
1121 : /************************************************************************/
1122 :
1123 : /**
1124 : * \brief Assign all points in a line string.
1125 : *
1126 : * This method clears any existing points assigned to this line string,
1127 : * and assigns a whole new set. It is the most efficient way of assigning
1128 : * the value of a line string.
1129 : *
1130 : * There is no SFCOM analog to this method.
1131 : *
1132 : * @param nPointsIn number of points being passed in paoPointsIn
1133 : * @param paoPointsIn list of points being assigned.
1134 : * @param padfZIn the Z values that go with the points (optional, may be NULL).
1135 : * @return (since 3.10) true in case of success, false in case of memory allocation error
1136 : */
1137 :
1138 20921 : bool OGRSimpleCurve::setPoints(int nPointsIn, const OGRRawPoint *paoPointsIn,
1139 : const double *padfZIn)
1140 :
1141 : {
1142 20921 : if (!setNumPoints(nPointsIn, FALSE)
1143 : #ifdef DEBUG
1144 20921 : || paoPoints == nullptr
1145 : #endif
1146 : )
1147 7 : return false;
1148 :
1149 20914 : if (nPointsIn)
1150 20914 : memcpy(paoPoints, paoPointsIn, sizeof(OGRRawPoint) * nPointsIn);
1151 :
1152 : /* -------------------------------------------------------------------- */
1153 : /* Check 2D/3D. */
1154 : /* -------------------------------------------------------------------- */
1155 20914 : if (padfZIn == nullptr && getCoordinateDimension() > 2)
1156 : {
1157 0 : Make2D();
1158 : }
1159 20914 : else if (padfZIn)
1160 : {
1161 1405 : if (!Make3D())
1162 0 : return false;
1163 1405 : if (padfZ && nPointsIn)
1164 1405 : memcpy(padfZ, padfZIn, sizeof(double) * nPointsIn);
1165 : }
1166 20914 : return true;
1167 : }
1168 :
1169 : /************************************************************************/
1170 : /* setPoints() */
1171 : /************************************************************************/
1172 :
1173 : /**
1174 : * \brief Assign all points in a line string.
1175 : *
1176 : * This method clear any existing points assigned to this line string,
1177 : * and assigns a whole new set.
1178 : *
1179 : * There is no SFCOM analog to this method.
1180 : *
1181 : * @param nPointsIn number of points being passed in padfX and padfY.
1182 : * @param padfX list of X coordinates of points being assigned.
1183 : * @param padfY list of Y coordinates of points being assigned.
1184 : * @param padfZIn list of Z coordinates of points being assigned (defaults to
1185 : * NULL for 2D objects).
1186 : * @return (since 3.10) true in case of success, false in case of memory allocation error
1187 : */
1188 :
1189 39031 : bool OGRSimpleCurve::setPoints(int nPointsIn, const double *padfX,
1190 : const double *padfY, const double *padfZIn)
1191 :
1192 : {
1193 : /* -------------------------------------------------------------------- */
1194 : /* Check 2D/3D. */
1195 : /* -------------------------------------------------------------------- */
1196 39031 : if (padfZIn == nullptr)
1197 35920 : Make2D();
1198 : else
1199 : {
1200 3111 : if (!Make3D())
1201 0 : return false;
1202 : }
1203 :
1204 : /* -------------------------------------------------------------------- */
1205 : /* Assign values. */
1206 : /* -------------------------------------------------------------------- */
1207 39031 : if (!setNumPoints(nPointsIn, FALSE))
1208 0 : return false;
1209 :
1210 429578 : for (int i = 0; i < nPointsIn; i++)
1211 : {
1212 390547 : paoPoints[i].x = padfX[i];
1213 390547 : paoPoints[i].y = padfY[i];
1214 : }
1215 :
1216 39031 : if (padfZ && padfZIn && nPointsIn)
1217 : {
1218 3111 : memcpy(padfZ, padfZIn, sizeof(double) * nPointsIn);
1219 : }
1220 39031 : return true;
1221 : }
1222 :
1223 : /************************************************************************/
1224 : /* setPointsM() */
1225 : /************************************************************************/
1226 :
1227 : /**
1228 : * \brief Assign all points in a line string.
1229 : *
1230 : * This method clear any existing points assigned to this line string,
1231 : * and assigns a whole new set.
1232 : *
1233 : * There is no SFCOM analog to this method.
1234 : *
1235 : * @param nPointsIn number of points being passed in padfX and padfY.
1236 : * @param padfX list of X coordinates of points being assigned.
1237 : * @param padfY list of Y coordinates of points being assigned.
1238 : * @param padfMIn list of M coordinates of points being assigned.
1239 : * @return (since 3.10) true in case of success, false in case of memory allocation error
1240 : */
1241 :
1242 22 : bool OGRSimpleCurve::setPointsM(int nPointsIn, const double *padfX,
1243 : const double *padfY, const double *padfMIn)
1244 :
1245 : {
1246 : /* -------------------------------------------------------------------- */
1247 : /* Check 2D/3D. */
1248 : /* -------------------------------------------------------------------- */
1249 22 : if (padfMIn == nullptr)
1250 4 : RemoveM();
1251 : else
1252 : {
1253 18 : if (!AddM())
1254 0 : return false;
1255 : }
1256 :
1257 : /* -------------------------------------------------------------------- */
1258 : /* Assign values. */
1259 : /* -------------------------------------------------------------------- */
1260 22 : if (!setNumPoints(nPointsIn, FALSE))
1261 0 : return false;
1262 :
1263 90 : for (int i = 0; i < nPointsIn; i++)
1264 : {
1265 68 : paoPoints[i].x = padfX[i];
1266 68 : paoPoints[i].y = padfY[i];
1267 : }
1268 :
1269 22 : if (padfMIn && padfM && nPointsIn)
1270 : {
1271 18 : memcpy(padfM, padfMIn, sizeof(double) * nPointsIn);
1272 : }
1273 22 : return true;
1274 : }
1275 :
1276 : /************************************************************************/
1277 : /* setPoints() */
1278 : /************************************************************************/
1279 :
1280 : /**
1281 : * \brief Assign all points in a line string.
1282 : *
1283 : * This method clear any existing points assigned to this line string,
1284 : * and assigns a whole new set.
1285 : *
1286 : * There is no SFCOM analog to this method.
1287 : *
1288 : * @param nPointsIn number of points being passed in padfX and padfY.
1289 : * @param padfX list of X coordinates of points being assigned.
1290 : * @param padfY list of Y coordinates of points being assigned.
1291 : * @param padfZIn list of Z coordinates of points being assigned.
1292 : * @param padfMIn list of M coordinates of points being assigned.
1293 : * @return (since 3.10) true in case of success, false in case of memory allocation error
1294 : */
1295 :
1296 3504 : bool OGRSimpleCurve::setPoints(int nPointsIn, const double *padfX,
1297 : const double *padfY, const double *padfZIn,
1298 : const double *padfMIn)
1299 :
1300 : {
1301 : /* -------------------------------------------------------------------- */
1302 : /* Check 2D/3D. */
1303 : /* -------------------------------------------------------------------- */
1304 3504 : if (padfZIn == nullptr)
1305 66 : Make2D();
1306 : else
1307 : {
1308 3438 : if (!Make3D())
1309 0 : return false;
1310 : }
1311 :
1312 : /* -------------------------------------------------------------------- */
1313 : /* Check measures. */
1314 : /* -------------------------------------------------------------------- */
1315 3504 : if (padfMIn == nullptr)
1316 3476 : RemoveM();
1317 : else
1318 : {
1319 28 : if (!AddM())
1320 0 : return false;
1321 : }
1322 :
1323 : /* -------------------------------------------------------------------- */
1324 : /* Assign values. */
1325 : /* -------------------------------------------------------------------- */
1326 3504 : if (!setNumPoints(nPointsIn, FALSE))
1327 0 : return false;
1328 :
1329 66284 : for (int i = 0; i < nPointsIn; i++)
1330 : {
1331 62780 : paoPoints[i].x = padfX[i];
1332 62780 : paoPoints[i].y = padfY[i];
1333 : }
1334 :
1335 3504 : if (padfZ != nullptr && padfZIn && nPointsIn)
1336 3438 : memcpy(padfZ, padfZIn, sizeof(double) * nPointsIn);
1337 3504 : if (padfM != nullptr && padfMIn && nPointsIn)
1338 28 : memcpy(padfM, padfMIn, sizeof(double) * nPointsIn);
1339 3504 : return true;
1340 : }
1341 :
1342 : /************************************************************************/
1343 : /* getPoints() */
1344 : /************************************************************************/
1345 :
1346 : /**
1347 : * \brief Returns all points of line string.
1348 : *
1349 : * This method copies all points into user list. This list must be at
1350 : * least sizeof(OGRRawPoint) * OGRGeometry::getNumPoints() byte in size.
1351 : * It also copies all Z coordinates.
1352 : *
1353 : * There is no SFCOM analog to this method.
1354 : *
1355 : * @param paoPointsOut a buffer into which the points is written.
1356 : * @param padfZOut the Z values that go with the points (optional, may be NULL).
1357 : */
1358 :
1359 726 : void OGRSimpleCurve::getPoints(OGRRawPoint *paoPointsOut,
1360 : double *padfZOut) const
1361 : {
1362 726 : if (!paoPointsOut || nPointCount == 0)
1363 3 : return;
1364 :
1365 723 : memcpy(paoPointsOut, paoPoints, sizeof(OGRRawPoint) * nPointCount);
1366 :
1367 : /* -------------------------------------------------------------------- */
1368 : /* Check 2D/3D. */
1369 : /* -------------------------------------------------------------------- */
1370 723 : if (padfZOut)
1371 : {
1372 196 : if (padfZ)
1373 195 : memcpy(padfZOut, padfZ, sizeof(double) * nPointCount);
1374 : else
1375 1 : memset(padfZOut, 0, sizeof(double) * nPointCount);
1376 : }
1377 : }
1378 :
1379 : /**
1380 : * \brief Returns all points of line string.
1381 : *
1382 : * This method copies all points into user arrays. The user provides the
1383 : * stride between 2 consecutive elements of the array.
1384 : *
1385 : * On some CPU architectures, care must be taken so that the arrays are properly
1386 : * aligned.
1387 : *
1388 : * There is no SFCOM analog to this method.
1389 : *
1390 : * @param pabyX a buffer of at least (nXStride * nPointCount) bytes, may be
1391 : * NULL.
1392 : * @param nXStride the number of bytes between 2 elements of pabyX.
1393 : * @param pabyY a buffer of at least (nYStride * nPointCount) bytes, may be
1394 : * NULL.
1395 : * @param nYStride the number of bytes between 2 elements of pabyY.
1396 : * @param pabyZ a buffer of at last size (nZStride * nPointCount) bytes, may be
1397 : * NULL.
1398 : * @param nZStride the number of bytes between 2 elements of pabyZ.
1399 : * @param pabyM a buffer of at last size (nMStride * nPointCount) bytes, may be
1400 : * NULL.
1401 : * @param nMStride the number of bytes between 2 elements of pabyM.
1402 : *
1403 : * @since OGR 2.1.0
1404 : */
1405 :
1406 182 : void OGRSimpleCurve::getPoints(void *pabyX, int nXStride, void *pabyY,
1407 : int nYStride, void *pabyZ, int nZStride,
1408 : void *pabyM, int nMStride) const
1409 : {
1410 182 : if (pabyX != nullptr && nXStride == 0)
1411 0 : return;
1412 182 : if (pabyY != nullptr && nYStride == 0)
1413 0 : return;
1414 182 : if (pabyZ != nullptr && nZStride == 0)
1415 0 : return;
1416 182 : if (pabyM != nullptr && nMStride == 0)
1417 0 : return;
1418 182 : if (nXStride == sizeof(OGRRawPoint) && nYStride == sizeof(OGRRawPoint) &&
1419 : static_cast<char *>(pabyY) ==
1420 182 : static_cast<char *>(pabyX) + sizeof(double) &&
1421 75 : (pabyZ == nullptr || nZStride == sizeof(double)))
1422 : {
1423 182 : getPoints(static_cast<OGRRawPoint *>(pabyX),
1424 : static_cast<double *>(pabyZ));
1425 : }
1426 : else
1427 : {
1428 0 : for (int i = 0; i < nPointCount; i++)
1429 : {
1430 0 : if (pabyX)
1431 0 : *reinterpret_cast<double *>(static_cast<char *>(pabyX) +
1432 0 : i * nXStride) = paoPoints[i].x;
1433 0 : if (pabyY)
1434 0 : *reinterpret_cast<double *>(static_cast<char *>(pabyY) +
1435 0 : i * nYStride) = paoPoints[i].y;
1436 : }
1437 :
1438 0 : if (pabyZ)
1439 : {
1440 0 : if (nZStride == sizeof(double))
1441 : {
1442 0 : if (padfZ)
1443 0 : memcpy(pabyZ, padfZ, sizeof(double) * nPointCount);
1444 : else
1445 0 : memset(pabyZ, 0, sizeof(double) * nPointCount);
1446 : }
1447 : else
1448 : {
1449 0 : for (int i = 0; i < nPointCount; i++)
1450 : {
1451 0 : *reinterpret_cast<double *>(static_cast<char *>(pabyZ) +
1452 0 : i * nZStride) =
1453 0 : (padfZ) ? padfZ[i] : 0.0;
1454 : }
1455 : }
1456 : }
1457 : }
1458 182 : if (pabyM)
1459 : {
1460 58 : if (nMStride == sizeof(double))
1461 : {
1462 58 : if (padfM)
1463 58 : memcpy(pabyM, padfM, sizeof(double) * nPointCount);
1464 : else
1465 0 : memset(pabyM, 0, sizeof(double) * nPointCount);
1466 : }
1467 : else
1468 : {
1469 0 : for (int i = 0; i < nPointCount; i++)
1470 : {
1471 0 : *reinterpret_cast<double *>(static_cast<char *>(pabyM) +
1472 0 : i * nMStride) =
1473 0 : (padfM) ? padfM[i] : 0.0;
1474 : }
1475 : }
1476 : }
1477 : }
1478 :
1479 : /************************************************************************/
1480 : /* reversePoints() */
1481 : /************************************************************************/
1482 :
1483 : /**
1484 : * \brief Reverse point order.
1485 : *
1486 : * This method updates the points in this line string in place
1487 : * reversing the point ordering (first for last, etc).
1488 : */
1489 :
1490 2456 : void OGRSimpleCurve::reversePoints()
1491 :
1492 : {
1493 60124 : for (int i = 0; i < nPointCount / 2; i++)
1494 : {
1495 57668 : std::swap(paoPoints[i], paoPoints[nPointCount - i - 1]);
1496 57668 : if (padfZ)
1497 : {
1498 2401 : std::swap(padfZ[i], padfZ[nPointCount - i - 1]);
1499 : }
1500 :
1501 57668 : if (padfM)
1502 : {
1503 6 : std::swap(padfM[i], padfM[nPointCount - i - 1]);
1504 : }
1505 : }
1506 2456 : }
1507 :
1508 : /************************************************************************/
1509 : /* addSubLineString() */
1510 : /************************************************************************/
1511 :
1512 : /**
1513 : * \brief Add a segment of another linestring to this one.
1514 : *
1515 : * Adds the request range of vertices to the end of this line string
1516 : * in an efficient manner. If the nStartVertex is larger than the
1517 : * nEndVertex then the vertices will be reversed as they are copied.
1518 : *
1519 : * @param poOtherLine the other OGRLineString.
1520 : * @param nStartVertex the first vertex to copy, defaults to 0 to start
1521 : * with the first vertex in the other linestring.
1522 : * @param nEndVertex the last vertex to copy, defaults to -1 indicating
1523 : * the last vertex of the other line string.
1524 : */
1525 :
1526 9245 : void OGRSimpleCurve::addSubLineString(const OGRLineString *poOtherLine,
1527 : int nStartVertex, int nEndVertex)
1528 :
1529 : {
1530 9245 : int nOtherLineNumPoints = poOtherLine->getNumPoints();
1531 9245 : if (nOtherLineNumPoints == 0)
1532 0 : return;
1533 :
1534 : /* -------------------------------------------------------------------- */
1535 : /* Do a bit of argument defaulting and validation. */
1536 : /* -------------------------------------------------------------------- */
1537 9245 : if (nEndVertex == -1)
1538 6465 : nEndVertex = nOtherLineNumPoints - 1;
1539 :
1540 9245 : if (nStartVertex < 0 || nEndVertex < 0 ||
1541 9245 : nStartVertex >= nOtherLineNumPoints ||
1542 : nEndVertex >= nOtherLineNumPoints)
1543 : {
1544 0 : CPLAssert(false);
1545 : return;
1546 : }
1547 :
1548 : /* -------------------------------------------------------------------- */
1549 : /* Grow this linestring to hold the additional points. */
1550 : /* -------------------------------------------------------------------- */
1551 9245 : int nOldPoints = nPointCount;
1552 9245 : int nPointsToAdd = std::abs(nEndVertex - nStartVertex) + 1;
1553 :
1554 9245 : if (!setNumPoints(nPointsToAdd + nOldPoints, FALSE)
1555 : #ifdef DEBUG
1556 9245 : || paoPoints == nullptr
1557 : #endif
1558 : )
1559 0 : return;
1560 :
1561 : /* -------------------------------------------------------------------- */
1562 : /* Copy the x/y points - forward copies use memcpy. */
1563 : /* -------------------------------------------------------------------- */
1564 9245 : if (nEndVertex >= nStartVertex)
1565 : {
1566 9054 : memcpy(paoPoints + nOldPoints, poOtherLine->paoPoints + nStartVertex,
1567 9054 : sizeof(OGRRawPoint) * nPointsToAdd);
1568 9054 : if (poOtherLine->padfZ != nullptr)
1569 : {
1570 1171 : Make3D();
1571 1171 : if (padfZ != nullptr)
1572 : {
1573 1171 : memcpy(padfZ + nOldPoints, poOtherLine->padfZ + nStartVertex,
1574 1171 : sizeof(double) * nPointsToAdd);
1575 : }
1576 : }
1577 9054 : if (poOtherLine->padfM != nullptr)
1578 : {
1579 92 : AddM();
1580 92 : if (padfM != nullptr)
1581 : {
1582 92 : memcpy(padfM + nOldPoints, poOtherLine->padfM + nStartVertex,
1583 92 : sizeof(double) * nPointsToAdd);
1584 : }
1585 : }
1586 : }
1587 :
1588 : /* -------------------------------------------------------------------- */
1589 : /* Copy the x/y points - reverse copies done double by double. */
1590 : /* -------------------------------------------------------------------- */
1591 : else
1592 : {
1593 1480 : for (int i = 0; i < nPointsToAdd; i++)
1594 : {
1595 1289 : paoPoints[i + nOldPoints].x =
1596 1289 : poOtherLine->paoPoints[nStartVertex - i].x;
1597 1289 : paoPoints[i + nOldPoints].y =
1598 1289 : poOtherLine->paoPoints[nStartVertex - i].y;
1599 : }
1600 :
1601 191 : if (poOtherLine->padfZ != nullptr)
1602 : {
1603 0 : Make3D();
1604 0 : if (padfZ != nullptr)
1605 : {
1606 0 : for (int i = 0; i < nPointsToAdd; i++)
1607 : {
1608 0 : padfZ[i + nOldPoints] =
1609 0 : poOtherLine->padfZ[nStartVertex - i];
1610 : }
1611 : }
1612 : }
1613 191 : if (poOtherLine->padfM != nullptr)
1614 : {
1615 0 : AddM();
1616 0 : if (padfM != nullptr)
1617 : {
1618 0 : for (int i = 0; i < nPointsToAdd; i++)
1619 : {
1620 0 : padfM[i + nOldPoints] =
1621 0 : poOtherLine->padfM[nStartVertex - i];
1622 : }
1623 : }
1624 : }
1625 : }
1626 : }
1627 :
1628 : /************************************************************************/
1629 : /* importFromWkb() */
1630 : /* */
1631 : /* Initialize from serialized stream in well known binary */
1632 : /* format. */
1633 : /************************************************************************/
1634 :
1635 5296 : OGRErr OGRSimpleCurve::importFromWkb(const unsigned char *pabyData,
1636 : size_t nSize, OGRwkbVariant eWkbVariant,
1637 : size_t &nBytesConsumedOut)
1638 :
1639 : {
1640 : OGRwkbByteOrder eByteOrder;
1641 5296 : size_t nDataOffset = 0;
1642 5296 : int nNewNumPoints = 0;
1643 :
1644 5296 : nBytesConsumedOut = 0;
1645 5296 : OGRErr eErr = importPreambleOfCollectionFromWkb(pabyData, nSize,
1646 : nDataOffset, eByteOrder, 16,
1647 : nNewNumPoints, eWkbVariant);
1648 5295 : if (eErr != OGRERR_NONE)
1649 203 : return eErr;
1650 :
1651 : // Check if the wkb stream buffer is big enough to store
1652 : // fetched number of points.
1653 5092 : const int dim = CoordinateDimension();
1654 5092 : const size_t nPointSize = dim * sizeof(double);
1655 10184 : if (nNewNumPoints < 0 ||
1656 5092 : static_cast<size_t>(nNewNumPoints) >
1657 5092 : std::numeric_limits<size_t>::max() / nPointSize)
1658 : {
1659 0 : return OGRERR_CORRUPT_DATA;
1660 : }
1661 5092 : const size_t nBufferMinSize = nPointSize * nNewNumPoints;
1662 :
1663 5092 : if (nSize != static_cast<size_t>(-1) && nBufferMinSize > nSize)
1664 : {
1665 67 : CPLError(CE_Failure, CPLE_AppDefined,
1666 : "Length of input WKB is too small");
1667 67 : return OGRERR_NOT_ENOUGH_DATA;
1668 : }
1669 :
1670 5025 : if (!setNumPoints(nNewNumPoints, FALSE))
1671 0 : return OGRERR_NOT_ENOUGH_MEMORY;
1672 :
1673 5026 : nBytesConsumedOut = 9 + 8 * static_cast<size_t>(nPointCount) *
1674 5026 : (2 + ((flags & OGR_G_3D) ? 1 : 0) +
1675 5026 : ((flags & OGR_G_MEASURED) ? 1 : 0));
1676 :
1677 : /* -------------------------------------------------------------------- */
1678 : /* Get the vertex. */
1679 : /* -------------------------------------------------------------------- */
1680 5026 : if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
1681 : {
1682 8832 : for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
1683 : {
1684 5328 : memcpy(paoPoints + i, pabyData + 9 + i * 32, 16);
1685 5328 : memcpy(padfZ + i, pabyData + 9 + 16 + i * 32, 8);
1686 5328 : memcpy(padfM + i, pabyData + 9 + 24 + i * 32, 8);
1687 3504 : }
1688 : }
1689 1522 : else if (flags & OGR_G_MEASURED)
1690 : {
1691 252 : for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
1692 : {
1693 185 : memcpy(paoPoints + i, pabyData + 9 + i * 24, 16);
1694 185 : memcpy(padfM + i, pabyData + 9 + 16 + i * 24, 8);
1695 : }
1696 : }
1697 1455 : else if (flags & OGR_G_3D)
1698 : {
1699 576 : for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
1700 : {
1701 413 : memcpy(paoPoints + i, pabyData + 9 + i * 24, 16);
1702 413 : memcpy(padfZ + i, pabyData + 9 + 16 + i * 24, 8);
1703 : }
1704 : }
1705 1292 : else if (nPointCount)
1706 : {
1707 1261 : memcpy(paoPoints, pabyData + 9, 16 * static_cast<size_t>(nPointCount));
1708 : }
1709 :
1710 : /* -------------------------------------------------------------------- */
1711 : /* Byte swap if needed. */
1712 : /* -------------------------------------------------------------------- */
1713 5026 : if (OGR_SWAP(eByteOrder))
1714 : {
1715 440 : for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
1716 : {
1717 310 : CPL_SWAPDOUBLE(&(paoPoints[i].x));
1718 310 : CPL_SWAPDOUBLE(&(paoPoints[i].y));
1719 : }
1720 :
1721 130 : if (flags & OGR_G_3D)
1722 : {
1723 14 : for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
1724 : {
1725 10 : CPL_SWAPDOUBLE(padfZ + i);
1726 : }
1727 : }
1728 :
1729 130 : if (flags & OGR_G_MEASURED)
1730 : {
1731 6 : for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
1732 : {
1733 4 : CPL_SWAPDOUBLE(padfM + i);
1734 : }
1735 : }
1736 : }
1737 :
1738 5026 : return OGRERR_NONE;
1739 : }
1740 :
1741 : /************************************************************************/
1742 : /* exportToWkb() */
1743 : /* */
1744 : /* Build a well known binary representation of this object. */
1745 : /************************************************************************/
1746 :
1747 9944 : OGRErr OGRSimpleCurve::exportToWkb(unsigned char *pabyData,
1748 : const OGRwkbExportOptions *psOptions) const
1749 :
1750 : {
1751 9944 : if (psOptions == nullptr)
1752 : {
1753 : static const OGRwkbExportOptions defaultOptions;
1754 0 : psOptions = &defaultOptions;
1755 : }
1756 :
1757 : /* -------------------------------------------------------------------- */
1758 : /* Set the byte order. */
1759 : /* -------------------------------------------------------------------- */
1760 9944 : pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER(
1761 : static_cast<unsigned char>(psOptions->eByteOrder));
1762 :
1763 : /* -------------------------------------------------------------------- */
1764 : /* Set the geometry feature type. */
1765 : /* -------------------------------------------------------------------- */
1766 9944 : GUInt32 nGType = getGeometryType();
1767 :
1768 9944 : if (psOptions->eWkbVariant == wkbVariantPostGIS1)
1769 : {
1770 6 : nGType = wkbFlatten(nGType);
1771 6 : if (Is3D())
1772 : // Explicitly set wkb25DBit.
1773 1 : nGType =
1774 1 : static_cast<OGRwkbGeometryType>(nGType | wkb25DBitInternalUse);
1775 6 : if (IsMeasured())
1776 0 : nGType = static_cast<OGRwkbGeometryType>(nGType | 0x40000000);
1777 : }
1778 9938 : else if (psOptions->eWkbVariant == wkbVariantIso)
1779 3741 : nGType = getIsoGeometryType();
1780 :
1781 9944 : if (psOptions->eByteOrder == wkbNDR)
1782 : {
1783 9931 : CPL_LSBPTR32(&nGType);
1784 : }
1785 : else
1786 : {
1787 13 : CPL_MSBPTR32(&nGType);
1788 : }
1789 :
1790 9943 : memcpy(pabyData + 1, &nGType, 4);
1791 :
1792 : /* -------------------------------------------------------------------- */
1793 : /* Copy in the data count. */
1794 : /* -------------------------------------------------------------------- */
1795 9943 : memcpy(pabyData + 5, &nPointCount, 4);
1796 :
1797 : /* -------------------------------------------------------------------- */
1798 : /* Copy in the raw data. */
1799 : /* -------------------------------------------------------------------- */
1800 9943 : if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
1801 : {
1802 4389 : for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
1803 : {
1804 2640 : memcpy(pabyData + 9 + 32 * i, paoPoints + i, 16);
1805 2640 : memcpy(pabyData + 9 + 16 + 32 * i, padfZ + i, 8);
1806 2640 : memcpy(pabyData + 9 + 24 + 32 * i, padfM + i, 8);
1807 : }
1808 1749 : OGRRoundCoordinatesIEEE754XYValues<32>(
1809 1749 : psOptions->sPrecision.nXYBitPrecision, pabyData + 9, nPointCount);
1810 1749 : OGRRoundCoordinatesIEEE754<32>(psOptions->sPrecision.nZBitPrecision,
1811 : pabyData + 9 + 2 * sizeof(uint64_t),
1812 1749 : nPointCount);
1813 1749 : OGRRoundCoordinatesIEEE754<32>(psOptions->sPrecision.nMBitPrecision,
1814 : pabyData + 9 + 3 * sizeof(uint64_t),
1815 1749 : nPointCount);
1816 : }
1817 8194 : else if (flags & OGR_G_MEASURED)
1818 : {
1819 107 : for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
1820 : {
1821 74 : memcpy(pabyData + 9 + 24 * i, paoPoints + i, 16);
1822 74 : memcpy(pabyData + 9 + 16 + 24 * i, padfM + i, 8);
1823 : }
1824 33 : OGRRoundCoordinatesIEEE754XYValues<24>(
1825 33 : psOptions->sPrecision.nXYBitPrecision, pabyData + 9, nPointCount);
1826 33 : OGRRoundCoordinatesIEEE754<24>(psOptions->sPrecision.nMBitPrecision,
1827 : pabyData + 9 + 2 * sizeof(uint64_t),
1828 33 : nPointCount);
1829 : }
1830 8161 : else if (flags & OGR_G_3D)
1831 : {
1832 63125 : for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
1833 : {
1834 59502 : memcpy(pabyData + 9 + 24 * i, paoPoints + i, 16);
1835 59502 : memcpy(pabyData + 9 + 16 + 24 * i, padfZ + i, 8);
1836 : }
1837 3623 : OGRRoundCoordinatesIEEE754XYValues<24>(
1838 3623 : psOptions->sPrecision.nXYBitPrecision, pabyData + 9, nPointCount);
1839 3623 : OGRRoundCoordinatesIEEE754<24>(psOptions->sPrecision.nZBitPrecision,
1840 : pabyData + 9 + 2 * sizeof(uint64_t),
1841 3623 : nPointCount);
1842 : }
1843 4538 : else if (nPointCount)
1844 : {
1845 4467 : memcpy(pabyData + 9, paoPoints, 16 * static_cast<size_t>(nPointCount));
1846 4467 : OGRRoundCoordinatesIEEE754XYValues<16>(
1847 4467 : psOptions->sPrecision.nXYBitPrecision, pabyData + 9, nPointCount);
1848 : }
1849 :
1850 : /* -------------------------------------------------------------------- */
1851 : /* Swap if needed. */
1852 : /* -------------------------------------------------------------------- */
1853 9943 : if (OGR_SWAP(psOptions->eByteOrder))
1854 : {
1855 13 : const int nCount = CPL_SWAP32(nPointCount);
1856 13 : memcpy(pabyData + 5, &nCount, 4);
1857 :
1858 : const size_t nCoords =
1859 13 : CoordinateDimension() * static_cast<size_t>(nPointCount);
1860 175 : for (size_t i = 0; i < nCoords; i++)
1861 : {
1862 162 : CPL_SWAP64PTR(pabyData + 9 + 8 * i);
1863 : }
1864 : }
1865 :
1866 9943 : return OGRERR_NONE;
1867 : }
1868 :
1869 : /************************************************************************/
1870 : /* importFromWkt() */
1871 : /* */
1872 : /* Instantiate from well known text format. Currently this is */
1873 : /* `LINESTRING ( x y, x y, ...)', */
1874 : /************************************************************************/
1875 :
1876 5187 : OGRErr OGRSimpleCurve::importFromWkt(const char **ppszInput)
1877 :
1878 : {
1879 5187 : int bHasZ = FALSE;
1880 5187 : int bHasM = FALSE;
1881 5187 : bool bIsEmpty = false;
1882 : const OGRErr eErr =
1883 5187 : importPreambleFromWkt(ppszInput, &bHasZ, &bHasM, &bIsEmpty);
1884 5187 : flags = 0;
1885 5187 : if (eErr != OGRERR_NONE)
1886 5 : return eErr;
1887 5182 : if (bHasZ)
1888 302 : flags |= OGR_G_3D;
1889 5182 : if (bHasM)
1890 135 : flags |= OGR_G_MEASURED;
1891 5182 : if (bIsEmpty)
1892 : {
1893 85 : return OGRERR_NONE;
1894 : }
1895 :
1896 5097 : const char *pszInput = *ppszInput;
1897 :
1898 : /* -------------------------------------------------------------------- */
1899 : /* Read the point list. */
1900 : /* -------------------------------------------------------------------- */
1901 5097 : int flagsFromInput = flags;
1902 5097 : nPointCount = 0;
1903 :
1904 : pszInput =
1905 5097 : OGRWktReadPointsM(pszInput, &paoPoints, &padfZ, &padfM, &flagsFromInput,
1906 : &m_nPointCapacity, &nPointCount);
1907 5097 : if (pszInput == nullptr)
1908 15 : return OGRERR_CORRUPT_DATA;
1909 :
1910 5082 : if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
1911 : {
1912 270 : if (!set3D(TRUE))
1913 0 : return OGRERR_NOT_ENOUGH_MEMORY;
1914 : }
1915 5082 : if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
1916 : {
1917 0 : if (!setMeasured(TRUE))
1918 0 : return OGRERR_NOT_ENOUGH_MEMORY;
1919 : }
1920 :
1921 5082 : *ppszInput = pszInput;
1922 :
1923 5082 : return OGRERR_NONE;
1924 : }
1925 :
1926 : //! @cond Doxygen_Suppress
1927 : /************************************************************************/
1928 : /* importFromWKTListOnly() */
1929 : /* */
1930 : /* Instantiate from "(x y, x y, ...)" */
1931 : /************************************************************************/
1932 :
1933 1412 : OGRErr OGRSimpleCurve::importFromWKTListOnly(const char **ppszInput, int bHasZ,
1934 : int bHasM,
1935 : OGRRawPoint *&paoPointsIn,
1936 : int &nMaxPointsIn,
1937 : double *&padfZIn)
1938 :
1939 : {
1940 1412 : const char *pszInput = *ppszInput;
1941 :
1942 : /* -------------------------------------------------------------------- */
1943 : /* Read the point list. */
1944 : /* -------------------------------------------------------------------- */
1945 1412 : int flagsFromInput = flags;
1946 1412 : int nPointCountRead = 0;
1947 1412 : double *padfMIn = nullptr;
1948 1412 : if (flagsFromInput == 0) // Flags was not set, this is not called by us.
1949 : {
1950 1412 : if (bHasM)
1951 124 : flagsFromInput |= OGR_G_MEASURED;
1952 1412 : if (bHasZ)
1953 197 : flagsFromInput |= OGR_G_3D;
1954 : }
1955 :
1956 : pszInput =
1957 1412 : OGRWktReadPointsM(pszInput, &paoPointsIn, &padfZIn, &padfMIn,
1958 : &flagsFromInput, &nMaxPointsIn, &nPointCountRead);
1959 :
1960 1412 : if (pszInput == nullptr)
1961 : {
1962 6 : CPLFree(padfMIn);
1963 6 : return OGRERR_CORRUPT_DATA;
1964 : }
1965 1406 : if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
1966 : {
1967 364 : flags |= OGR_G_3D;
1968 364 : bHasZ = TRUE;
1969 : }
1970 1406 : if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
1971 : {
1972 124 : flags |= OGR_G_MEASURED;
1973 124 : bHasM = TRUE;
1974 : }
1975 :
1976 1406 : *ppszInput = pszInput;
1977 :
1978 1406 : if (bHasM && bHasZ)
1979 72 : setPoints(nPointCountRead, paoPointsIn, padfZIn, padfMIn);
1980 1334 : else if (bHasM && !bHasZ)
1981 52 : setPointsM(nPointCountRead, paoPointsIn, padfMIn);
1982 : else
1983 1282 : setPoints(nPointCountRead, paoPointsIn, padfZIn);
1984 :
1985 1406 : CPLFree(padfMIn);
1986 :
1987 1406 : return OGRERR_NONE;
1988 : }
1989 :
1990 : //! @endcond
1991 :
1992 : /************************************************************************/
1993 : /* exportToWkt() */
1994 : /* */
1995 : /* Translate this structure into its well known text format */
1996 : /* equivalent. This could be made a lot more CPU efficient. */
1997 : /************************************************************************/
1998 :
1999 3624 : std::string OGRSimpleCurve::exportToWkt(const OGRWktOptions &opts,
2000 : OGRErr *err) const
2001 : {
2002 : // LINEARRING or LINESTRING or CIRCULARSTRING
2003 7248 : std::string wkt = getGeometryName();
2004 3624 : wkt += wktTypeString(opts.variant);
2005 3624 : if (IsEmpty())
2006 : {
2007 89 : wkt += "EMPTY";
2008 : }
2009 : else
2010 : {
2011 3535 : wkt += '(';
2012 :
2013 3535 : OGRBoolean hasZ = Is3D();
2014 : OGRBoolean hasM =
2015 3535 : (opts.variant != wkbVariantIso ? FALSE : IsMeasured());
2016 :
2017 : try
2018 : {
2019 3535 : const int nOrdinatesPerVertex =
2020 3535 : 2 + ((hasZ) ? 1 : 0) + ((hasM) ? 1 : 0);
2021 : // At least 2 bytes per ordinate: one for the value,
2022 : // and one for the separator...
2023 3535 : wkt.reserve(wkt.size() + 2 * static_cast<size_t>(nPointCount) *
2024 3535 : nOrdinatesPerVertex);
2025 :
2026 34424 : for (int i = 0; i < nPointCount; i++)
2027 : {
2028 30889 : if (i > 0)
2029 27354 : wkt += ',';
2030 :
2031 87671 : wkt += OGRMakeWktCoordinateM(
2032 58360 : paoPoints[i].x, paoPoints[i].y, padfZ ? padfZ[i] : 0.0,
2033 61778 : padfM ? padfM[i] : 0.0, hasZ, hasM, opts);
2034 : }
2035 3535 : wkt += ')';
2036 : }
2037 0 : catch (const std::bad_alloc &e)
2038 : {
2039 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
2040 0 : if (err)
2041 0 : *err = OGRERR_FAILURE;
2042 0 : return std::string();
2043 : }
2044 : }
2045 3624 : if (err)
2046 3615 : *err = OGRERR_NONE;
2047 3624 : return wkt;
2048 : }
2049 :
2050 : /************************************************************************/
2051 : /* get_Length() */
2052 : /* */
2053 : /* For now we return a simple euclidean 2D distance. */
2054 : /************************************************************************/
2055 :
2056 1133 : double OGRSimpleCurve::get_Length() const
2057 :
2058 : {
2059 1133 : double dfLength = 0.0;
2060 :
2061 3259 : for (int i = 0; i < nPointCount - 1; i++)
2062 : {
2063 :
2064 2126 : const double dfDeltaX = paoPoints[i + 1].x - paoPoints[i].x;
2065 2126 : const double dfDeltaY = paoPoints[i + 1].y - paoPoints[i].y;
2066 2126 : dfLength += sqrt(dfDeltaX * dfDeltaX + dfDeltaY * dfDeltaY);
2067 : }
2068 :
2069 1133 : return dfLength;
2070 : }
2071 :
2072 : /************************************************************************/
2073 : /* StartPoint() */
2074 : /************************************************************************/
2075 :
2076 283330 : void OGRSimpleCurve::StartPoint(OGRPoint *poPoint) const
2077 :
2078 : {
2079 283330 : getPoint(0, poPoint);
2080 283329 : }
2081 :
2082 : /************************************************************************/
2083 : /* EndPoint() */
2084 : /************************************************************************/
2085 :
2086 223175 : void OGRSimpleCurve::EndPoint(OGRPoint *poPoint) const
2087 :
2088 : {
2089 223175 : getPoint(nPointCount - 1, poPoint);
2090 223175 : }
2091 :
2092 : /************************************************************************/
2093 : /* Value() */
2094 : /* */
2095 : /* Get an interpolated point at some distance along the curve. */
2096 : /************************************************************************/
2097 :
2098 52 : void OGRSimpleCurve::Value(double dfDistance, OGRPoint *poPoint) const
2099 :
2100 : {
2101 52 : if (dfDistance < 0)
2102 : {
2103 1 : StartPoint(poPoint);
2104 1 : return;
2105 : }
2106 :
2107 51 : double dfLength = 0.0;
2108 :
2109 192 : for (int i = 0; i < nPointCount - 1; i++)
2110 : {
2111 191 : const double dfDeltaX = paoPoints[i + 1].x - paoPoints[i].x;
2112 191 : const double dfDeltaY = paoPoints[i + 1].y - paoPoints[i].y;
2113 : const double dfSegLength =
2114 191 : sqrt(dfDeltaX * dfDeltaX + dfDeltaY * dfDeltaY);
2115 :
2116 191 : if (dfSegLength > 0)
2117 : {
2118 171 : if ((dfLength <= dfDistance) &&
2119 171 : ((dfLength + dfSegLength) >= dfDistance))
2120 : {
2121 50 : double dfRatio = (dfDistance - dfLength) / dfSegLength;
2122 :
2123 50 : poPoint->setX(paoPoints[i].x * (1 - dfRatio) +
2124 50 : paoPoints[i + 1].x * dfRatio);
2125 50 : poPoint->setY(paoPoints[i].y * (1 - dfRatio) +
2126 50 : paoPoints[i + 1].y * dfRatio);
2127 :
2128 50 : if (getCoordinateDimension() == 3)
2129 1 : poPoint->setZ(padfZ[i] * (1 - dfRatio) +
2130 1 : padfZ[i + 1] * dfRatio);
2131 :
2132 50 : return;
2133 : }
2134 :
2135 121 : dfLength += dfSegLength;
2136 : }
2137 : }
2138 :
2139 1 : EndPoint(poPoint);
2140 : }
2141 :
2142 : /************************************************************************/
2143 : /* Project() */
2144 : /* */
2145 : /* Return distance of point projected on line from origin of this line. */
2146 : /************************************************************************/
2147 :
2148 : /**
2149 : * \brief Project point on linestring.
2150 : *
2151 : * The input point projected on linestring. This is the shortest distance
2152 : * from point to the linestring. The distance from begin of linestring to
2153 : * the point projection returned.
2154 : *
2155 : * This method is built on the GEOS library. Check it for the
2156 : * definition of the geometry operation.
2157 : * If OGR is built without the GEOS library, this method will always return -1,
2158 : * issuing a CPLE_NotSupported error.
2159 : *
2160 : * @return a distance from the begin of the linestring to the projected point.
2161 : */
2162 :
2163 62 : double OGRSimpleCurve::Project(const OGRPoint *poPoint) const
2164 :
2165 : {
2166 62 : double dfResult = -1;
2167 : #ifndef HAVE_GEOS
2168 : CPL_IGNORE_RET_VAL(poPoint);
2169 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
2170 : return dfResult;
2171 : #else
2172 62 : GEOSGeom hThisGeosGeom = nullptr;
2173 62 : GEOSGeom hPointGeosGeom = nullptr;
2174 :
2175 62 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
2176 62 : hThisGeosGeom = exportToGEOS(hGEOSCtxt);
2177 62 : hPointGeosGeom = poPoint->exportToGEOS(hGEOSCtxt);
2178 62 : if (hThisGeosGeom != nullptr && hPointGeosGeom != nullptr)
2179 : {
2180 62 : dfResult = GEOSProject_r(hGEOSCtxt, hThisGeosGeom, hPointGeosGeom);
2181 : }
2182 62 : GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
2183 62 : GEOSGeom_destroy_r(hGEOSCtxt, hPointGeosGeom);
2184 62 : freeGEOSContext(hGEOSCtxt);
2185 :
2186 62 : return dfResult;
2187 :
2188 : #endif // HAVE_GEOS
2189 : }
2190 :
2191 : /************************************************************************/
2192 : /* getSubLine() */
2193 : /* */
2194 : /* Extracts a portion of this OGRLineString into a new OGRLineString. */
2195 : /************************************************************************/
2196 :
2197 : /**
2198 : * \brief Get the portion of linestring.
2199 : *
2200 : * The portion of the linestring extracted to new one. The input distances
2201 : * (maybe present as ratio of length of linestring) set begin and end of
2202 : * extracted portion.
2203 : *
2204 : * @param dfDistanceFrom The distance from the origin of linestring, where the
2205 : * subline should begins
2206 : * @param dfDistanceTo The distance from the origin of linestring, where the
2207 : * subline should ends
2208 : * @param bAsRatio The flag indicating that distances are the ratio of the
2209 : * linestring length.
2210 : *
2211 : * @return a newly allocated linestring now owned by the caller, or NULL on
2212 : * failure.
2213 : *
2214 : * @since OGR 1.11.0
2215 : */
2216 :
2217 53 : OGRLineString *OGRSimpleCurve::getSubLine(double dfDistanceFrom,
2218 : double dfDistanceTo,
2219 : int bAsRatio) const
2220 :
2221 : {
2222 106 : auto poNewLineString = std::make_unique<OGRLineString>();
2223 :
2224 53 : poNewLineString->assignSpatialReference(getSpatialReference());
2225 53 : poNewLineString->setCoordinateDimension(getCoordinateDimension());
2226 :
2227 53 : const double dfLen = get_Length();
2228 53 : if (bAsRatio == TRUE)
2229 : {
2230 : // Convert to real distance.
2231 0 : dfDistanceFrom *= dfLen;
2232 0 : dfDistanceTo *= dfLen;
2233 : }
2234 :
2235 53 : if (dfDistanceFrom < 0)
2236 0 : dfDistanceFrom = 0;
2237 53 : if (dfDistanceTo > dfLen)
2238 0 : dfDistanceTo = dfLen;
2239 :
2240 53 : if (dfDistanceFrom > dfDistanceTo || dfDistanceFrom >= dfLen)
2241 : {
2242 0 : CPLError(CE_Failure, CPLE_IllegalArg, "Input distances are invalid.");
2243 :
2244 0 : return nullptr;
2245 : }
2246 :
2247 53 : double dfLength = 0.0;
2248 :
2249 : // Get first point.
2250 :
2251 53 : int i = 0; // Used after if blocks.
2252 53 : if (dfDistanceFrom == 0)
2253 : {
2254 : bool bRet;
2255 5 : if (getCoordinateDimension() == 3)
2256 0 : bRet = poNewLineString->addPoint(paoPoints[0].x, paoPoints[0].y,
2257 0 : padfZ[0]);
2258 : else
2259 5 : bRet = poNewLineString->addPoint(paoPoints[0].x, paoPoints[0].y);
2260 5 : if (!bRet)
2261 0 : return nullptr;
2262 : }
2263 : else
2264 : {
2265 367 : for (i = 0; i < nPointCount - 1; i++)
2266 : {
2267 367 : const double dfDeltaX = paoPoints[i + 1].x - paoPoints[i].x;
2268 367 : const double dfDeltaY = paoPoints[i + 1].y - paoPoints[i].y;
2269 : const double dfSegLength =
2270 367 : sqrt(dfDeltaX * dfDeltaX + dfDeltaY * dfDeltaY);
2271 :
2272 367 : if (dfSegLength > 0)
2273 : {
2274 367 : if ((dfLength <= dfDistanceFrom) &&
2275 367 : ((dfLength + dfSegLength) >= dfDistanceFrom))
2276 : {
2277 48 : double dfRatio = (dfDistanceFrom - dfLength) / dfSegLength;
2278 :
2279 48 : double dfX = paoPoints[i].x * (1 - dfRatio) +
2280 48 : paoPoints[i + 1].x * dfRatio;
2281 48 : double dfY = paoPoints[i].y * (1 - dfRatio) +
2282 48 : paoPoints[i + 1].y * dfRatio;
2283 :
2284 : bool bRet;
2285 48 : if (getCoordinateDimension() == 3)
2286 : {
2287 0 : bRet = poNewLineString->addPoint(
2288 : dfX, dfY,
2289 0 : padfZ[i] * (1 - dfRatio) + padfZ[i + 1] * dfRatio);
2290 : }
2291 : else
2292 : {
2293 48 : bRet = poNewLineString->addPoint(dfX, dfY);
2294 : }
2295 48 : if (!bRet)
2296 0 : return nullptr;
2297 :
2298 : // Check if dfDistanceTo is in same segment.
2299 48 : if (dfLength <= dfDistanceTo &&
2300 48 : (dfLength + dfSegLength) >= dfDistanceTo)
2301 : {
2302 27 : dfRatio = (dfDistanceTo - dfLength) / dfSegLength;
2303 :
2304 27 : dfX = paoPoints[i].x * (1 - dfRatio) +
2305 27 : paoPoints[i + 1].x * dfRatio;
2306 27 : dfY = paoPoints[i].y * (1 - dfRatio) +
2307 27 : paoPoints[i + 1].y * dfRatio;
2308 :
2309 27 : if (getCoordinateDimension() == 3)
2310 : {
2311 0 : bRet = poNewLineString->addPoint(
2312 : dfX, dfY,
2313 0 : padfZ[i] * (1 - dfRatio) +
2314 0 : padfZ[i + 1] * dfRatio);
2315 : }
2316 : else
2317 : {
2318 27 : bRet = poNewLineString->addPoint(dfX, dfY);
2319 : }
2320 :
2321 27 : if (!bRet || poNewLineString->getNumPoints() < 2)
2322 : {
2323 0 : return nullptr;
2324 : }
2325 :
2326 27 : return poNewLineString.release();
2327 : }
2328 21 : i++;
2329 21 : dfLength += dfSegLength;
2330 21 : break;
2331 : }
2332 :
2333 319 : dfLength += dfSegLength;
2334 : }
2335 : }
2336 : }
2337 :
2338 : // Add points.
2339 55 : for (; i < nPointCount - 1; i++)
2340 : {
2341 : bool bRet;
2342 55 : if (getCoordinateDimension() == 3)
2343 0 : bRet = poNewLineString->addPoint(paoPoints[i].x, paoPoints[i].y,
2344 0 : padfZ[i]);
2345 : else
2346 55 : bRet = poNewLineString->addPoint(paoPoints[i].x, paoPoints[i].y);
2347 55 : if (!bRet)
2348 0 : return nullptr;
2349 :
2350 55 : const double dfDeltaX = paoPoints[i + 1].x - paoPoints[i].x;
2351 55 : const double dfDeltaY = paoPoints[i + 1].y - paoPoints[i].y;
2352 : const double dfSegLength =
2353 55 : sqrt(dfDeltaX * dfDeltaX + dfDeltaY * dfDeltaY);
2354 :
2355 55 : if (dfSegLength > 0)
2356 : {
2357 55 : if ((dfLength <= dfDistanceTo) &&
2358 55 : ((dfLength + dfSegLength) >= dfDistanceTo))
2359 : {
2360 26 : const double dfRatio = (dfDistanceTo - dfLength) / dfSegLength;
2361 :
2362 26 : const double dfX = paoPoints[i].x * (1 - dfRatio) +
2363 26 : paoPoints[i + 1].x * dfRatio;
2364 26 : const double dfY = paoPoints[i].y * (1 - dfRatio) +
2365 26 : paoPoints[i + 1].y * dfRatio;
2366 :
2367 26 : if (getCoordinateDimension() == 3)
2368 0 : bRet = poNewLineString->addPoint(
2369 : dfX, dfY,
2370 0 : padfZ[i] * (1 - dfRatio) + padfZ[i + 1] * dfRatio);
2371 : else
2372 26 : bRet = poNewLineString->addPoint(dfX, dfY);
2373 26 : if (!bRet)
2374 0 : return nullptr;
2375 :
2376 26 : return poNewLineString.release();
2377 : }
2378 :
2379 29 : dfLength += dfSegLength;
2380 : }
2381 : }
2382 :
2383 : bool bRet;
2384 0 : if (getCoordinateDimension() == 3)
2385 0 : bRet = poNewLineString->addPoint(paoPoints[nPointCount - 1].x,
2386 0 : paoPoints[nPointCount - 1].y,
2387 0 : padfZ[nPointCount - 1]);
2388 : else
2389 0 : bRet = poNewLineString->addPoint(paoPoints[nPointCount - 1].x,
2390 0 : paoPoints[nPointCount - 1].y);
2391 :
2392 0 : if (!bRet || poNewLineString->getNumPoints() < 2)
2393 : {
2394 0 : return nullptr;
2395 : }
2396 :
2397 0 : return poNewLineString.release();
2398 : }
2399 :
2400 : /************************************************************************/
2401 : /* getEnvelope() */
2402 : /************************************************************************/
2403 :
2404 5643780 : void OGRSimpleCurve::getEnvelope(OGREnvelope *psEnvelope) const
2405 :
2406 : {
2407 5643780 : if (IsEmpty())
2408 : {
2409 3 : psEnvelope->MinX = 0.0;
2410 3 : psEnvelope->MaxX = 0.0;
2411 3 : psEnvelope->MinY = 0.0;
2412 3 : psEnvelope->MaxY = 0.0;
2413 3 : return;
2414 : }
2415 :
2416 5643770 : double dfMinX = paoPoints[0].x;
2417 5643770 : double dfMaxX = paoPoints[0].x;
2418 5643770 : double dfMinY = paoPoints[0].y;
2419 5643770 : double dfMaxY = paoPoints[0].y;
2420 :
2421 31868700 : for (int iPoint = 1; iPoint < nPointCount; iPoint++)
2422 : {
2423 26224900 : if (dfMaxX < paoPoints[iPoint].x)
2424 7497660 : dfMaxX = paoPoints[iPoint].x;
2425 26224900 : if (dfMaxY < paoPoints[iPoint].y)
2426 7448110 : dfMaxY = paoPoints[iPoint].y;
2427 26224900 : if (dfMinX > paoPoints[iPoint].x)
2428 4727570 : dfMinX = paoPoints[iPoint].x;
2429 26224900 : if (dfMinY > paoPoints[iPoint].y)
2430 5541440 : dfMinY = paoPoints[iPoint].y;
2431 : }
2432 :
2433 5643770 : psEnvelope->MinX = dfMinX;
2434 5643770 : psEnvelope->MaxX = dfMaxX;
2435 5643770 : psEnvelope->MinY = dfMinY;
2436 5643770 : psEnvelope->MaxY = dfMaxY;
2437 : }
2438 :
2439 : /************************************************************************/
2440 : /* getEnvelope() */
2441 : /************************************************************************/
2442 :
2443 637045 : void OGRSimpleCurve::getEnvelope(OGREnvelope3D *psEnvelope) const
2444 :
2445 : {
2446 637045 : getEnvelope(static_cast<OGREnvelope *>(psEnvelope));
2447 :
2448 637045 : if (IsEmpty() || padfZ == nullptr)
2449 : {
2450 259529 : psEnvelope->MinZ = 0.0;
2451 259529 : psEnvelope->MaxZ = 0.0;
2452 259529 : return;
2453 : }
2454 :
2455 377516 : double dfMinZ = padfZ[0];
2456 377516 : double dfMaxZ = padfZ[0];
2457 :
2458 1549830 : for (int iPoint = 1; iPoint < nPointCount; iPoint++)
2459 : {
2460 1172320 : if (dfMinZ > padfZ[iPoint])
2461 370010 : dfMinZ = padfZ[iPoint];
2462 1172320 : if (dfMaxZ < padfZ[iPoint])
2463 230759 : dfMaxZ = padfZ[iPoint];
2464 : }
2465 :
2466 377516 : psEnvelope->MinZ = dfMinZ;
2467 377516 : psEnvelope->MaxZ = dfMaxZ;
2468 : }
2469 :
2470 : /************************************************************************/
2471 : /* Equals() */
2472 : /************************************************************************/
2473 :
2474 48134 : OGRBoolean OGRSimpleCurve::Equals(const OGRGeometry *poOther) const
2475 :
2476 : {
2477 48134 : if (poOther == this)
2478 1 : return TRUE;
2479 :
2480 48133 : if (poOther->getGeometryType() != getGeometryType())
2481 1 : return FALSE;
2482 :
2483 48132 : if (IsEmpty() && poOther->IsEmpty())
2484 1 : return TRUE;
2485 :
2486 : // TODO(schwehr): Test the SRS.
2487 :
2488 48131 : auto poOLine = poOther->toSimpleCurve();
2489 48131 : if (getNumPoints() != poOLine->getNumPoints())
2490 8 : return FALSE;
2491 :
2492 251715 : for (int iPoint = 0; iPoint < getNumPoints(); iPoint++)
2493 : {
2494 431635 : if (getX(iPoint) != poOLine->getX(iPoint) ||
2495 431635 : getY(iPoint) != poOLine->getY(iPoint) ||
2496 203592 : getZ(iPoint) != poOLine->getZ(iPoint))
2497 14119 : return FALSE;
2498 : }
2499 :
2500 34004 : return TRUE;
2501 : }
2502 :
2503 : /************************************************************************/
2504 : /* transform() */
2505 : /************************************************************************/
2506 :
2507 2331 : OGRErr OGRSimpleCurve::transform(OGRCoordinateTransformation *poCT)
2508 :
2509 : {
2510 : /* -------------------------------------------------------------------- */
2511 : /* Make a copy of the points to operate on, so as to be able to */
2512 : /* keep only valid reprojected points if partial reprojection enabled */
2513 : /* or keeping intact the original geometry if only full reprojection */
2514 : /* allowed. */
2515 : /* -------------------------------------------------------------------- */
2516 : double *xyz = static_cast<double *>(
2517 2331 : VSI_MALLOC_VERBOSE(sizeof(double) * nPointCount * 3));
2518 : int *pabSuccess =
2519 2331 : static_cast<int *>(VSI_CALLOC_VERBOSE(sizeof(int), nPointCount));
2520 2331 : if (xyz == nullptr || pabSuccess == nullptr)
2521 : {
2522 0 : VSIFree(xyz);
2523 0 : VSIFree(pabSuccess);
2524 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2525 : }
2526 :
2527 49149 : for (int i = 0; i < nPointCount; i++)
2528 : {
2529 46818 : xyz[i] = paoPoints[i].x;
2530 46818 : xyz[i + nPointCount] = paoPoints[i].y;
2531 46818 : if (padfZ)
2532 20354 : xyz[i + nPointCount * 2] = padfZ[i];
2533 : else
2534 26464 : xyz[i + nPointCount * 2] = 0.0;
2535 : }
2536 :
2537 : /* -------------------------------------------------------------------- */
2538 : /* Transform and reapply. */
2539 : /* -------------------------------------------------------------------- */
2540 2331 : poCT->Transform(nPointCount, xyz, xyz + nPointCount, xyz + nPointCount * 2,
2541 2331 : nullptr, pabSuccess);
2542 :
2543 2331 : const char *pszEnablePartialReprojection = nullptr;
2544 :
2545 2331 : int j = 0; // Used after for.
2546 49149 : for (int i = 0; i < nPointCount; i++)
2547 : {
2548 46818 : if (pabSuccess[i])
2549 : {
2550 46818 : xyz[j] = xyz[i];
2551 46818 : xyz[j + nPointCount] = xyz[i + nPointCount];
2552 46818 : xyz[j + 2 * nPointCount] = xyz[i + 2 * nPointCount];
2553 46818 : j++;
2554 : }
2555 : else
2556 : {
2557 0 : if (pszEnablePartialReprojection == nullptr)
2558 0 : pszEnablePartialReprojection = CPLGetConfigOption(
2559 : "OGR_ENABLE_PARTIAL_REPROJECTION", nullptr);
2560 0 : if (pszEnablePartialReprojection == nullptr)
2561 : {
2562 : static bool bHasWarned = false;
2563 0 : if (!bHasWarned)
2564 : {
2565 : // Check that there is at least one valid reprojected point
2566 : // and issue an error giving an hint to use
2567 : // OGR_ENABLE_PARTIAL_REPROJECTION.
2568 0 : bool bHasOneValidPoint = j != 0;
2569 0 : for (; i < nPointCount && !bHasOneValidPoint; i++)
2570 : {
2571 0 : if (pabSuccess[i])
2572 0 : bHasOneValidPoint = true;
2573 : }
2574 0 : if (bHasOneValidPoint)
2575 : {
2576 0 : bHasWarned = true;
2577 0 : CPLError(CE_Failure, CPLE_AppDefined,
2578 : "Full reprojection failed, but partial is "
2579 : "possible if you define "
2580 : "OGR_ENABLE_PARTIAL_REPROJECTION "
2581 : "configuration option to TRUE");
2582 : }
2583 : }
2584 :
2585 0 : CPLFree(xyz);
2586 0 : CPLFree(pabSuccess);
2587 0 : return OGRERR_FAILURE;
2588 : }
2589 0 : else if (!CPLTestBool(pszEnablePartialReprojection))
2590 : {
2591 0 : CPLFree(xyz);
2592 0 : CPLFree(pabSuccess);
2593 0 : return OGRERR_FAILURE;
2594 : }
2595 : }
2596 : }
2597 :
2598 2331 : if (j == 0 && nPointCount != 0)
2599 : {
2600 0 : CPLFree(xyz);
2601 0 : CPLFree(pabSuccess);
2602 0 : return OGRERR_FAILURE;
2603 : }
2604 :
2605 2331 : setPoints(j, xyz, xyz + nPointCount,
2606 2331 : (padfZ) ? xyz + nPointCount * 2 : nullptr);
2607 2331 : CPLFree(xyz);
2608 2331 : CPLFree(pabSuccess);
2609 :
2610 2331 : assignSpatialReference(poCT->GetTargetCS());
2611 :
2612 2331 : return OGRERR_NONE;
2613 : }
2614 :
2615 : /************************************************************************/
2616 : /* IsEmpty() */
2617 : /************************************************************************/
2618 :
2619 7766810 : OGRBoolean OGRSimpleCurve::IsEmpty() const
2620 : {
2621 7766810 : return (nPointCount == 0);
2622 : }
2623 :
2624 : /************************************************************************/
2625 : /* OGRSimpleCurve::segmentize() */
2626 : /************************************************************************/
2627 :
2628 63 : bool OGRSimpleCurve::segmentize(double dfMaxLength)
2629 : {
2630 63 : if (dfMaxLength <= 0)
2631 : {
2632 0 : CPLError(CE_Failure, CPLE_AppDefined,
2633 : "dfMaxLength must be strictly positive");
2634 0 : return false;
2635 : }
2636 63 : if (nPointCount < 2)
2637 0 : return true;
2638 :
2639 : // So as to make sure that the same line followed in both directions
2640 : // result in the same segmentized line.
2641 63 : if (paoPoints[0].x < paoPoints[nPointCount - 1].x ||
2642 56 : (paoPoints[0].x == paoPoints[nPointCount - 1].x &&
2643 48 : paoPoints[0].y < paoPoints[nPointCount - 1].y))
2644 : {
2645 13 : reversePoints();
2646 13 : bool bRet = segmentize(dfMaxLength);
2647 13 : reversePoints();
2648 13 : return bRet;
2649 : }
2650 :
2651 50 : int nNewPointCount = 0;
2652 50 : const double dfSquareMaxLength = dfMaxLength * dfMaxLength;
2653 :
2654 : // First pass to compute new number of points
2655 50 : constexpr double REL_EPSILON_LENGTH_SQUARE = 1e-5;
2656 50 : constexpr double REL_EPSILON_ROUND = 1e-2;
2657 707 : for (int i = 0; i < nPointCount; i++)
2658 : {
2659 707 : nNewPointCount++;
2660 :
2661 707 : if (i == nPointCount - 1)
2662 49 : break;
2663 :
2664 : // Must be kept in sync with the second pass loop
2665 658 : const double dfX = paoPoints[i + 1].x - paoPoints[i].x;
2666 658 : const double dfY = paoPoints[i + 1].y - paoPoints[i].y;
2667 658 : const double dfSquareDist = dfX * dfX + dfY * dfY;
2668 658 : if (dfSquareDist - dfSquareMaxLength >
2669 658 : REL_EPSILON_LENGTH_SQUARE * dfSquareMaxLength)
2670 : {
2671 285 : const double dfIntermediatePoints = floor(
2672 285 : sqrt(dfSquareDist / dfSquareMaxLength) - REL_EPSILON_ROUND);
2673 : const int nIntermediatePoints =
2674 285 : DoubleToIntClamp(dfIntermediatePoints);
2675 :
2676 : // TODO(schwehr): Can these be tighter?
2677 : // Limit allocation of paoNewPoints to a few GB of memory.
2678 : // An OGRRawPoint is 2 doubles.
2679 : // kMax is a guess of what a reasonable max might be.
2680 285 : constexpr int kMax = 2 << 26;
2681 285 : if (nNewPointCount > kMax || nIntermediatePoints > kMax)
2682 : {
2683 1 : CPLError(CE_Failure, CPLE_AppDefined,
2684 : "Too many points in a segment: %d or %d",
2685 : nNewPointCount, nIntermediatePoints);
2686 1 : return false;
2687 : }
2688 :
2689 284 : nNewPointCount += nIntermediatePoints;
2690 : }
2691 : }
2692 :
2693 49 : if (nPointCount == nNewPointCount)
2694 8 : return true;
2695 :
2696 : // Allocate new arrays
2697 : OGRRawPoint *paoNewPoints = static_cast<OGRRawPoint *>(
2698 41 : VSI_MALLOC_VERBOSE(sizeof(OGRRawPoint) * nNewPointCount));
2699 41 : if (paoNewPoints == nullptr)
2700 0 : return false;
2701 41 : double *padfNewZ = nullptr;
2702 41 : double *padfNewM = nullptr;
2703 41 : if (padfZ != nullptr)
2704 : {
2705 : padfNewZ = static_cast<double *>(
2706 2 : VSI_MALLOC_VERBOSE(sizeof(double) * nNewPointCount));
2707 2 : if (padfNewZ == nullptr)
2708 : {
2709 0 : VSIFree(paoNewPoints);
2710 0 : return false;
2711 : }
2712 : }
2713 41 : if (padfM != nullptr)
2714 : {
2715 : padfNewM = static_cast<double *>(
2716 2 : VSI_MALLOC_VERBOSE(sizeof(double) * nNewPointCount));
2717 2 : if (padfNewM == nullptr)
2718 : {
2719 0 : VSIFree(paoNewPoints);
2720 0 : VSIFree(padfNewZ);
2721 0 : return false;
2722 : }
2723 : }
2724 :
2725 : // Second pass to fill new arrays
2726 : // Must be kept in sync with the first pass loop
2727 41 : nNewPointCount = 0;
2728 606 : for (int i = 0; i < nPointCount; i++)
2729 : {
2730 606 : paoNewPoints[nNewPointCount] = paoPoints[i];
2731 :
2732 606 : if (padfZ != nullptr)
2733 : {
2734 4 : padfNewZ[nNewPointCount] = padfZ[i];
2735 : }
2736 :
2737 606 : if (padfM != nullptr)
2738 : {
2739 4 : padfNewM[nNewPointCount] = padfM[i];
2740 : }
2741 :
2742 606 : nNewPointCount++;
2743 :
2744 606 : if (i == nPointCount - 1)
2745 41 : break;
2746 :
2747 565 : const double dfX = paoPoints[i + 1].x - paoPoints[i].x;
2748 565 : const double dfY = paoPoints[i + 1].y - paoPoints[i].y;
2749 565 : const double dfSquareDist = dfX * dfX + dfY * dfY;
2750 :
2751 : // Must be kept in sync with the initial pass loop
2752 565 : if (dfSquareDist - dfSquareMaxLength >
2753 565 : REL_EPSILON_LENGTH_SQUARE * dfSquareMaxLength)
2754 : {
2755 282 : const double dfIntermediatePoints = floor(
2756 282 : sqrt(dfSquareDist / dfSquareMaxLength) - REL_EPSILON_ROUND);
2757 : const int nIntermediatePoints =
2758 282 : DoubleToIntClamp(dfIntermediatePoints);
2759 :
2760 21296 : for (int j = 1; j <= nIntermediatePoints; j++)
2761 : {
2762 : // coverity[overflow_const]
2763 21014 : const int newI = nNewPointCount + j - 1;
2764 21014 : paoNewPoints[newI].x =
2765 21014 : paoPoints[i].x + j * dfX / (nIntermediatePoints + 1);
2766 21014 : paoNewPoints[newI].y =
2767 21014 : paoPoints[i].y + j * dfY / (nIntermediatePoints + 1);
2768 21014 : if (padfZ != nullptr)
2769 : {
2770 : // No interpolation.
2771 10 : padfNewZ[newI] = padfZ[i];
2772 : }
2773 21014 : if (padfM != nullptr)
2774 : {
2775 : // No interpolation.
2776 2 : padfNewM[newI] = padfM[i];
2777 : }
2778 : }
2779 :
2780 282 : nNewPointCount += nIntermediatePoints;
2781 : }
2782 : }
2783 :
2784 41 : CPLFree(paoPoints);
2785 41 : paoPoints = paoNewPoints;
2786 41 : nPointCount = nNewPointCount;
2787 41 : m_nPointCapacity = nNewPointCount;
2788 :
2789 41 : if (padfZ != nullptr)
2790 : {
2791 2 : CPLFree(padfZ);
2792 2 : padfZ = padfNewZ;
2793 : }
2794 41 : if (padfM != nullptr)
2795 : {
2796 2 : CPLFree(padfM);
2797 2 : padfM = padfNewM;
2798 : }
2799 41 : return true;
2800 : }
2801 :
2802 : /************************************************************************/
2803 : /* swapXY() */
2804 : /************************************************************************/
2805 :
2806 94 : void OGRSimpleCurve::swapXY()
2807 : {
2808 626 : for (int i = 0; i < nPointCount; i++)
2809 : {
2810 532 : std::swap(paoPoints[i].x, paoPoints[i].y);
2811 : }
2812 94 : }
2813 :
2814 : /************************************************************************/
2815 : /* OGRSimpleCurvePointIterator */
2816 : /************************************************************************/
2817 :
2818 : class OGRSimpleCurvePointIterator final : public OGRPointIterator
2819 : {
2820 : CPL_DISALLOW_COPY_ASSIGN(OGRSimpleCurvePointIterator)
2821 :
2822 : const OGRSimpleCurve *poSC = nullptr;
2823 : int iCurPoint = 0;
2824 :
2825 : public:
2826 169 : explicit OGRSimpleCurvePointIterator(const OGRSimpleCurve *poSCIn)
2827 169 : : poSC(poSCIn)
2828 : {
2829 169 : }
2830 :
2831 : OGRBoolean getNextPoint(OGRPoint *p) override;
2832 : };
2833 :
2834 : /************************************************************************/
2835 : /* getNextPoint() */
2836 : /************************************************************************/
2837 :
2838 697 : OGRBoolean OGRSimpleCurvePointIterator::getNextPoint(OGRPoint *p)
2839 : {
2840 697 : if (iCurPoint >= poSC->getNumPoints())
2841 133 : return FALSE;
2842 564 : poSC->getPoint(iCurPoint, p);
2843 564 : iCurPoint++;
2844 564 : return TRUE;
2845 : }
2846 :
2847 : /************************************************************************/
2848 : /* getPointIterator() */
2849 : /************************************************************************/
2850 :
2851 169 : OGRPointIterator *OGRSimpleCurve::getPointIterator() const
2852 : {
2853 169 : return new OGRSimpleCurvePointIterator(this);
2854 : }
2855 :
2856 : /************************************************************************/
2857 : /* OGRLineString( const OGRLineString& ) */
2858 : /************************************************************************/
2859 :
2860 : /**
2861 : * \brief Copy constructor.
2862 : *
2863 : * Note: before GDAL 2.1, only the default implementation of the constructor
2864 : * existed, which could be unsafe to use.
2865 : *
2866 : * @since GDAL 2.1
2867 : */
2868 :
2869 : OGRLineString::OGRLineString(const OGRLineString &) = default;
2870 :
2871 : /************************************************************************/
2872 : /* OGRLineString( OGRLineString&& ) */
2873 : /************************************************************************/
2874 :
2875 : /**
2876 : * \brief Move constructor.
2877 : *
2878 : * @since GDAL 3.11
2879 : */
2880 :
2881 : OGRLineString::OGRLineString(OGRLineString &&) = default;
2882 :
2883 : /************************************************************************/
2884 : /* operator=( const OGRLineString& ) */
2885 : /************************************************************************/
2886 :
2887 : /**
2888 : * \brief Assignment operator.
2889 : *
2890 : * Note: before GDAL 2.1, only the default implementation of the operator
2891 : * existed, which could be unsafe to use.
2892 : *
2893 : * @since GDAL 2.1
2894 : */
2895 :
2896 9 : OGRLineString &OGRLineString::operator=(const OGRLineString &other)
2897 : {
2898 9 : if (this != &other)
2899 : {
2900 8 : OGRSimpleCurve::operator=(other);
2901 : }
2902 9 : return *this;
2903 : }
2904 :
2905 : /************************************************************************/
2906 : /* operator=( OGRLineString&& ) */
2907 : /************************************************************************/
2908 :
2909 : /**
2910 : * \brief Move assignment operator.
2911 : *
2912 : * @since GDAL 3.11
2913 : */
2914 :
2915 4 : OGRLineString &OGRLineString::operator=(OGRLineString &&other)
2916 : {
2917 4 : if (this != &other)
2918 : {
2919 4 : OGRSimpleCurve::operator=(std::move(other));
2920 : }
2921 4 : return *this;
2922 : }
2923 :
2924 : /************************************************************************/
2925 : /* getGeometryType() */
2926 : /************************************************************************/
2927 :
2928 846493 : OGRwkbGeometryType OGRLineString::getGeometryType() const
2929 :
2930 : {
2931 846493 : if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
2932 44081 : return wkbLineStringZM;
2933 802412 : else if (flags & OGR_G_MEASURED)
2934 1188 : return wkbLineStringM;
2935 801224 : else if (flags & OGR_G_3D)
2936 147543 : return wkbLineString25D;
2937 : else
2938 653681 : return wkbLineString;
2939 : }
2940 :
2941 : /************************************************************************/
2942 : /* getGeometryName() */
2943 : /************************************************************************/
2944 :
2945 10543 : const char *OGRLineString::getGeometryName() const
2946 :
2947 : {
2948 10543 : return "LINESTRING";
2949 : }
2950 :
2951 : /************************************************************************/
2952 : /* curveToLine() */
2953 : /************************************************************************/
2954 :
2955 952 : OGRLineString *OGRLineString::CurveToLine(
2956 : CPL_UNUSED double /* dfMaxAngleStepSizeDegrees */,
2957 : CPL_UNUSED const char *const * /* papszOptions */) const
2958 : {
2959 952 : return clone();
2960 : }
2961 :
2962 : /************************************************************************/
2963 : /* get_LinearArea() */
2964 : /************************************************************************/
2965 :
2966 : /**
2967 : * \brief Compute area of ring / closed linestring.
2968 : *
2969 : * The area is computed according to Green's Theorem:
2970 : *
2971 : * Area is "Sum(x(i)*(y(i+1) - y(i-1)))/2" for i = 0 to pointCount-1,
2972 : * assuming the last point is a duplicate of the first.
2973 : *
2974 : * @return computed area.
2975 : */
2976 :
2977 61797 : double OGRSimpleCurve::get_LinearArea() const
2978 :
2979 : {
2980 123589 : if (nPointCount < 2 ||
2981 61796 : (WkbSize() != 0 && /* if not a linearring, check it is closed */
2982 60 : (paoPoints[0].x != paoPoints[nPointCount - 1].x ||
2983 59 : paoPoints[0].y != paoPoints[nPointCount - 1].y)))
2984 : {
2985 2 : return 0;
2986 : }
2987 :
2988 61791 : double dfAreaSum =
2989 61791 : paoPoints[0].x * (paoPoints[1].y - paoPoints[nPointCount - 1].y);
2990 :
2991 3360220 : for (int i = 1; i < nPointCount - 1; i++)
2992 : {
2993 3298430 : dfAreaSum += paoPoints[i].x * (paoPoints[i + 1].y - paoPoints[i - 1].y);
2994 : }
2995 :
2996 61791 : dfAreaSum += paoPoints[nPointCount - 1].x *
2997 61791 : (paoPoints[0].y - paoPoints[nPointCount - 2].y);
2998 :
2999 61791 : return 0.5 * fabs(dfAreaSum);
3000 : }
3001 :
3002 : /************************************************************************/
3003 : /* getCurveGeometry() */
3004 : /************************************************************************/
3005 :
3006 : OGRGeometry *
3007 3198 : OGRLineString::getCurveGeometry(const char *const *papszOptions) const
3008 : {
3009 3198 : return OGRGeometryFactory::curveFromLineString(this, papszOptions);
3010 : }
3011 :
3012 : /************************************************************************/
3013 : /* TransferMembersAndDestroy() */
3014 : /************************************************************************/
3015 : //! @cond Doxygen_Suppress
3016 590 : OGRLineString *OGRLineString::TransferMembersAndDestroy(OGRLineString *poSrc,
3017 : OGRLineString *poDst)
3018 : {
3019 590 : if (poSrc->Is3D())
3020 101 : poDst->flags |= OGR_G_3D;
3021 590 : if (poSrc->IsMeasured())
3022 47 : poDst->flags |= OGR_G_MEASURED;
3023 590 : poDst->assignSpatialReference(poSrc->getSpatialReference());
3024 590 : poDst->nPointCount = poSrc->nPointCount;
3025 590 : poDst->m_nPointCapacity = poSrc->m_nPointCapacity;
3026 590 : poDst->paoPoints = poSrc->paoPoints;
3027 590 : poDst->padfZ = poSrc->padfZ;
3028 590 : poDst->padfM = poSrc->padfM;
3029 590 : poSrc->nPointCount = 0;
3030 590 : poSrc->m_nPointCapacity = 0;
3031 590 : poSrc->paoPoints = nullptr;
3032 590 : poSrc->padfZ = nullptr;
3033 590 : poSrc->padfM = nullptr;
3034 590 : delete poSrc;
3035 590 : return poDst;
3036 : }
3037 :
3038 : //! @endcond
3039 : /************************************************************************/
3040 : /* CastToLinearRing() */
3041 : /************************************************************************/
3042 :
3043 : /**
3044 : * \brief Cast to linear ring.
3045 : *
3046 : * The passed in geometry is consumed and a new one returned (or NULL in case
3047 : * of failure)
3048 : *
3049 : * @param poLS the input geometry - ownership is passed to the method.
3050 : * @return new geometry.
3051 : */
3052 :
3053 526 : OGRLinearRing *OGRLineString::CastToLinearRing(OGRLineString *poLS)
3054 : {
3055 526 : if (poLS->nPointCount < 2 || !poLS->get_IsClosed())
3056 : {
3057 2 : CPLError(CE_Failure, CPLE_AppDefined,
3058 : "Cannot convert non-closed linestring to linearring");
3059 2 : delete poLS;
3060 2 : return nullptr;
3061 : }
3062 524 : OGRLinearRing *poLR = new OGRLinearRing();
3063 524 : TransferMembersAndDestroy(poLS, poLR);
3064 524 : return poLR;
3065 : }
3066 :
3067 : /************************************************************************/
3068 : /* clone() */
3069 : /************************************************************************/
3070 :
3071 300833 : OGRLineString *OGRLineString::clone() const
3072 : {
3073 300833 : return new (std::nothrow) OGRLineString(*this);
3074 : }
3075 :
3076 : //! @cond Doxygen_Suppress
3077 :
3078 : /************************************************************************/
3079 : /* GetCasterToLineString() */
3080 : /************************************************************************/
3081 :
3082 156 : static OGRLineString *CasterToLineString(OGRCurve *poCurve)
3083 : {
3084 156 : return poCurve->toLineString();
3085 : }
3086 :
3087 156 : OGRCurveCasterToLineString OGRLineString::GetCasterToLineString() const
3088 : {
3089 156 : return ::CasterToLineString;
3090 : }
3091 :
3092 : /************************************************************************/
3093 : /* GetCasterToLinearRing() */
3094 : /************************************************************************/
3095 :
3096 526 : OGRLinearRing *OGRLineString::CasterToLinearRing(OGRCurve *poCurve)
3097 : {
3098 526 : return OGRLineString::CastToLinearRing(poCurve->toLineString());
3099 : }
3100 :
3101 526 : OGRCurveCasterToLinearRing OGRLineString::GetCasterToLinearRing() const
3102 : {
3103 526 : return OGRLineString::CasterToLinearRing;
3104 : }
3105 :
3106 : /************************************************************************/
3107 : /* get_Area() */
3108 : /************************************************************************/
3109 :
3110 61796 : double OGRLineString::get_Area() const
3111 : {
3112 61796 : return get_LinearArea();
3113 : }
3114 :
3115 : /************************************************************************/
3116 : /* GetGeodesicAreaOrLength() */
3117 : /************************************************************************/
3118 :
3119 44 : static bool GetGeodesicAreaOrLength(const OGRLineString *poLS,
3120 : const OGRSpatialReference *poSRSOverride,
3121 : double *pdfArea, double *pdfLength)
3122 : {
3123 44 : if (!poSRSOverride)
3124 11 : poSRSOverride = poLS->getSpatialReference();
3125 :
3126 44 : if (!poSRSOverride)
3127 : {
3128 2 : CPLError(CE_Failure, CPLE_AppDefined,
3129 : "Cannot compute %s on ellipsoid due to missing SRS",
3130 : pdfArea ? "area" : "length");
3131 2 : return false;
3132 : }
3133 :
3134 42 : OGRErr eErr = OGRERR_NONE;
3135 42 : double dfSemiMajor = poSRSOverride->GetSemiMajor(&eErr);
3136 42 : if (eErr != OGRERR_NONE)
3137 2 : return false;
3138 40 : const double dfInvFlattening = poSRSOverride->GetInvFlattening(&eErr);
3139 40 : if (eErr != OGRERR_NONE)
3140 0 : return false;
3141 :
3142 : geod_geodesic g;
3143 40 : geod_init(&g, dfSemiMajor,
3144 : dfInvFlattening != 0 ? 1.0 / dfInvFlattening : 0.0);
3145 :
3146 80 : std::vector<double> adfLat;
3147 80 : std::vector<double> adfLon;
3148 40 : const int nPointCount = poLS->getNumPoints();
3149 40 : adfLat.reserve(nPointCount);
3150 40 : adfLon.reserve(nPointCount);
3151 :
3152 80 : OGRSpatialReference oGeogCRS;
3153 40 : if (oGeogCRS.CopyGeogCSFrom(poSRSOverride) != OGRERR_NONE)
3154 : {
3155 0 : CPLError(CE_Failure, CPLE_AppDefined,
3156 : "Cannot reproject geometry to geographic CRS");
3157 0 : return false;
3158 : }
3159 40 : oGeogCRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
3160 : auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
3161 80 : OGRCreateCoordinateTransformation(poSRSOverride, &oGeogCRS));
3162 40 : if (!poCT)
3163 : {
3164 0 : CPLError(CE_Failure, CPLE_AppDefined,
3165 : "Cannot reproject geometry to geographic CRS");
3166 0 : return false;
3167 : }
3168 896 : for (int i = 0; i < nPointCount; ++i)
3169 : {
3170 856 : adfLon.push_back(poLS->getX(i));
3171 856 : adfLat.push_back(poLS->getY(i));
3172 : }
3173 : #ifdef __GNUC__
3174 : #pragma GCC diagnostic push
3175 : #pragma GCC diagnostic ignored "-Wnull-dereference"
3176 : #endif
3177 80 : std::vector<int> anSuccess;
3178 40 : anSuccess.resize(adfLon.size());
3179 : #ifdef __GNUC__
3180 : #pragma GCC diagnostic pop
3181 : #endif
3182 40 : poCT->Transform(adfLon.size(), adfLon.data(), adfLat.data(), nullptr,
3183 : anSuccess.data());
3184 : double dfToDegrees =
3185 40 : oGeogCRS.GetAngularUnits(nullptr) / CPLAtof(SRS_UA_DEGREE_CONV);
3186 40 : if (std::fabs(dfToDegrees - 1) <= 1e-10)
3187 40 : dfToDegrees = 1.0;
3188 896 : for (int i = 0; i < nPointCount; ++i)
3189 : {
3190 856 : if (!anSuccess[i])
3191 : {
3192 0 : CPLError(CE_Failure, CPLE_AppDefined,
3193 : "Cannot reproject geometry to geographic CRS");
3194 0 : return false;
3195 : }
3196 856 : adfLon[i] *= dfToDegrees;
3197 856 : adfLat[i] *= dfToDegrees;
3198 : }
3199 :
3200 40 : geod_polygonarea(&g, adfLat.data(), adfLon.data(),
3201 40 : static_cast<int>(adfLat.size()), pdfArea, pdfLength);
3202 40 : return true;
3203 : }
3204 :
3205 : /************************************************************************/
3206 : /* get_GeodesicArea() */
3207 : /************************************************************************/
3208 :
3209 : double
3210 22 : OGRLineString::get_GeodesicArea(const OGRSpatialReference *poSRSOverride) const
3211 : {
3212 22 : double dfArea = 0;
3213 22 : if (!GetGeodesicAreaOrLength(this, poSRSOverride, &dfArea, nullptr))
3214 2 : return -1.0;
3215 20 : return std::fabs(dfArea);
3216 : }
3217 :
3218 : /************************************************************************/
3219 : /* get_GeodesicLength() */
3220 : /************************************************************************/
3221 :
3222 22 : double OGRLineString::get_GeodesicLength(
3223 : const OGRSpatialReference *poSRSOverride) const
3224 : {
3225 22 : double dfLength = 0;
3226 22 : if (!GetGeodesicAreaOrLength(this, poSRSOverride, nullptr, &dfLength))
3227 2 : return -1;
3228 20 : return dfLength;
3229 : }
3230 :
3231 : /************************************************************************/
3232 : /* get_AreaOfCurveSegments() */
3233 : /************************************************************************/
3234 :
3235 31 : double OGRLineString::get_AreaOfCurveSegments() const
3236 : {
3237 31 : return 0;
3238 : }
3239 :
3240 : /************************************************************************/
3241 : /* isClockwise() */
3242 : /************************************************************************/
3243 :
3244 : /**
3245 : * \brief Returns TRUE if the ring has clockwise winding (or less than 2 points)
3246 : *
3247 : * Assumes that the line is closed.
3248 : *
3249 : * @return TRUE if clockwise otherwise FALSE.
3250 : */
3251 :
3252 79654 : int OGRLineString::isClockwise() const
3253 :
3254 : {
3255 : // WARNING: keep in sync OGRLineString::isClockwise(),
3256 : // OGRCurve::isClockwise() and OGRWKBIsClockwiseRing()
3257 :
3258 79654 : if (nPointCount < 2)
3259 1 : return TRUE;
3260 :
3261 79653 : bool bUseFallback = false;
3262 :
3263 : // Find the lowest rightmost vertex.
3264 79653 : int v = 0; // Used after for.
3265 3784680 : for (int i = 1; i < nPointCount - 1; i++)
3266 : {
3267 : // => v < end.
3268 3705030 : if (paoPoints[i].y < paoPoints[v].y ||
3269 3220160 : (paoPoints[i].y == paoPoints[v].y &&
3270 51050 : paoPoints[i].x > paoPoints[v].x))
3271 : {
3272 513492 : v = i;
3273 513492 : bUseFallback = false;
3274 : }
3275 3191540 : else if (paoPoints[i].y == paoPoints[v].y &&
3276 22436 : paoPoints[i].x == paoPoints[v].x)
3277 : {
3278 : // Two vertex with same coordinates are the lowest rightmost
3279 : // vertex. Cannot use that point as the pivot (#5342).
3280 84 : bUseFallback = true;
3281 : }
3282 : }
3283 :
3284 : // Previous.
3285 79653 : int next = v - 1;
3286 79653 : if (next < 0)
3287 : {
3288 28198 : next = nPointCount - 1 - 1;
3289 : }
3290 :
3291 79653 : constexpr double EPSILON = 1.0E-5;
3292 177397 : const auto epsilonEqual = [](double a, double b, double eps)
3293 177397 : { return ::fabs(a - b) < eps; };
3294 :
3295 96013 : if (epsilonEqual(paoPoints[next].x, paoPoints[v].x, EPSILON) &&
3296 16359 : epsilonEqual(paoPoints[next].y, paoPoints[v].y, EPSILON))
3297 : {
3298 : // Don't try to be too clever by retrying with a next point.
3299 : // This can lead to false results as in the case of #3356.
3300 242 : bUseFallback = true;
3301 : }
3302 :
3303 79645 : const double dx0 = paoPoints[next].x - paoPoints[v].x;
3304 79645 : const double dy0 = paoPoints[next].y - paoPoints[v].y;
3305 :
3306 : // Following.
3307 79645 : next = v + 1;
3308 79645 : if (next >= nPointCount - 1)
3309 : {
3310 17999 : next = 0;
3311 : }
3312 :
3313 81390 : if (epsilonEqual(paoPoints[next].x, paoPoints[v].x, EPSILON) &&
3314 1745 : epsilonEqual(paoPoints[next].y, paoPoints[v].y, EPSILON))
3315 : {
3316 : // Don't try to be too clever by retrying with a next point.
3317 : // This can lead to false results as in the case of #3356.
3318 272 : bUseFallback = true;
3319 : }
3320 :
3321 79645 : const double dx1 = paoPoints[next].x - paoPoints[v].x;
3322 79645 : const double dy1 = paoPoints[next].y - paoPoints[v].y;
3323 :
3324 79645 : const double crossproduct = dx1 * dy0 - dx0 * dy1;
3325 :
3326 79645 : if (!bUseFallback)
3327 : {
3328 79264 : if (crossproduct > 0) // CCW
3329 44763 : return FALSE;
3330 34501 : else if (crossproduct < 0) // CW
3331 34470 : return TRUE;
3332 : }
3333 :
3334 : // This is a degenerate case: the extent of the polygon is less than EPSILON
3335 : // or 2 nearly identical points were found.
3336 : // Try with Green Formula as a fallback, but this is not a guarantee
3337 : // as we'll probably be affected by numerical instabilities.
3338 :
3339 412 : double dfSum =
3340 412 : paoPoints[0].x * (paoPoints[1].y - paoPoints[nPointCount - 1].y);
3341 :
3342 45727 : for (int i = 1; i < nPointCount - 1; i++)
3343 : {
3344 45315 : dfSum += paoPoints[i].x * (paoPoints[i + 1].y - paoPoints[i - 1].y);
3345 : }
3346 :
3347 412 : dfSum += paoPoints[nPointCount - 1].x *
3348 412 : (paoPoints[0].y - paoPoints[nPointCount - 2].y);
3349 :
3350 412 : return dfSum < 0;
3351 : }
3352 :
3353 : //! @endcond
|