Coverage Report

Created: 2025-06-13 06:18

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