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