• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 12706066811

10 Jan 2025 08:38AM UTC coverage: 70.084% (-2.5%) from 72.549%
12706066811

Pull #11629

github

web-flow
Merge 9418dc48f into 0df468c56
Pull Request #11629: add uv documentation for python package

563296 of 803749 relevant lines covered (70.08%)

223434.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.15
/ogr/ogrlinestring.cpp
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)
567✔
30
{
31
    if (std::isnan(dfValue))
567✔
32
        return 0;
×
33
    if (dfValue >= std::numeric_limits<int>::max())
567✔
34
        return std::numeric_limits<int>::max();
1✔
35
    if (dfValue <= std::numeric_limits<int>::min())
566✔
36
        return std::numeric_limits<int>::min();
×
37
    return static_cast<int>(dfValue);
566✔
38
}
39

40
}  // namespace
41

42
/************************************************************************/
43
/*                OGRSimpleCurve( const OGRSimpleCurve& )               */
44
/************************************************************************/
45

46
/**
47
 * \brief Copy constructor.
48
 *
49
 * Note: before GDAL 2.1, only the default implementation of the constructor
50
 * existed, which could be unsafe to use.
51
 *
52
 * @since GDAL 2.1
53
 */
54

55
OGRSimpleCurve::OGRSimpleCurve(const OGRSimpleCurve &other)
301,286✔
56
    : OGRCurve(other), nPointCount(0), paoPoints(nullptr), padfZ(nullptr),
57
      padfM(nullptr)
301,286✔
58
{
59
    if (other.nPointCount > 0)
301,286✔
60
        setPoints(other.nPointCount, other.paoPoints, other.padfZ, other.padfM);
301,077✔
61
}
301,286✔
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)
3✔
75
    : OGRCurve(std::move(other)), nPointCount(other.nPointCount),
6✔
76
      m_nPointCapacity(other.m_nPointCapacity), paoPoints(other.paoPoints),
3✔
77
      padfZ(other.padfZ), padfM(other.padfM)
3✔
78
{
79
    other.nPointCount = 0;
3✔
80
    other.m_nPointCapacity = 0;
3✔
81
    other.paoPoints = nullptr;
3✔
82
    other.padfZ = nullptr;
3✔
83
    other.padfM = nullptr;
3✔
84
}
3✔
85

86
// cppcheck-suppress-end accessMoved
87

88
/************************************************************************/
89
/*                          ~OGRSimpleCurve()                           */
90
/************************************************************************/
91

92
OGRSimpleCurve::~OGRSimpleCurve()
3,772,410✔
93

94
{
95
    CPLFree(paoPoints);
3,772,450✔
96
    CPLFree(padfZ);
3,772,440✔
97
    CPLFree(padfM);
3,772,400✔
98
}
3,772,400✔
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)
12✔
114
{
115
    if (this == &other)
12✔
116
        return *this;
×
117

118
    OGRCurve::operator=(other);
12✔
119

120
    setPoints(other.nPointCount, other.paoPoints, other.padfZ, other.padfM);
12✔
121
    flags = other.flags;
12✔
122

123
    return *this;
12✔
124
}
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)
6✔
137
{
138
    if (this != &other)
6✔
139
    {
140
        // cppcheck-suppress-begin accessMoved
141
        OGRCurve::operator=(std::move(other));
6✔
142

143
        nPointCount = other.nPointCount;
6✔
144
        m_nPointCapacity = other.m_nPointCapacity;
6✔
145
        CPLFree(paoPoints);
6✔
146
        paoPoints = other.paoPoints;
6✔
147
        CPLFree(padfZ);
6✔
148
        padfZ = other.padfZ;
6✔
149
        CPLFree(padfM);
6✔
150
        padfM = other.padfM;
6✔
151
        flags = other.flags;
6✔
152
        other.nPointCount = 0;
6✔
153
        other.m_nPointCapacity = 0;
6✔
154
        other.paoPoints = nullptr;
6✔
155
        other.padfZ = nullptr;
6✔
156
        other.padfM = nullptr;
6✔
157
        // cppcheck-suppress-end accessMoved
158
    }
159

160
    return *this;
6✔
161
}
162

163
/************************************************************************/
164
/*                            flattenTo2D()                             */
165
/************************************************************************/
166

167
void OGRSimpleCurve::flattenTo2D()
1,065✔
168

169
{
170
    Make2D();
1,065✔
171
    setMeasured(FALSE);
1,065✔
172
}
1,065✔
173

174
/************************************************************************/
175
/*                               empty()                                */
176
/************************************************************************/
177

178
void OGRSimpleCurve::empty()
14,292✔
179

180
{
181
    setNumPoints(0);
14,292✔
182
}
14,292✔
183

184
/************************************************************************/
185
/*                       setCoordinateDimension()                       */
186
/************************************************************************/
187

188
bool OGRSimpleCurve::setCoordinateDimension(int nNewDimension)
2,180✔
189

190
{
191
    setMeasured(FALSE);
2,180✔
192
    if (nNewDimension == 2)
2,180✔
193
        Make2D();
1,172✔
194
    else if (nNewDimension == 3)
1,008✔
195
        return Make3D();
1,008✔
196
    return true;
1,172✔
197
}
198

199
bool OGRSimpleCurve::set3D(OGRBoolean bIs3D)
119,703✔
200

201
{
202
    if (bIs3D)
119,703✔
203
        return Make3D();
117,235✔
204
    else
205
        Make2D();
2,468✔
206
    return true;
2,468✔
207
}
208

209
bool OGRSimpleCurve::setMeasured(OGRBoolean bIsMeasured)
119,368✔
210

211
{
212
    if (bIsMeasured)
119,368✔
213
        return AddM();
8,192✔
214
    else
215
        RemoveM();
111,176✔
216
    return true;
111,176✔
217
}
218

219
/************************************************************************/
220
/*                              WkbSize()                               */
221
/*                                                                      */
222
/*      Return the size of this object in well known binary             */
223
/*      representation including the byte order, and type information.  */
224
/************************************************************************/
225

226
size_t OGRSimpleCurve::WkbSize() const
92,255✔
227

228
{
229
    return 5 + 4 + 8 * static_cast<size_t>(nPointCount) * CoordinateDimension();
92,255✔
230
}
231

232
//! @cond Doxygen_Suppress
233

234
/************************************************************************/
235
/*                               Make2D()                               */
236
/************************************************************************/
237

238
void OGRSimpleCurve::Make2D()
49,616✔
239

240
{
241
    if (padfZ != nullptr)
49,616✔
242
    {
243
        CPLFree(padfZ);
1,872✔
244
        padfZ = nullptr;
1,872✔
245
    }
246
    flags &= ~OGR_G_3D;
49,616✔
247
}
49,616✔
248

249
/************************************************************************/
250
/*                               Make3D()                               */
251
/************************************************************************/
252

253
bool OGRSimpleCurve::Make3D()
2,776,440✔
254

255
{
256
    if (padfZ == nullptr)
2,776,440✔
257
    {
258
        padfZ = static_cast<double *>(
2,661,660✔
259
            VSI_CALLOC_VERBOSE(sizeof(double), std::max(1, m_nPointCapacity)));
2,661,660✔
260
        if (padfZ == nullptr)
2,661,660✔
261
        {
262
            flags &= ~OGR_G_3D;
×
263
            CPLError(CE_Failure, CPLE_AppDefined,
×
264
                     "OGRSimpleCurve::Make3D() failed");
265
            return false;
×
266
        }
267
    }
268
    flags |= OGR_G_3D;
2,776,440✔
269
    return true;
2,776,440✔
270
}
271

272
/************************************************************************/
273
/*                               RemoveM()                              */
274
/************************************************************************/
275

276
void OGRSimpleCurve::RemoveM()
125,594✔
277

278
{
279
    if (padfM != nullptr)
125,594✔
280
    {
281
        CPLFree(padfM);
521✔
282
        padfM = nullptr;
521✔
283
    }
284
    flags &= ~OGR_G_MEASURED;
125,594✔
285
}
125,594✔
286

287
/************************************************************************/
288
/*                               AddM()                                 */
289
/************************************************************************/
290

291
bool OGRSimpleCurve::AddM()
39,218✔
292

293
{
294
    if (padfM == nullptr)
39,218✔
295
    {
296
        padfM = static_cast<double *>(
34,705✔
297
            VSI_CALLOC_VERBOSE(sizeof(double), std::max(1, m_nPointCapacity)));
34,705✔
298
        if (padfM == nullptr)
34,705✔
299
        {
300
            flags &= ~OGR_G_MEASURED;
×
301
            CPLError(CE_Failure, CPLE_AppDefined,
×
302
                     "OGRSimpleCurve::AddM() failed");
303
            return false;
×
304
        }
305
    }
306
    flags |= OGR_G_MEASURED;
39,218✔
307
    return true;
39,218✔
308
}
309

310
//! @endcond
311

312
/************************************************************************/
313
/*                              getPoint()                              */
314
/************************************************************************/
315

316
/**
317
 * \brief Fetch a point in line string.
318
 *
319
 * This method relates to the SFCOM ILineString::get_Point() method.
320
 *
321
 * @param i the vertex to fetch, from 0 to getNumPoints()-1.
322
 * @param poPoint a point to initialize with the fetched point.
323
 */
324

325
void OGRSimpleCurve::getPoint(int i, OGRPoint *poPoint) const
1,162,340✔
326

327
{
328
    CPLAssert(i >= 0);
1,162,340✔
329
    CPLAssert(i < nPointCount);
1,162,340✔
330
    CPLAssert(poPoint != nullptr);
1,162,340✔
331

332
    poPoint->setX(paoPoints[i].x);
1,162,340✔
333
    poPoint->setY(paoPoints[i].y);
1,162,330✔
334

335
    if ((flags & OGR_G_3D) && padfZ != nullptr)
1,162,340✔
336
        poPoint->setZ(padfZ[i]);
46,025✔
337
    if ((flags & OGR_G_MEASURED) && padfM != nullptr)
1,162,340✔
338
        poPoint->setM(padfM[i]);
28,415✔
339
}
1,162,340✔
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
692,283✔
394

395
{
396
    if (padfZ != nullptr && iVertex >= 0 && iVertex < nPointCount &&
692,283✔
397
        (flags & OGR_G_3D))
253,422✔
398
        return (padfZ[iVertex]);
253,422✔
399
    else
400
        return 0.0;
438,861✔
401
}
402

403
/************************************************************************/
404
/*                                getM()                                */
405
/************************************************************************/
406

407
/**
408
 * \brief Get measure at vertex.
409
 *
410
 * Returns the M (measure) value at the indicated vertex.  If no M
411
 * value is available, 0.0 is returned.
412
 *
413
 * @param iVertex the vertex to return, between 0 and getNumPoints()-1.
414
 *
415
 * @return M value.
416
 */
417

418
double OGRSimpleCurve::getM(int iVertex) const
2,660✔
419

420
{
421
    if (padfM != nullptr && iVertex >= 0 && iVertex < nPointCount &&
2,660✔
422
        (flags & OGR_G_MEASURED))
2,660✔
423
        return (padfM[iVertex]);
2,660✔
424
    else
425
        return 0.0;
×
426
}
427

428
/************************************************************************/
429
/*                            setNumPoints()                            */
430
/************************************************************************/
431

432
/**
433
 * \brief Set number of points in geometry.
434
 *
435
 * This method primary exists to preset the number of points in a linestring
436
 * geometry before setPoint() is used to assign them to avoid reallocating
437
 * the array larger with each call to addPoint().
438
 *
439
 * This method has no SFCOM analog.
440
 *
441
 * @param nNewPointCount the new number of points for geometry.
442
 * @param bZeroizeNewContent whether to set to zero the new elements of arrays
443
 *                           that are extended.
444
 * @return (since 3.10) true in case of success, false in case of memory allocation error
445
 */
446

447
bool OGRSimpleCurve::setNumPoints(int nNewPointCount, int bZeroizeNewContent)
21,583,900✔
448

449
{
450
    CPLAssert(nNewPointCount >= 0);
21,583,900✔
451

452
    if (nNewPointCount > m_nPointCapacity)
21,583,900✔
453
    {
454
        // Overflow of sizeof(OGRRawPoint) * nNewPointCount can only occur on
455
        // 32 bit, but we don't really want to allocate 2 billion points even on
456
        // 64 bit...
457
        if (nNewPointCount > std::numeric_limits<int>::max() /
8,670,330✔
458
                                 static_cast<int>(sizeof(OGRRawPoint)))
459
        {
460
            CPLError(CE_Failure, CPLE_IllegalArg,
2✔
461
                     "Too many points on line/curve (%d points exceeds the "
462
                     "limit of %d points)",
463
                     nNewPointCount,
464
                     std::numeric_limits<int>::max() /
12✔
465
                         static_cast<int>(sizeof(OGRRawPoint)));
466
            return false;
2✔
467
        }
468

469
        // If first allocation, just aim for nNewPointCount
470
        // Otherwise aim for nNewPointCount + nNewPointCount / 3 to have
471
        // exponential growth.
472
        const int nNewCapacity =
473
            (nPointCount == 0 ||
13,576,300✔
474
             nNewPointCount > std::numeric_limits<int>::max() /
4,905,990✔
475
                                      static_cast<int>(sizeof(OGRRawPoint)) -
4,905,990✔
476
                                  nNewPointCount / 3)
4,905,990✔
477
                ? nNewPointCount
8,670,310✔
478
                : nNewPointCount + nNewPointCount / 3;
4,905,990✔
479

480
        if (nPointCount == 0 && paoPoints)
8,670,310✔
481
        {
482
            // If there was an allocated array, but the old number of points is
483
            // 0, then free the arrays before allocating them, to avoid
484
            // potential costly recopy of useless data.
485
            VSIFree(paoPoints);
10✔
486
            paoPoints = nullptr;
10✔
487
            VSIFree(padfZ);
10✔
488
            padfZ = nullptr;
10✔
489
            VSIFree(padfM);
10✔
490
            padfM = nullptr;
10✔
491
            m_nPointCapacity = 0;
10✔
492
        }
493

494
        OGRRawPoint *paoNewPoints = static_cast<OGRRawPoint *>(
495
            VSI_REALLOC_VERBOSE(paoPoints, sizeof(OGRRawPoint) * nNewCapacity));
8,670,310✔
496
        if (paoNewPoints == nullptr)
8,670,320✔
497
        {
498
            return false;
×
499
        }
500
        paoPoints = paoNewPoints;
8,670,320✔
501

502
        if (flags & OGR_G_3D)
8,670,320✔
503
        {
504
            double *padfNewZ = static_cast<double *>(
505
                VSI_REALLOC_VERBOSE(padfZ, sizeof(double) * nNewCapacity));
3,865,280✔
506
            if (padfNewZ == nullptr)
3,865,280✔
507
            {
508
                return false;
×
509
            }
510
            padfZ = padfNewZ;
3,865,280✔
511
        }
512

513
        if (flags & OGR_G_MEASURED)
8,670,320✔
514
        {
515
            double *padfNewM = static_cast<double *>(
516
                VSI_REALLOC_VERBOSE(padfM, sizeof(double) * nNewCapacity));
4,522✔
517
            if (padfNewM == nullptr)
4,522✔
518
            {
519
                return false;
×
520
            }
521
            padfM = padfNewM;
4,522✔
522
        }
523

524
        m_nPointCapacity = nNewCapacity;
8,670,320✔
525
    }
526

527
    if (nNewPointCount > nPointCount && bZeroizeNewContent)
21,583,900✔
528
    {
529
        // gcc 8.0 (dev) complains about -Wclass-memaccess since
530
        // OGRRawPoint() has a constructor. So use a void* pointer.  Doing
531
        // the memset() here is correct since the constructor sets to 0.  We
532
        // could instead use a std::fill(), but at every other place, we
533
        // treat this class as a regular POD (see above use of realloc())
534
        void *dest = static_cast<void *>(paoPoints + nPointCount);
19,507,900✔
535
        memset(dest, 0, sizeof(OGRRawPoint) * (nNewPointCount - nPointCount));
19,507,900✔
536

537
        if ((flags & OGR_G_3D) && padfZ)
19,507,900✔
538
            memset(padfZ + nPointCount, 0,
5,503,410✔
539
                   sizeof(double) * (nNewPointCount - nPointCount));
5,503,410✔
540

541
        if ((flags & OGR_G_MEASURED) && padfM)
19,507,900✔
542
            memset(padfM + nPointCount, 0,
409✔
543
                   sizeof(double) * (nNewPointCount - nPointCount));
409✔
544
    }
545

546
    nPointCount = nNewPointCount;
21,583,900✔
547
    return true;
21,583,900✔
548
}
549

550
/************************************************************************/
551
/*                              setPoint()                              */
552
/************************************************************************/
553

554
/**
555
 * \brief Set the location of a vertex in line string.
556
 *
557
 * If iPoint is larger than the number of necessary the number of existing
558
 * points in the line string, the point count will be increased to
559
 * accommodate the request.
560
 *
561
 * There is no SFCOM analog to this method.
562
 *
563
 * @param iPoint the index of the vertex to assign (zero based).
564
 * @param poPoint the value to assign to the vertex.
565
 * @return (since 3.10) true in case of success, false in case of memory allocation error
566
 */
567

568
bool OGRSimpleCurve::setPoint(int iPoint, OGRPoint *poPoint)
1,605✔
569

570
{
571
    if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
1,605✔
572
        return setPoint(iPoint, poPoint->getX(), poPoint->getY(),
59✔
573
                        poPoint->getZ(), poPoint->getM());
59✔
574
    else if (flags & OGR_G_3D)
1,546✔
575
        return setPoint(iPoint, poPoint->getX(), poPoint->getY(),
863✔
576
                        poPoint->getZ());
863✔
577
    else if (flags & OGR_G_MEASURED)
683✔
578
        return setPointM(iPoint, poPoint->getX(), poPoint->getY(),
3✔
579
                         poPoint->getM());
3✔
580
    else
581
        return setPoint(iPoint, poPoint->getX(), poPoint->getY());
680✔
582
}
583

584
/************************************************************************/
585
/*                           CheckPointCount()                          */
586
/************************************************************************/
587

588
static inline bool CheckPointCount(int iPoint)
19,488,200✔
589
{
590
    if (iPoint == std::numeric_limits<int>::max())
19,488,200✔
591
    {
592
        CPLError(CE_Failure, CPLE_AppDefined, "Too big point count.");
×
593
        return false;
1✔
594
    }
595
    return true;
19,488,200✔
596
}
597

598
/************************************************************************/
599
/*                              setPoint()                              */
600
/************************************************************************/
601

602
/**
603
 * \brief Set the location of a vertex in line string.
604
 *
605
 * If iPoint is larger than the number of necessary the number of existing
606
 * points in the line string, the point count will be increased to
607
 * accommodate the request.
608
 *
609
 * There is no SFCOM analog to this method.
610
 *
611
 * @param iPoint the index of the vertex to assign (zero based).
612
 * @param xIn input X coordinate to assign.
613
 * @param yIn input Y coordinate to assign.
614
 * @param zIn input Z coordinate to assign (defaults to zero).
615
 * @return (since 3.10) true in case of success, false in case of memory allocation error
616
 */
617

618
bool OGRSimpleCurve::setPoint(int iPoint, double xIn, double yIn, double zIn)
5,562,730✔
619

620
{
621
    if (!(flags & OGR_G_3D))
5,562,730✔
622
    {
623
        if (!Make3D())
1,263,480✔
624
            return false;
×
625
    }
626

627
    if (iPoint >= nPointCount)
5,562,730✔
628
    {
629
        if (!CheckPointCount(iPoint) || !setNumPoints(iPoint + 1))
5,503,150✔
630
            return false;
1✔
631
    }
632
#ifdef DEBUG
633
    if (paoPoints == nullptr)
5,562,730✔
634
        return false;
×
635
#endif
636

637
    paoPoints[iPoint].x = xIn;
5,562,730✔
638
    paoPoints[iPoint].y = yIn;
5,562,730✔
639

640
    if (padfZ != nullptr)
5,562,730✔
641
    {
642
        padfZ[iPoint] = zIn;
5,562,730✔
643
    }
644
    return true;
5,562,730✔
645
}
646

647
/**
648
 * \brief Set the location of a vertex in line string.
649
 *
650
 * If iPoint is larger than the number of necessary the number of existing
651
 * points in the line string, the point count will be increased to
652
 * accommodate the request.
653
 *
654
 * There is no SFCOM analog to this method.
655
 *
656
 * @param iPoint the index of the vertex to assign (zero based).
657
 * @param xIn input X coordinate to assign.
658
 * @param yIn input Y coordinate to assign.
659
 * @param mIn input M coordinate to assign (defaults to zero).
660
 * @return (since 3.10) true in case of success, false in case of memory allocation error
661
 */
662

663
bool OGRSimpleCurve::setPointM(int iPoint, double xIn, double yIn, double mIn)
443✔
664

665
{
666
    if (!(flags & OGR_G_MEASURED))
443✔
667
    {
668
        if (!AddM())
108✔
669
            return false;
×
670
    }
671

672
    if (iPoint >= nPointCount)
443✔
673
    {
674
        if (!CheckPointCount(iPoint) || !setNumPoints(iPoint + 1))
6✔
675
            return false;
×
676
    }
677
#ifdef DEBUG
678
    if (paoPoints == nullptr)
443✔
679
        return false;
×
680
#endif
681

682
    paoPoints[iPoint].x = xIn;
443✔
683
    paoPoints[iPoint].y = yIn;
443✔
684

685
    if (padfM != nullptr)
443✔
686
    {
687
        padfM[iPoint] = mIn;
443✔
688
    }
689
    return true;
443✔
690
}
691

692
/**
693
 * \brief Set the location of a vertex in line string.
694
 *
695
 * If iPoint is larger than the number of necessary the number of existing
696
 * points in the line string, the point count will be increased to
697
 * accommodate the request.
698
 *
699
 * There is no SFCOM analog to this method.
700
 *
701
 * @param iPoint the index of the vertex to assign (zero based).
702
 * @param xIn input X coordinate to assign.
703
 * @param yIn input Y coordinate to assign.
704
 * @param zIn input Z coordinate to assign (defaults to zero).
705
 * @param mIn input M coordinate to assign (defaults to zero).
706
 * @return (since 3.10) true in case of success, false in case of memory allocation error
707
 */
708

709
bool OGRSimpleCurve::setPoint(int iPoint, double xIn, double yIn, double zIn,
852✔
710
                              double mIn)
711

712
{
713
    if (!(flags & OGR_G_3D))
852✔
714
    {
715
        if (!Make3D())
271✔
716
            return false;
×
717
    }
718
    if (!(flags & OGR_G_MEASURED))
852✔
719
    {
720
        if (!AddM())
284✔
721
            return false;
×
722
    }
723

724
    if (iPoint >= nPointCount)
852✔
725
    {
726
        if (!CheckPointCount(iPoint) || !setNumPoints(iPoint + 1))
261✔
727
            return false;
×
728
    }
729
#ifdef DEBUG
730
    if (paoPoints == nullptr)
852✔
731
        return false;
×
732
#endif
733

734
    paoPoints[iPoint].x = xIn;
852✔
735
    paoPoints[iPoint].y = yIn;
852✔
736

737
    if (padfZ != nullptr)
852✔
738
    {
739
        padfZ[iPoint] = zIn;
852✔
740
    }
741
    if (padfM != nullptr)
852✔
742
    {
743
        padfM[iPoint] = mIn;
852✔
744
    }
745
    return true;
852✔
746
}
747

748
/**
749
 * \brief Set the location of a vertex in line string.
750
 *
751
 * If iPoint is larger than the number of necessary the number of existing
752
 * points in the line string, the point count will be increased to
753
 * accommodate the request.
754
 *
755
 * There is no SFCOM analog to this method.
756
 *
757
 * @param iPoint the index of the vertex to assign (zero based).
758
 * @param xIn input X coordinate to assign.
759
 * @param yIn input Y coordinate to assign.
760
 * @return (since 3.10) true in case of success, false in case of memory allocation error
761
 */
762

763
bool OGRSimpleCurve::setPoint(int iPoint, double xIn, double yIn)
27,669,800✔
764

765
{
766
    if (iPoint >= nPointCount)
27,669,800✔
767
    {
768
        if (!CheckPointCount(iPoint) || !setNumPoints(iPoint + 1) || !paoPoints)
13,984,800✔
769
            return false;
2✔
770
    }
771

772
    paoPoints[iPoint].x = xIn;
27,669,800✔
773
    paoPoints[iPoint].y = yIn;
27,669,800✔
774
    return true;
27,669,800✔
775
}
776

777
/************************************************************************/
778
/*                                setZ()                                */
779
/************************************************************************/
780

781
/**
782
 * \brief Set the Z of a vertex in line string.
783
 *
784
 * If iPoint is larger than the number of necessary the number of existing
785
 * points in the line string, the point count will be increased to
786
 * accommodate the request.
787
 *
788
 * There is no SFCOM analog to this method.
789
 *
790
 * @param iPoint the index of the vertex to assign (zero based).
791
 * @param zIn input Z coordinate to assign.
792
 * @return (since 3.10) true in case of success, false in case of memory allocation error
793
 */
794

795
bool OGRSimpleCurve::setZ(int iPoint, double zIn)
7,010✔
796
{
797
    if (getCoordinateDimension() == 2)
7,010✔
798
    {
799
        if (!Make3D())
840✔
800
            return false;
×
801
    }
802

803
    if (iPoint >= nPointCount)
7,010✔
804
    {
805
        if (!CheckPointCount(iPoint) || !setNumPoints(iPoint + 1))
×
806
            return false;
×
807
    }
808

809
    if (padfZ != nullptr)
7,010✔
810
        padfZ[iPoint] = zIn;
7,010✔
811
    return true;
7,010✔
812
}
813

814
/************************************************************************/
815
/*                                setM()                                */
816
/************************************************************************/
817

818
/**
819
 * \brief Set the M of a vertex in line string.
820
 *
821
 * If iPoint is larger than the number of necessary the number of existing
822
 * points in the line string, the point count will be increased to
823
 * accommodate the request.
824
 *
825
 * There is no SFCOM analog to this method.
826
 *
827
 * @param iPoint the index of the vertex to assign (zero based).
828
 * @param mIn input M coordinate to assign.
829
 * @return (since 3.10) true in case of success, false in case of memory allocation error
830
 */
831

832
bool OGRSimpleCurve::setM(int iPoint, double mIn)
835✔
833
{
834
    if (!(flags & OGR_G_MEASURED))
835✔
835
    {
836
        if (!AddM())
103✔
837
            return false;
×
838
    }
839

840
    if (iPoint >= nPointCount)
835✔
841
    {
842
        if (!CheckPointCount(iPoint) || !setNumPoints(iPoint + 1))
×
843
            return false;
×
844
    }
845

846
    if (padfM != nullptr)
835✔
847
        padfM[iPoint] = mIn;
835✔
848
    return true;
835✔
849
}
850

851
/************************************************************************/
852
/*                              addPoint()                              */
853
/************************************************************************/
854

855
/**
856
 * \brief Add a point to a line string.
857
 *
858
 * The vertex count of the line string is increased by one, and assigned from
859
 * the passed location value.
860
 *
861
 * There is no SFCOM analog to this method.
862
 *
863
 * @param poPoint the point to assign to the new vertex.
864
 * @return (since 3.10) true in case of success, false in case of memory allocation error
865
 */
866

867
bool OGRSimpleCurve::addPoint(const OGRPoint *poPoint)
5,021,190✔
868

869
{
870
    if (poPoint->Is3D() && poPoint->IsMeasured())
5,021,190✔
871
        return setPoint(nPointCount, poPoint->getX(), poPoint->getY(),
250✔
872
                        poPoint->getZ(), poPoint->getM());
250✔
873
    else if (poPoint->Is3D())
5,020,940✔
874
        return setPoint(nPointCount, poPoint->getX(), poPoint->getY(),
4,986,920✔
875
                        poPoint->getZ());
4,986,920✔
876
    else if (poPoint->IsMeasured())
34,023✔
877
        return setPointM(nPointCount, poPoint->getX(), poPoint->getY(),
×
878
                         poPoint->getM());
×
879
    else
880
        return setPoint(nPointCount, poPoint->getX(), poPoint->getY());
34,023✔
881
}
882

883
/************************************************************************/
884
/*                              addPoint()                              */
885
/************************************************************************/
886

887
/**
888
 * \brief Add a point to a line string.
889
 *
890
 * The vertex count of the line string is increased by one, and assigned from
891
 * the passed location value.
892
 *
893
 * There is no SFCOM analog to this method.
894
 *
895
 * @param x the X coordinate to assign to the new point.
896
 * @param y the Y coordinate to assign to the new point.
897
 * @param z the Z coordinate to assign to the new point (defaults to zero).
898
 * @param m the M coordinate to assign to the new point (defaults to zero).
899
 * @return (since 3.10) true in case of success, false in case of memory allocation error
900
 */
901

902
bool OGRSimpleCurve::addPoint(double x, double y, double z, double m)
11✔
903

904
{
905
    return setPoint(nPointCount, x, y, z, m);
11✔
906
}
907

908
/**
909
 * \brief Add a point to a line string.
910
 *
911
 * The vertex count of the line string is increased by one, and assigned from
912
 * the passed location value.
913
 *
914
 * There is no SFCOM analog to this method.
915
 *
916
 * @param x the X coordinate to assign to the new point.
917
 * @param y the Y coordinate to assign to the new point.
918
 * @param z the Z coordinate to assign to the new point (defaults to zero).
919
 * @return (since 3.10) true in case of success, false in case of memory allocation error
920
 */
921

922
bool OGRSimpleCurve::addPoint(double x, double y, double z)
507,151✔
923

924
{
925
    return setPoint(nPointCount, x, y, z);
507,151✔
926
}
927

928
/**
929
 * \brief Add a point to a line string.
930
 *
931
 * The vertex count of the line string is increased by one, and assigned from
932
 * the passed location value.
933
 *
934
 * There is no SFCOM analog to this method.
935
 *
936
 * @param x the X coordinate to assign to the new point.
937
 * @param y the Y coordinate to assign to the new point.
938
 * @return (since 3.10) true in case of success, false in case of memory allocation error
939
 */
940

941
bool OGRSimpleCurve::addPoint(double x, double y)
13,895,800✔
942

943
{
944
    return setPoint(nPointCount, x, y);
13,895,800✔
945
}
946

947
/**
948
 * \brief Add a point to a line string.
949
 *
950
 * The vertex count of the line string is increased by one, and assigned from
951
 * the passed location value.
952
 *
953
 * There is no SFCOM analog to this method.
954
 *
955
 * @param x the X coordinate to assign to the new point.
956
 * @param y the Y coordinate to assign to the new point.
957
 * @param m the M coordinate to assign to the new point.
958
 * @return (since 3.10) true in case of success, false in case of memory allocation error
959
 */
960

961
bool OGRSimpleCurve::addPointM(double x, double y, double m)
6✔
962

963
{
964
    return setPointM(nPointCount, x, y, m);
6✔
965
}
966

967
/************************************************************************/
968
/*                            removePoint()                             */
969
/************************************************************************/
970

971
/**
972
 * \brief Remove a point from a line string.
973
 *
974
 * There is no SFCOM analog to this method.
975
 *
976
 * @param nIndex Point index
977
 * @since GDAL 3.3
978
 */
979

980
bool OGRSimpleCurve::removePoint(int nIndex)
15✔
981
{
982
    if (nIndex < 0 || nIndex >= nPointCount)
15✔
983
        return false;
4✔
984
    if (nIndex < nPointCount - 1)
11✔
985
    {
986
        memmove(paoPoints + nIndex, paoPoints + nIndex + 1,
7✔
987
                sizeof(OGRRawPoint) * (nPointCount - 1 - nIndex));
7✔
988
        if (padfZ)
7✔
989
        {
990
            memmove(padfZ + nIndex, padfZ + nIndex + 1,
1✔
991
                    sizeof(double) * (nPointCount - 1 - nIndex));
1✔
992
        }
993
        if (padfM)
7✔
994
        {
995
            memmove(padfM + nIndex, padfM + nIndex + 1,
1✔
996
                    sizeof(double) * (nPointCount - 1 - nIndex));
1✔
997
        }
998
    }
999
    nPointCount--;
11✔
1000
    return true;
11✔
1001
}
1002

1003
/************************************************************************/
1004
/*                             setPointsM()                             */
1005
/************************************************************************/
1006

1007
/**
1008
 * \brief Assign all points in a line string.
1009
 *
1010
 * This method clears any existing points assigned to this line string,
1011
 * and assigns a whole new set.  It is the most efficient way of assigning
1012
 * the value of a line string.
1013
 *
1014
 * There is no SFCOM analog to this method.
1015
 *
1016
 * @param nPointsIn number of points being passed in paoPointsIn
1017
 * @param paoPointsIn list of points being assigned.
1018
 * @param padfMIn the M values that go with the points.
1019
 * @return (since 3.10) true in case of success, false in case of memory allocation error
1020
 */
1021

1022
bool OGRSimpleCurve::setPointsM(int nPointsIn, const OGRRawPoint *paoPointsIn,
190✔
1023
                                const double *padfMIn)
1024

1025
{
1026
    if (!setNumPoints(nPointsIn, FALSE)
190✔
1027
#ifdef DEBUG
1028
        || paoPoints == nullptr
190✔
1029
#endif
1030
    )
1031
        return false;
×
1032

1033
    if (nPointsIn)
190✔
1034
        memcpy(paoPoints, paoPointsIn, sizeof(OGRRawPoint) * nPointsIn);
190✔
1035

1036
    /* -------------------------------------------------------------------- */
1037
    /*      Check measures.                                                 */
1038
    /* -------------------------------------------------------------------- */
1039
    if (padfMIn == nullptr && (flags & OGR_G_MEASURED))
190✔
1040
    {
1041
        RemoveM();
×
1042
    }
1043
    else if (padfMIn)
190✔
1044
    {
1045
        if (!AddM())
190✔
1046
            return false;
×
1047
        if (padfM && nPointsIn)
190✔
1048
            memcpy(padfM, padfMIn, sizeof(double) * nPointsIn);
190✔
1049
    }
1050
    return true;
190✔
1051
}
1052

1053
/************************************************************************/
1054
/*                             setPoints()                              */
1055
/************************************************************************/
1056

1057
/**
1058
 * \brief Assign all points in a line string.
1059
 *
1060
 * This method clears any existing points assigned to this line string,
1061
 * and assigns a whole new set.  It is the most efficient way of assigning
1062
 * the value of a line string.
1063
 *
1064
 * There is no SFCOM analog to this method.
1065
 *
1066
 * @param nPointsIn number of points being passed in paoPointsIn
1067
 * @param paoPointsIn list of points being assigned.
1068
 * @param padfZIn the Z values that go with the points.
1069
 * @param padfMIn the M values that go with the points.
1070
 * @return (since 3.10) true in case of success, false in case of memory allocation error
1071
 */
1072

1073
bool OGRSimpleCurve::setPoints(int nPointsIn, const OGRRawPoint *paoPointsIn,
1,900,820✔
1074
                               const double *padfZIn, const double *padfMIn)
1075

1076
{
1077
    if (!setNumPoints(nPointsIn, FALSE)
1,900,820✔
1078
#ifdef DEBUG
1079
        || paoPoints == nullptr
1,900,820✔
1080
#endif
1081
    )
1082
        return false;
89✔
1083

1084
    if (nPointsIn)
1,900,730✔
1085
        memcpy(paoPoints, paoPointsIn, sizeof(OGRRawPoint) * nPointsIn);
1,900,730✔
1086

1087
    /* -------------------------------------------------------------------- */
1088
    /*      Check 2D/3D.                                                    */
1089
    /* -------------------------------------------------------------------- */
1090
    if (padfZIn == nullptr && getCoordinateDimension() > 2)
1,900,730✔
1091
    {
1092
        Make2D();
×
1093
    }
1094
    else if (padfZIn)
1,900,730✔
1095
    {
1096
        if (!Make3D())
1,352,750✔
1097
            return false;
×
1098
        if (padfZ && nPointsIn)
1,352,750✔
1099
            memcpy(padfZ, padfZIn, sizeof(double) * nPointsIn);
1,352,750✔
1100
    }
1101

1102
    /* -------------------------------------------------------------------- */
1103
    /*      Check measures.                                                 */
1104
    /* -------------------------------------------------------------------- */
1105
    if (padfMIn == nullptr && (flags & OGR_G_MEASURED))
1,900,730✔
1106
    {
1107
        RemoveM();
×
1108
    }
1109
    else if (padfMIn)
1,900,730✔
1110
    {
1111
        if (!AddM())
804✔
1112
            return false;
×
1113
        if (padfM && nPointsIn)
804✔
1114
            memcpy(padfM, padfMIn, sizeof(double) * nPointsIn);
804✔
1115
    }
1116
    return true;
1,900,730✔
1117
}
1118

1119
/************************************************************************/
1120
/*                             setPoints()                              */
1121
/************************************************************************/
1122

1123
/**
1124
 * \brief Assign all points in a line string.
1125
 *
1126
 * This method clears any existing points assigned to this line string,
1127
 * and assigns a whole new set.  It is the most efficient way of assigning
1128
 * the value of a line string.
1129
 *
1130
 * There is no SFCOM analog to this method.
1131
 *
1132
 * @param nPointsIn number of points being passed in paoPointsIn
1133
 * @param paoPointsIn list of points being assigned.
1134
 * @param padfZIn the Z values that go with the points (optional, may be NULL).
1135
 * @return (since 3.10) true in case of success, false in case of memory allocation error
1136
 */
1137

1138
bool OGRSimpleCurve::setPoints(int nPointsIn, const OGRRawPoint *paoPointsIn,
20,916✔
1139
                               const double *padfZIn)
1140

1141
{
1142
    if (!setNumPoints(nPointsIn, FALSE)
20,916✔
1143
#ifdef DEBUG
1144
        || paoPoints == nullptr
20,916✔
1145
#endif
1146
    )
1147
        return false;
7✔
1148

1149
    if (nPointsIn)
20,909✔
1150
        memcpy(paoPoints, paoPointsIn, sizeof(OGRRawPoint) * nPointsIn);
20,909✔
1151

1152
    /* -------------------------------------------------------------------- */
1153
    /*      Check 2D/3D.                                                    */
1154
    /* -------------------------------------------------------------------- */
1155
    if (padfZIn == nullptr && getCoordinateDimension() > 2)
20,909✔
1156
    {
1157
        Make2D();
×
1158
    }
1159
    else if (padfZIn)
20,909✔
1160
    {
1161
        if (!Make3D())
1,405✔
1162
            return false;
×
1163
        if (padfZ && nPointsIn)
1,405✔
1164
            memcpy(padfZ, padfZIn, sizeof(double) * nPointsIn);
1,405✔
1165
    }
1166
    return true;
20,909✔
1167
}
1168

1169
/************************************************************************/
1170
/*                             setPoints()                              */
1171
/************************************************************************/
1172

1173
/**
1174
 * \brief Assign all points in a line string.
1175
 *
1176
 * This method clear any existing points assigned to this line string,
1177
 * and assigns a whole new set.
1178
 *
1179
 * There is no SFCOM analog to this method.
1180
 *
1181
 * @param nPointsIn number of points being passed in padfX and padfY.
1182
 * @param padfX list of X coordinates of points being assigned.
1183
 * @param padfY list of Y coordinates of points being assigned.
1184
 * @param padfZIn list of Z coordinates of points being assigned (defaults to
1185
 * NULL for 2D objects).
1186
 * @return (since 3.10) true in case of success, false in case of memory allocation error
1187
 */
1188

1189
bool OGRSimpleCurve::setPoints(int nPointsIn, const double *padfX,
39,355✔
1190
                               const double *padfY, const double *padfZIn)
1191

1192
{
1193
    /* -------------------------------------------------------------------- */
1194
    /*      Check 2D/3D.                                                    */
1195
    /* -------------------------------------------------------------------- */
1196
    if (padfZIn == nullptr)
39,355✔
1197
        Make2D();
36,244✔
1198
    else
1199
    {
1200
        if (!Make3D())
3,111✔
1201
            return false;
×
1202
    }
1203

1204
    /* -------------------------------------------------------------------- */
1205
    /*      Assign values.                                                  */
1206
    /* -------------------------------------------------------------------- */
1207
    if (!setNumPoints(nPointsIn, FALSE))
39,355✔
1208
        return false;
×
1209

1210
    for (int i = 0; i < nPointsIn; i++)
439,711✔
1211
    {
1212
        paoPoints[i].x = padfX[i];
400,356✔
1213
        paoPoints[i].y = padfY[i];
400,356✔
1214
    }
1215

1216
    if (padfZ && padfZIn && nPointsIn)
39,355✔
1217
    {
1218
        memcpy(padfZ, padfZIn, sizeof(double) * nPointsIn);
3,111✔
1219
    }
1220
    return true;
39,355✔
1221
}
1222

1223
/************************************************************************/
1224
/*                             setPointsM()                             */
1225
/************************************************************************/
1226

1227
/**
1228
 * \brief Assign all points in a line string.
1229
 *
1230
 * This method clear any existing points assigned to this line string,
1231
 * and assigns a whole new set.
1232
 *
1233
 * There is no SFCOM analog to this method.
1234
 *
1235
 * @param nPointsIn number of points being passed in padfX and padfY.
1236
 * @param padfX list of X coordinates of points being assigned.
1237
 * @param padfY list of Y coordinates of points being assigned.
1238
 * @param padfMIn list of M coordinates of points being assigned.
1239
 * @return (since 3.10) true in case of success, false in case of memory allocation error
1240
 */
1241

1242
bool OGRSimpleCurve::setPointsM(int nPointsIn, const double *padfX,
22✔
1243
                                const double *padfY, const double *padfMIn)
1244

1245
{
1246
    /* -------------------------------------------------------------------- */
1247
    /*      Check 2D/3D.                                                    */
1248
    /* -------------------------------------------------------------------- */
1249
    if (padfMIn == nullptr)
22✔
1250
        RemoveM();
4✔
1251
    else
1252
    {
1253
        if (!AddM())
18✔
1254
            return false;
×
1255
    }
1256

1257
    /* -------------------------------------------------------------------- */
1258
    /*      Assign values.                                                  */
1259
    /* -------------------------------------------------------------------- */
1260
    if (!setNumPoints(nPointsIn, FALSE))
22✔
1261
        return false;
×
1262

1263
    for (int i = 0; i < nPointsIn; i++)
90✔
1264
    {
1265
        paoPoints[i].x = padfX[i];
68✔
1266
        paoPoints[i].y = padfY[i];
68✔
1267
    }
1268

1269
    if (padfMIn && padfM && nPointsIn)
22✔
1270
    {
1271
        memcpy(padfM, padfMIn, sizeof(double) * nPointsIn);
18✔
1272
    }
1273
    return true;
22✔
1274
}
1275

1276
/************************************************************************/
1277
/*                             setPoints()                              */
1278
/************************************************************************/
1279

1280
/**
1281
 * \brief Assign all points in a line string.
1282
 *
1283
 * This method clear any existing points assigned to this line string,
1284
 * and assigns a whole new set.
1285
 *
1286
 * There is no SFCOM analog to this method.
1287
 *
1288
 * @param nPointsIn number of points being passed in padfX and padfY.
1289
 * @param padfX list of X coordinates of points being assigned.
1290
 * @param padfY list of Y coordinates of points being assigned.
1291
 * @param padfZIn list of Z coordinates of points being assigned.
1292
 * @param padfMIn list of M coordinates of points being assigned.
1293
 * @return (since 3.10) true in case of success, false in case of memory allocation error
1294
 */
1295

1296
bool OGRSimpleCurve::setPoints(int nPointsIn, const double *padfX,
3,504✔
1297
                               const double *padfY, const double *padfZIn,
1298
                               const double *padfMIn)
1299

1300
{
1301
    /* -------------------------------------------------------------------- */
1302
    /*      Check 2D/3D.                                                    */
1303
    /* -------------------------------------------------------------------- */
1304
    if (padfZIn == nullptr)
3,504✔
1305
        Make2D();
66✔
1306
    else
1307
    {
1308
        if (!Make3D())
3,438✔
1309
            return false;
×
1310
    }
1311

1312
    /* -------------------------------------------------------------------- */
1313
    /*      Check measures.                                                 */
1314
    /* -------------------------------------------------------------------- */
1315
    if (padfMIn == nullptr)
3,504✔
1316
        RemoveM();
3,476✔
1317
    else
1318
    {
1319
        if (!AddM())
28✔
1320
            return false;
×
1321
    }
1322

1323
    /* -------------------------------------------------------------------- */
1324
    /*      Assign values.                                                  */
1325
    /* -------------------------------------------------------------------- */
1326
    if (!setNumPoints(nPointsIn, FALSE))
3,504✔
1327
        return false;
×
1328

1329
    for (int i = 0; i < nPointsIn; i++)
66,284✔
1330
    {
1331
        paoPoints[i].x = padfX[i];
62,780✔
1332
        paoPoints[i].y = padfY[i];
62,780✔
1333
    }
1334

1335
    if (padfZ != nullptr && padfZIn && nPointsIn)
3,504✔
1336
        memcpy(padfZ, padfZIn, sizeof(double) * nPointsIn);
3,438✔
1337
    if (padfM != nullptr && padfMIn && nPointsIn)
3,504✔
1338
        memcpy(padfM, padfMIn, sizeof(double) * nPointsIn);
28✔
1339
    return true;
3,504✔
1340
}
1341

1342
/************************************************************************/
1343
/*                          getPoints()                                 */
1344
/************************************************************************/
1345

1346
/**
1347
 * \brief Returns all points of line string.
1348
 *
1349
 * This method copies all points into user list. This list must be at
1350
 * least sizeof(OGRRawPoint) * OGRGeometry::getNumPoints() byte in size.
1351
 * It also copies all Z coordinates.
1352
 *
1353
 * There is no SFCOM analog to this method.
1354
 *
1355
 * @param paoPointsOut a buffer into which the points is written.
1356
 * @param padfZOut the Z values that go with the points (optional, may be NULL).
1357
 */
1358

1359
void OGRSimpleCurve::getPoints(OGRRawPoint *paoPointsOut,
730✔
1360
                               double *padfZOut) const
1361
{
1362
    if (!paoPointsOut || nPointCount == 0)
730✔
1363
        return;
3✔
1364

1365
    memcpy(paoPointsOut, paoPoints, sizeof(OGRRawPoint) * nPointCount);
727✔
1366

1367
    /* -------------------------------------------------------------------- */
1368
    /*      Check 2D/3D.                                                    */
1369
    /* -------------------------------------------------------------------- */
1370
    if (padfZOut)
727✔
1371
    {
1372
        if (padfZ)
198✔
1373
            memcpy(padfZOut, padfZ, sizeof(double) * nPointCount);
196✔
1374
        else
1375
            memset(padfZOut, 0, sizeof(double) * nPointCount);
2✔
1376
    }
1377
}
1378

1379
/**
1380
 * \brief Returns all points of line string.
1381
 *
1382
 * This method copies all points into user arrays. The user provides the
1383
 * stride between 2 consecutive elements of the array.
1384
 *
1385
 * On some CPU architectures, care must be taken so that the arrays are properly
1386
 * aligned.
1387
 *
1388
 * There is no SFCOM analog to this method.
1389
 *
1390
 * @param pabyX a buffer of at least (nXStride * nPointCount) bytes, may be
1391
 * NULL.
1392
 * @param nXStride the number of bytes between 2 elements of pabyX.
1393
 * @param pabyY a buffer of at least (nYStride * nPointCount) bytes, may be
1394
 * NULL.
1395
 * @param nYStride the number of bytes between 2 elements of pabyY.
1396
 * @param pabyZ a buffer of at last size (nZStride * nPointCount) bytes, may be
1397
 * NULL.
1398
 * @param nZStride the number of bytes between 2 elements of pabyZ.
1399
 * @param pabyM a buffer of at last size (nMStride * nPointCount) bytes, may be
1400
 * NULL.
1401
 * @param nMStride the number of bytes between 2 elements of pabyM.
1402
 *
1403
 * @since OGR 2.1.0
1404
 */
1405

1406
void OGRSimpleCurve::getPoints(void *pabyX, int nXStride, void *pabyY,
186✔
1407
                               int nYStride, void *pabyZ, int nZStride,
1408
                               void *pabyM, int nMStride) const
1409
{
1410
    if (pabyX != nullptr && nXStride == 0)
186✔
1411
        return;
×
1412
    if (pabyY != nullptr && nYStride == 0)
186✔
1413
        return;
×
1414
    if (pabyZ != nullptr && nZStride == 0)
186✔
1415
        return;
×
1416
    if (pabyM != nullptr && nMStride == 0)
186✔
1417
        return;
×
1418
    if (nXStride == sizeof(OGRRawPoint) && nYStride == sizeof(OGRRawPoint) &&
186✔
1419
        static_cast<char *>(pabyY) ==
1420
            static_cast<char *>(pabyX) + sizeof(double) &&
186✔
1421
        (pabyZ == nullptr || nZStride == sizeof(double)))
77✔
1422
    {
1423
        getPoints(static_cast<OGRRawPoint *>(pabyX),
186✔
1424
                  static_cast<double *>(pabyZ));
1425
    }
1426
    else
1427
    {
1428
        for (int i = 0; i < nPointCount; i++)
×
1429
        {
1430
            if (pabyX)
×
1431
                *reinterpret_cast<double *>(static_cast<char *>(pabyX) +
×
1432
                                            i * nXStride) = paoPoints[i].x;
×
1433
            if (pabyY)
×
1434
                *reinterpret_cast<double *>(static_cast<char *>(pabyY) +
×
1435
                                            i * nYStride) = paoPoints[i].y;
×
1436
        }
1437

1438
        if (pabyZ)
×
1439
        {
1440
            if (nZStride == sizeof(double))
×
1441
            {
1442
                if (padfZ)
×
1443
                    memcpy(pabyZ, padfZ, sizeof(double) * nPointCount);
×
1444
                else
1445
                    memset(pabyZ, 0, sizeof(double) * nPointCount);
×
1446
            }
1447
            else
1448
            {
1449
                for (int i = 0; i < nPointCount; i++)
×
1450
                {
1451
                    *reinterpret_cast<double *>(static_cast<char *>(pabyZ) +
×
1452
                                                i * nZStride) =
×
1453
                        (padfZ) ? padfZ[i] : 0.0;
×
1454
                }
1455
            }
1456
        }
1457
    }
1458
    if (pabyM)
186✔
1459
    {
1460
        if (nMStride == sizeof(double))
58✔
1461
        {
1462
            if (padfM)
58✔
1463
                memcpy(pabyM, padfM, sizeof(double) * nPointCount);
58✔
1464
            else
1465
                memset(pabyM, 0, sizeof(double) * nPointCount);
×
1466
        }
1467
        else
1468
        {
1469
            for (int i = 0; i < nPointCount; i++)
×
1470
            {
1471
                *reinterpret_cast<double *>(static_cast<char *>(pabyM) +
×
1472
                                            i * nMStride) =
×
1473
                    (padfM) ? padfM[i] : 0.0;
×
1474
            }
1475
        }
1476
    }
1477
}
1478

1479
/************************************************************************/
1480
/*                           reversePoints()                            */
1481
/************************************************************************/
1482

1483
/**
1484
 * \brief Reverse point order.
1485
 *
1486
 * This method updates the points in this line string in place
1487
 * reversing the point ordering (first for last, etc).
1488
 */
1489

1490
void OGRSimpleCurve::reversePoints()
2,464✔
1491

1492
{
1493
    for (int i = 0; i < nPointCount / 2; i++)
60,962✔
1494
    {
1495
        std::swap(paoPoints[i], paoPoints[nPointCount - i - 1]);
58,498✔
1496
        if (padfZ)
58,498✔
1497
        {
1498
            std::swap(padfZ[i], padfZ[nPointCount - i - 1]);
2,401✔
1499
        }
1500

1501
        if (padfM)
58,498✔
1502
        {
1503
            std::swap(padfM[i], padfM[nPointCount - i - 1]);
6✔
1504
        }
1505
    }
1506
}
2,464✔
1507

1508
/************************************************************************/
1509
/*                          addSubLineString()                          */
1510
/************************************************************************/
1511

1512
/**
1513
 * \brief Add a segment of another linestring to this one.
1514
 *
1515
 * Adds the request range of vertices to the end of this line string
1516
 * in an efficient manner.  If the nStartVertex is larger than the
1517
 * nEndVertex then the vertices will be reversed as they are copied.
1518
 *
1519
 * @param poOtherLine the other OGRLineString.
1520
 * @param nStartVertex the first vertex to copy, defaults to 0 to start
1521
 * with the first vertex in the other linestring.
1522
 * @param nEndVertex the last vertex to copy, defaults to -1 indicating
1523
 * the last vertex of the other line string.
1524
 */
1525

1526
void OGRSimpleCurve::addSubLineString(const OGRLineString *poOtherLine,
9,256✔
1527
                                      int nStartVertex, int nEndVertex)
1528

1529
{
1530
    int nOtherLineNumPoints = poOtherLine->getNumPoints();
9,256✔
1531
    if (nOtherLineNumPoints == 0)
9,256✔
1532
        return;
×
1533

1534
    /* -------------------------------------------------------------------- */
1535
    /*      Do a bit of argument defaulting and validation.                 */
1536
    /* -------------------------------------------------------------------- */
1537
    if (nEndVertex == -1)
9,256✔
1538
        nEndVertex = nOtherLineNumPoints - 1;
6,476✔
1539

1540
    if (nStartVertex < 0 || nEndVertex < 0 ||
9,256✔
1541
        nStartVertex >= nOtherLineNumPoints ||
9,256✔
1542
        nEndVertex >= nOtherLineNumPoints)
1543
    {
1544
        CPLAssert(false);
×
1545
        return;
1546
    }
1547

1548
    /* -------------------------------------------------------------------- */
1549
    /*      Grow this linestring to hold the additional points.             */
1550
    /* -------------------------------------------------------------------- */
1551
    int nOldPoints = nPointCount;
9,256✔
1552
    int nPointsToAdd = std::abs(nEndVertex - nStartVertex) + 1;
9,256✔
1553

1554
    if (!setNumPoints(nPointsToAdd + nOldPoints, FALSE)
9,256✔
1555
#ifdef DEBUG
1556
        || paoPoints == nullptr
9,256✔
1557
#endif
1558
    )
1559
        return;
×
1560

1561
    /* -------------------------------------------------------------------- */
1562
    /*      Copy the x/y points - forward copies use memcpy.                */
1563
    /* -------------------------------------------------------------------- */
1564
    if (nEndVertex >= nStartVertex)
9,256✔
1565
    {
1566
        memcpy(paoPoints + nOldPoints, poOtherLine->paoPoints + nStartVertex,
9,065✔
1567
               sizeof(OGRRawPoint) * nPointsToAdd);
9,065✔
1568
        if (poOtherLine->padfZ != nullptr)
9,065✔
1569
        {
1570
            Make3D();
1,171✔
1571
            if (padfZ != nullptr)
1,171✔
1572
            {
1573
                memcpy(padfZ + nOldPoints, poOtherLine->padfZ + nStartVertex,
1,171✔
1574
                       sizeof(double) * nPointsToAdd);
1,171✔
1575
            }
1576
        }
1577
        if (poOtherLine->padfM != nullptr)
9,065✔
1578
        {
1579
            AddM();
92✔
1580
            if (padfM != nullptr)
92✔
1581
            {
1582
                memcpy(padfM + nOldPoints, poOtherLine->padfM + nStartVertex,
92✔
1583
                       sizeof(double) * nPointsToAdd);
92✔
1584
            }
1585
        }
1586
    }
1587

1588
    /* -------------------------------------------------------------------- */
1589
    /*      Copy the x/y points - reverse copies done double by double.     */
1590
    /* -------------------------------------------------------------------- */
1591
    else
1592
    {
1593
        for (int i = 0; i < nPointsToAdd; i++)
1,480✔
1594
        {
1595
            paoPoints[i + nOldPoints].x =
1,289✔
1596
                poOtherLine->paoPoints[nStartVertex - i].x;
1,289✔
1597
            paoPoints[i + nOldPoints].y =
1,289✔
1598
                poOtherLine->paoPoints[nStartVertex - i].y;
1,289✔
1599
        }
1600

1601
        if (poOtherLine->padfZ != nullptr)
191✔
1602
        {
1603
            Make3D();
×
1604
            if (padfZ != nullptr)
×
1605
            {
1606
                for (int i = 0; i < nPointsToAdd; i++)
×
1607
                {
1608
                    padfZ[i + nOldPoints] =
×
1609
                        poOtherLine->padfZ[nStartVertex - i];
×
1610
                }
1611
            }
1612
        }
1613
        if (poOtherLine->padfM != nullptr)
191✔
1614
        {
1615
            AddM();
×
1616
            if (padfM != nullptr)
×
1617
            {
1618
                for (int i = 0; i < nPointsToAdd; i++)
×
1619
                {
1620
                    padfM[i + nOldPoints] =
×
1621
                        poOtherLine->padfM[nStartVertex - i];
×
1622
                }
1623
            }
1624
        }
1625
    }
1626
}
1627

1628
/************************************************************************/
1629
/*                           importFromWkb()                            */
1630
/*                                                                      */
1631
/*      Initialize from serialized stream in well known binary          */
1632
/*      format.                                                         */
1633
/************************************************************************/
1634

1635
OGRErr OGRSimpleCurve::importFromWkb(const unsigned char *pabyData,
5,303✔
1636
                                     size_t nSize, OGRwkbVariant eWkbVariant,
1637
                                     size_t &nBytesConsumedOut)
1638

1639
{
1640
    OGRwkbByteOrder eByteOrder;
1641
    size_t nDataOffset = 0;
5,303✔
1642
    int nNewNumPoints = 0;
5,303✔
1643

1644
    nBytesConsumedOut = 0;
5,303✔
1645
    OGRErr eErr = importPreambleOfCollectionFromWkb(pabyData, nSize,
5,303✔
1646
                                                    nDataOffset, eByteOrder, 16,
1647
                                                    nNewNumPoints, eWkbVariant);
1648
    if (eErr != OGRERR_NONE)
5,301✔
1649
        return eErr;
203✔
1650

1651
    // Check if the wkb stream buffer is big enough to store
1652
    // fetched number of points.
1653
    const int dim = CoordinateDimension();
5,098✔
1654
    const size_t nPointSize = dim * sizeof(double);
5,097✔
1655
    if (nNewNumPoints < 0 ||
10,195✔
1656
        static_cast<size_t>(nNewNumPoints) >
5,098✔
1657
            std::numeric_limits<size_t>::max() / nPointSize)
5,098✔
1658
    {
1659
        return OGRERR_CORRUPT_DATA;
×
1660
    }
1661
    const size_t nBufferMinSize = nPointSize * nNewNumPoints;
5,097✔
1662

1663
    if (nSize != static_cast<size_t>(-1) && nBufferMinSize > nSize)
5,097✔
1664
    {
1665
        CPLError(CE_Failure, CPLE_AppDefined,
67✔
1666
                 "Length of input WKB is too small");
1667
        return OGRERR_NOT_ENOUGH_DATA;
67✔
1668
    }
1669

1670
    if (!setNumPoints(nNewNumPoints, FALSE))
5,030✔
1671
        return OGRERR_NOT_ENOUGH_MEMORY;
×
1672

1673
    nBytesConsumedOut = 9 + 8 * static_cast<size_t>(nPointCount) *
5,033✔
1674
                                (2 + ((flags & OGR_G_3D) ? 1 : 0) +
5,033✔
1675
                                 ((flags & OGR_G_MEASURED) ? 1 : 0));
5,033✔
1676

1677
    /* -------------------------------------------------------------------- */
1678
    /*      Get the vertex.                                                 */
1679
    /* -------------------------------------------------------------------- */
1680
    if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
5,033✔
1681
    {
1682
        for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
8,832✔
1683
        {
1684
            memcpy(paoPoints + i, pabyData + 9 + i * 32, 16);
5,328✔
1685
            memcpy(padfZ + i, pabyData + 9 + 16 + i * 32, 8);
5,328✔
1686
            memcpy(padfM + i, pabyData + 9 + 24 + i * 32, 8);
5,328✔
1687
        }
3,504✔
1688
    }
1689
    else if (flags & OGR_G_MEASURED)
1,529✔
1690
    {
1691
        for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
252✔
1692
        {
1693
            memcpy(paoPoints + i, pabyData + 9 + i * 24, 16);
185✔
1694
            memcpy(padfM + i, pabyData + 9 + 16 + i * 24, 8);
185✔
1695
        }
1696
    }
1697
    else if (flags & OGR_G_3D)
1,462✔
1698
    {
1699
        for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
576✔
1700
        {
1701
            memcpy(paoPoints + i, pabyData + 9 + i * 24, 16);
413✔
1702
            memcpy(padfZ + i, pabyData + 9 + 16 + i * 24, 8);
413✔
1703
        }
1704
    }
1705
    else if (nPointCount)
1,299✔
1706
    {
1707
        memcpy(paoPoints, pabyData + 9, 16 * static_cast<size_t>(nPointCount));
1,267✔
1708
    }
1709

1710
    /* -------------------------------------------------------------------- */
1711
    /*      Byte swap if needed.                                            */
1712
    /* -------------------------------------------------------------------- */
1713
    if (OGR_SWAP(eByteOrder))
5,033✔
1714
    {
1715
        for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
440✔
1716
        {
1717
            CPL_SWAPDOUBLE(&(paoPoints[i].x));
310✔
1718
            CPL_SWAPDOUBLE(&(paoPoints[i].y));
310✔
1719
        }
1720

1721
        if (flags & OGR_G_3D)
130✔
1722
        {
1723
            for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
14✔
1724
            {
1725
                CPL_SWAPDOUBLE(padfZ + i);
10✔
1726
            }
1727
        }
1728

1729
        if (flags & OGR_G_MEASURED)
130✔
1730
        {
1731
            for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
6✔
1732
            {
1733
                CPL_SWAPDOUBLE(padfM + i);
4✔
1734
            }
1735
        }
1736
    }
1737

1738
    return OGRERR_NONE;
5,033✔
1739
}
1740

1741
/************************************************************************/
1742
/*                            exportToWkb()                             */
1743
/*                                                                      */
1744
/*      Build a well known binary representation of this object.        */
1745
/************************************************************************/
1746

1747
OGRErr OGRSimpleCurve::exportToWkb(unsigned char *pabyData,
9,988✔
1748
                                   const OGRwkbExportOptions *psOptions) const
1749

1750
{
1751
    if (psOptions == nullptr)
9,988✔
1752
    {
1753
        static const OGRwkbExportOptions defaultOptions;
1754
        psOptions = &defaultOptions;
×
1755
    }
1756

1757
    /* -------------------------------------------------------------------- */
1758
    /*      Set the byte order.                                             */
1759
    /* -------------------------------------------------------------------- */
1760
    pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER(
9,988✔
1761
        static_cast<unsigned char>(psOptions->eByteOrder));
1762

1763
    /* -------------------------------------------------------------------- */
1764
    /*      Set the geometry feature type.                                  */
1765
    /* -------------------------------------------------------------------- */
1766
    GUInt32 nGType = getGeometryType();
9,988✔
1767

1768
    if (psOptions->eWkbVariant == wkbVariantPostGIS1)
9,986✔
1769
    {
1770
        nGType = wkbFlatten(nGType);
6✔
1771
        if (Is3D())
6✔
1772
            // Explicitly set wkb25DBit.
1773
            nGType =
1✔
1774
                static_cast<OGRwkbGeometryType>(nGType | wkb25DBitInternalUse);
1✔
1775
        if (IsMeasured())
6✔
1776
            nGType = static_cast<OGRwkbGeometryType>(nGType | 0x40000000);
×
1777
    }
1778
    else if (psOptions->eWkbVariant == wkbVariantIso)
9,980✔
1779
        nGType = getIsoGeometryType();
3,741✔
1780

1781
    if (psOptions->eByteOrder == wkbNDR)
9,986✔
1782
    {
1783
        CPL_LSBPTR32(&nGType);
9,973✔
1784
    }
1785
    else
1786
    {
1787
        CPL_MSBPTR32(&nGType);
13✔
1788
    }
1789

1790
    memcpy(pabyData + 1, &nGType, 4);
9,986✔
1791

1792
    /* -------------------------------------------------------------------- */
1793
    /*      Copy in the data count.                                         */
1794
    /* -------------------------------------------------------------------- */
1795
    memcpy(pabyData + 5, &nPointCount, 4);
9,986✔
1796

1797
    /* -------------------------------------------------------------------- */
1798
    /*      Copy in the raw data.                                           */
1799
    /* -------------------------------------------------------------------- */
1800
    if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
9,986✔
1801
    {
1802
        for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
4,389✔
1803
        {
1804
            memcpy(pabyData + 9 + 32 * i, paoPoints + i, 16);
2,640✔
1805
            memcpy(pabyData + 9 + 16 + 32 * i, padfZ + i, 8);
2,640✔
1806
            memcpy(pabyData + 9 + 24 + 32 * i, padfM + i, 8);
2,640✔
1807
        }
1808
        OGRRoundCoordinatesIEEE754XYValues<32>(
1,749✔
1809
            psOptions->sPrecision.nXYBitPrecision, pabyData + 9, nPointCount);
1,749✔
1810
        OGRRoundCoordinatesIEEE754<32>(psOptions->sPrecision.nZBitPrecision,
1,749✔
1811
                                       pabyData + 9 + 2 * sizeof(uint64_t),
1812
                                       nPointCount);
1,749✔
1813
        OGRRoundCoordinatesIEEE754<32>(psOptions->sPrecision.nMBitPrecision,
1,749✔
1814
                                       pabyData + 9 + 3 * sizeof(uint64_t),
1815
                                       nPointCount);
1,749✔
1816
    }
1817
    else if (flags & OGR_G_MEASURED)
8,237✔
1818
    {
1819
        for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
107✔
1820
        {
1821
            memcpy(pabyData + 9 + 24 * i, paoPoints + i, 16);
74✔
1822
            memcpy(pabyData + 9 + 16 + 24 * i, padfM + i, 8);
74✔
1823
        }
1824
        OGRRoundCoordinatesIEEE754XYValues<24>(
33✔
1825
            psOptions->sPrecision.nXYBitPrecision, pabyData + 9, nPointCount);
33✔
1826
        OGRRoundCoordinatesIEEE754<24>(psOptions->sPrecision.nMBitPrecision,
33✔
1827
                                       pabyData + 9 + 2 * sizeof(uint64_t),
1828
                                       nPointCount);
33✔
1829
    }
1830
    else if (flags & OGR_G_3D)
8,204✔
1831
    {
1832
        for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
63,125✔
1833
        {
1834
            memcpy(pabyData + 9 + 24 * i, paoPoints + i, 16);
59,502✔
1835
            memcpy(pabyData + 9 + 16 + 24 * i, padfZ + i, 8);
59,502✔
1836
        }
1837
        OGRRoundCoordinatesIEEE754XYValues<24>(
3,623✔
1838
            psOptions->sPrecision.nXYBitPrecision, pabyData + 9, nPointCount);
3,623✔
1839
        OGRRoundCoordinatesIEEE754<24>(psOptions->sPrecision.nZBitPrecision,
3,623✔
1840
                                       pabyData + 9 + 2 * sizeof(uint64_t),
1841
                                       nPointCount);
3,623✔
1842
    }
1843
    else if (nPointCount)
4,581✔
1844
    {
1845
        memcpy(pabyData + 9, paoPoints, 16 * static_cast<size_t>(nPointCount));
4,511✔
1846
        OGRRoundCoordinatesIEEE754XYValues<16>(
4,511✔
1847
            psOptions->sPrecision.nXYBitPrecision, pabyData + 9, nPointCount);
4,511✔
1848
    }
1849

1850
    /* -------------------------------------------------------------------- */
1851
    /*      Swap if needed.                                                 */
1852
    /* -------------------------------------------------------------------- */
1853
    if (OGR_SWAP(psOptions->eByteOrder))
9,986✔
1854
    {
1855
        const int nCount = CPL_SWAP32(nPointCount);
13✔
1856
        memcpy(pabyData + 5, &nCount, 4);
13✔
1857

1858
        const size_t nCoords =
1859
            CoordinateDimension() * static_cast<size_t>(nPointCount);
13✔
1860
        for (size_t i = 0; i < nCoords; i++)
175✔
1861
        {
1862
            CPL_SWAP64PTR(pabyData + 9 + 8 * i);
162✔
1863
        }
1864
    }
1865

1866
    return OGRERR_NONE;
9,986✔
1867
}
1868

1869
/************************************************************************/
1870
/*                           importFromWkt()                            */
1871
/*                                                                      */
1872
/*      Instantiate from well known text format.  Currently this is     */
1873
/*      `LINESTRING ( x y, x y, ...)',                                  */
1874
/************************************************************************/
1875

1876
OGRErr OGRSimpleCurve::importFromWkt(const char **ppszInput)
5,206✔
1877

1878
{
1879
    int bHasZ = FALSE;
5,206✔
1880
    int bHasM = FALSE;
5,206✔
1881
    bool bIsEmpty = false;
5,206✔
1882
    const OGRErr eErr =
1883
        importPreambleFromWkt(ppszInput, &bHasZ, &bHasM, &bIsEmpty);
5,206✔
1884
    flags = 0;
5,206✔
1885
    if (eErr != OGRERR_NONE)
5,206✔
1886
        return eErr;
5✔
1887
    if (bHasZ)
5,201✔
1888
        flags |= OGR_G_3D;
302✔
1889
    if (bHasM)
5,201✔
1890
        flags |= OGR_G_MEASURED;
135✔
1891
    if (bIsEmpty)
5,201✔
1892
    {
1893
        return OGRERR_NONE;
85✔
1894
    }
1895

1896
    const char *pszInput = *ppszInput;
5,116✔
1897

1898
    /* -------------------------------------------------------------------- */
1899
    /*      Read the point list.                                            */
1900
    /* -------------------------------------------------------------------- */
1901
    int flagsFromInput = flags;
5,116✔
1902
    nPointCount = 0;
5,116✔
1903

1904
    pszInput =
1905
        OGRWktReadPointsM(pszInput, &paoPoints, &padfZ, &padfM, &flagsFromInput,
5,116✔
1906
                          &m_nPointCapacity, &nPointCount);
1907
    if (pszInput == nullptr)
5,116✔
1908
        return OGRERR_CORRUPT_DATA;
15✔
1909

1910
    if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
5,101✔
1911
    {
1912
        if (!set3D(TRUE))
272✔
1913
            return OGRERR_NOT_ENOUGH_MEMORY;
×
1914
    }
1915
    if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
5,101✔
1916
    {
1917
        if (!setMeasured(TRUE))
×
1918
            return OGRERR_NOT_ENOUGH_MEMORY;
×
1919
    }
1920

1921
    *ppszInput = pszInput;
5,101✔
1922

1923
    return OGRERR_NONE;
5,101✔
1924
}
1925

1926
//! @cond Doxygen_Suppress
1927
/************************************************************************/
1928
/*                        importFromWKTListOnly()                       */
1929
/*                                                                      */
1930
/*      Instantiate from "(x y, x y, ...)"                              */
1931
/************************************************************************/
1932

1933
OGRErr OGRSimpleCurve::importFromWKTListOnly(const char **ppszInput, int bHasZ,
1,413✔
1934
                                             int bHasM,
1935
                                             OGRRawPoint *&paoPointsIn,
1936
                                             int &nMaxPointsIn,
1937
                                             double *&padfZIn)
1938

1939
{
1940
    const char *pszInput = *ppszInput;
1,413✔
1941

1942
    /* -------------------------------------------------------------------- */
1943
    /*      Read the point list.                                            */
1944
    /* -------------------------------------------------------------------- */
1945
    int flagsFromInput = flags;
1,413✔
1946
    int nPointCountRead = 0;
1,413✔
1947
    double *padfMIn = nullptr;
1,413✔
1948
    if (flagsFromInput == 0)  // Flags was not set, this is not called by us.
1,413✔
1949
    {
1950
        if (bHasM)
1,413✔
1951
            flagsFromInput |= OGR_G_MEASURED;
124✔
1952
        if (bHasZ)
1,413✔
1953
            flagsFromInput |= OGR_G_3D;
197✔
1954
    }
1955

1956
    pszInput =
1957
        OGRWktReadPointsM(pszInput, &paoPointsIn, &padfZIn, &padfMIn,
1,413✔
1958
                          &flagsFromInput, &nMaxPointsIn, &nPointCountRead);
1959

1960
    if (pszInput == nullptr)
1,413✔
1961
    {
1962
        CPLFree(padfMIn);
6✔
1963
        return OGRERR_CORRUPT_DATA;
6✔
1964
    }
1965
    if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
1,407✔
1966
    {
1967
        flags |= OGR_G_3D;
364✔
1968
        bHasZ = TRUE;
364✔
1969
    }
1970
    if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
1,407✔
1971
    {
1972
        flags |= OGR_G_MEASURED;
124✔
1973
        bHasM = TRUE;
124✔
1974
    }
1975

1976
    *ppszInput = pszInput;
1,407✔
1977

1978
    if (bHasM && bHasZ)
1,407✔
1979
        setPoints(nPointCountRead, paoPointsIn, padfZIn, padfMIn);
72✔
1980
    else if (bHasM && !bHasZ)
1,335✔
1981
        setPointsM(nPointCountRead, paoPointsIn, padfMIn);
52✔
1982
    else
1983
        setPoints(nPointCountRead, paoPointsIn, padfZIn);
1,283✔
1984

1985
    CPLFree(padfMIn);
1,407✔
1986

1987
    return OGRERR_NONE;
1,407✔
1988
}
1989

1990
//! @endcond
1991

1992
/************************************************************************/
1993
/*                            exportToWkt()                             */
1994
/*                                                                      */
1995
/*      Translate this structure into its well known text format       */
1996
/*      equivalent.  This could be made a lot more CPU efficient.       */
1997
/************************************************************************/
1998

1999
std::string OGRSimpleCurve::exportToWkt(const OGRWktOptions &opts,
3,645✔
2000
                                        OGRErr *err) const
2001
{
2002
    // LINEARRING or LINESTRING or CIRCULARSTRING
2003
    std::string wkt = getGeometryName();
7,290✔
2004
    wkt += wktTypeString(opts.variant);
3,645✔
2005
    if (IsEmpty())
3,645✔
2006
    {
2007
        wkt += "EMPTY";
89✔
2008
    }
2009
    else
2010
    {
2011
        wkt += '(';
3,556✔
2012

2013
        OGRBoolean hasZ = Is3D();
3,556✔
2014
        OGRBoolean hasM =
2015
            (opts.variant != wkbVariantIso ? FALSE : IsMeasured());
3,556✔
2016

2017
        try
2018
        {
2019
            const int nOrdinatesPerVertex =
3,556✔
2020
                2 + ((hasZ) ? 1 : 0) + ((hasM) ? 1 : 0);
3,556✔
2021
            // At least 2 bytes per ordinate: one for the value,
2022
            // and one for the separator...
2023
            wkt.reserve(wkt.size() + 2 * static_cast<size_t>(nPointCount) *
3,556✔
2024
                                         nOrdinatesPerVertex);
3,556✔
2025

2026
            for (int i = 0; i < nPointCount; i++)
35,012✔
2027
            {
2028
                if (i > 0)
31,456✔
2029
                    wkt += ',';
27,900✔
2030

2031
                wkt += OGRMakeWktCoordinateM(
89,372✔
2032
                    paoPoints[i].x, paoPoints[i].y, padfZ ? padfZ[i] : 0.0,
59,494✔
2033
                    padfM ? padfM[i] : 0.0, hasZ, hasM, opts);
62,912✔
2034
            }
2035
            wkt += ')';
3,556✔
2036
        }
2037
        catch (const std::bad_alloc &e)
×
2038
        {
2039
            CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
×
2040
            if (err)
×
2041
                *err = OGRERR_FAILURE;
×
2042
            return std::string();
×
2043
        }
2044
    }
2045
    if (err)
3,645✔
2046
        *err = OGRERR_NONE;
3,636✔
2047
    return wkt;
3,645✔
2048
}
2049

2050
/************************************************************************/
2051
/*                             get_Length()                             */
2052
/*                                                                      */
2053
/*      For now we return a simple euclidean 2D distance.               */
2054
/************************************************************************/
2055

2056
double OGRSimpleCurve::get_Length() const
1,135✔
2057

2058
{
2059
    double dfLength = 0.0;
1,135✔
2060

2061
    for (int i = 0; i < nPointCount - 1; i++)
3,256✔
2062
    {
2063

2064
        const double dfDeltaX = paoPoints[i + 1].x - paoPoints[i].x;
2,121✔
2065
        const double dfDeltaY = paoPoints[i + 1].y - paoPoints[i].y;
2,121✔
2066
        dfLength += sqrt(dfDeltaX * dfDeltaX + dfDeltaY * dfDeltaY);
2,121✔
2067
    }
2068

2069
    return dfLength;
1,135✔
2070
}
2071

2072
/************************************************************************/
2073
/*                             StartPoint()                             */
2074
/************************************************************************/
2075

2076
void OGRSimpleCurve::StartPoint(OGRPoint *poPoint) const
283,684✔
2077

2078
{
2079
    getPoint(0, poPoint);
283,684✔
2080
}
283,683✔
2081

2082
/************************************************************************/
2083
/*                              EndPoint()                              */
2084
/************************************************************************/
2085

2086
void OGRSimpleCurve::EndPoint(OGRPoint *poPoint) const
223,532✔
2087

2088
{
2089
    getPoint(nPointCount - 1, poPoint);
223,532✔
2090
}
223,532✔
2091

2092
/************************************************************************/
2093
/*                               Value()                                */
2094
/*                                                                      */
2095
/*      Get an interpolated point at some distance along the curve.     */
2096
/************************************************************************/
2097

2098
void OGRSimpleCurve::Value(double dfDistance, OGRPoint *poPoint) const
52✔
2099

2100
{
2101
    if (dfDistance < 0)
52✔
2102
    {
2103
        StartPoint(poPoint);
1✔
2104
        return;
1✔
2105
    }
2106

2107
    double dfLength = 0.0;
51✔
2108

2109
    for (int i = 0; i < nPointCount - 1; i++)
192✔
2110
    {
2111
        const double dfDeltaX = paoPoints[i + 1].x - paoPoints[i].x;
191✔
2112
        const double dfDeltaY = paoPoints[i + 1].y - paoPoints[i].y;
191✔
2113
        const double dfSegLength =
2114
            sqrt(dfDeltaX * dfDeltaX + dfDeltaY * dfDeltaY);
191✔
2115

2116
        if (dfSegLength > 0)
191✔
2117
        {
2118
            if ((dfLength <= dfDistance) &&
171✔
2119
                ((dfLength + dfSegLength) >= dfDistance))
171✔
2120
            {
2121
                double dfRatio = (dfDistance - dfLength) / dfSegLength;
50✔
2122

2123
                poPoint->setX(paoPoints[i].x * (1 - dfRatio) +
50✔
2124
                              paoPoints[i + 1].x * dfRatio);
50✔
2125
                poPoint->setY(paoPoints[i].y * (1 - dfRatio) +
50✔
2126
                              paoPoints[i + 1].y * dfRatio);
50✔
2127

2128
                if (getCoordinateDimension() == 3)
50✔
2129
                    poPoint->setZ(padfZ[i] * (1 - dfRatio) +
1✔
2130
                                  padfZ[i + 1] * dfRatio);
1✔
2131

2132
                return;
50✔
2133
            }
2134

2135
            dfLength += dfSegLength;
121✔
2136
        }
2137
    }
2138

2139
    EndPoint(poPoint);
1✔
2140
}
2141

2142
/************************************************************************/
2143
/*                              Project()                               */
2144
/*                                                                      */
2145
/* Return distance of point projected on line from origin of this line. */
2146
/************************************************************************/
2147

2148
/**
2149
 * \brief Project point on linestring.
2150
 *
2151
 * The input point projected on linestring. This is the shortest distance
2152
 * from point to the linestring. The distance from begin of linestring to
2153
 * the point projection returned.
2154
 *
2155
 * This method is built on the GEOS library. Check it for the
2156
 * definition of the geometry operation.
2157
 * If OGR is built without the GEOS library, this method will always return -1,
2158
 * issuing a CPLE_NotSupported error.
2159
 *
2160
 * @return a distance from the begin of the linestring to the projected point.
2161
 */
2162

2163
double OGRSimpleCurve::Project(const OGRPoint *poPoint) const
62✔
2164

2165
{
2166
    double dfResult = -1;
62✔
2167
#ifndef HAVE_GEOS
2168
    CPL_IGNORE_RET_VAL(poPoint);
2169
    CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
2170
    return dfResult;
2171
#else
2172
    GEOSGeom hThisGeosGeom = nullptr;
62✔
2173
    GEOSGeom hPointGeosGeom = nullptr;
62✔
2174

2175
    GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
62✔
2176
    hThisGeosGeom = exportToGEOS(hGEOSCtxt);
62✔
2177
    hPointGeosGeom = poPoint->exportToGEOS(hGEOSCtxt);
62✔
2178
    if (hThisGeosGeom != nullptr && hPointGeosGeom != nullptr)
62✔
2179
    {
2180
        dfResult = GEOSProject_r(hGEOSCtxt, hThisGeosGeom, hPointGeosGeom);
62✔
2181
    }
2182
    GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
62✔
2183
    GEOSGeom_destroy_r(hGEOSCtxt, hPointGeosGeom);
62✔
2184
    freeGEOSContext(hGEOSCtxt);
62✔
2185

2186
    return dfResult;
62✔
2187

2188
#endif  // HAVE_GEOS
2189
}
2190

2191
/************************************************************************/
2192
/*                            getSubLine()                              */
2193
/*                                                                      */
2194
/*  Extracts a portion of this OGRLineString into a new OGRLineString.  */
2195
/************************************************************************/
2196

2197
/**
2198
 * \brief Get the portion of linestring.
2199
 *
2200
 * The portion of the linestring extracted to new one. The input distances
2201
 * (maybe present as ratio of length of linestring) set begin and end of
2202
 * extracted portion.
2203
 *
2204
 * @param dfDistanceFrom The distance from the origin of linestring, where the
2205
 * subline should begins
2206
 * @param dfDistanceTo The distance from the origin of linestring, where the
2207
 * subline should ends
2208
 * @param bAsRatio The flag indicating that distances are the ratio of the
2209
 * linestring length.
2210
 *
2211
 * @return a newly allocated linestring now owned by the caller, or NULL on
2212
 * failure.
2213
 *
2214
 * @since OGR 1.11.0
2215
 */
2216

2217
OGRLineString *OGRSimpleCurve::getSubLine(double dfDistanceFrom,
53✔
2218
                                          double dfDistanceTo,
2219
                                          int bAsRatio) const
2220

2221
{
2222
    auto poNewLineString = std::make_unique<OGRLineString>();
106✔
2223

2224
    poNewLineString->assignSpatialReference(getSpatialReference());
53✔
2225
    poNewLineString->setCoordinateDimension(getCoordinateDimension());
53✔
2226

2227
    const double dfLen = get_Length();
53✔
2228
    if (bAsRatio == TRUE)
53✔
2229
    {
2230
        // Convert to real distance.
2231
        dfDistanceFrom *= dfLen;
×
2232
        dfDistanceTo *= dfLen;
×
2233
    }
2234

2235
    if (dfDistanceFrom < 0)
53✔
2236
        dfDistanceFrom = 0;
×
2237
    if (dfDistanceTo > dfLen)
53✔
2238
        dfDistanceTo = dfLen;
×
2239

2240
    if (dfDistanceFrom > dfDistanceTo || dfDistanceFrom >= dfLen)
53✔
2241
    {
2242
        CPLError(CE_Failure, CPLE_IllegalArg, "Input distances are invalid.");
×
2243

2244
        return nullptr;
×
2245
    }
2246

2247
    double dfLength = 0.0;
53✔
2248

2249
    // Get first point.
2250

2251
    int i = 0;  // Used after if blocks.
53✔
2252
    if (dfDistanceFrom == 0)
53✔
2253
    {
2254
        bool bRet;
2255
        if (getCoordinateDimension() == 3)
5✔
2256
            bRet = poNewLineString->addPoint(paoPoints[0].x, paoPoints[0].y,
×
2257
                                             padfZ[0]);
×
2258
        else
2259
            bRet = poNewLineString->addPoint(paoPoints[0].x, paoPoints[0].y);
5✔
2260
        if (!bRet)
5✔
2261
            return nullptr;
×
2262
    }
2263
    else
2264
    {
2265
        for (i = 0; i < nPointCount - 1; i++)
367✔
2266
        {
2267
            const double dfDeltaX = paoPoints[i + 1].x - paoPoints[i].x;
367✔
2268
            const double dfDeltaY = paoPoints[i + 1].y - paoPoints[i].y;
367✔
2269
            const double dfSegLength =
2270
                sqrt(dfDeltaX * dfDeltaX + dfDeltaY * dfDeltaY);
367✔
2271

2272
            if (dfSegLength > 0)
367✔
2273
            {
2274
                if ((dfLength <= dfDistanceFrom) &&
367✔
2275
                    ((dfLength + dfSegLength) >= dfDistanceFrom))
367✔
2276
                {
2277
                    double dfRatio = (dfDistanceFrom - dfLength) / dfSegLength;
48✔
2278

2279
                    double dfX = paoPoints[i].x * (1 - dfRatio) +
48✔
2280
                                 paoPoints[i + 1].x * dfRatio;
48✔
2281
                    double dfY = paoPoints[i].y * (1 - dfRatio) +
48✔
2282
                                 paoPoints[i + 1].y * dfRatio;
48✔
2283

2284
                    bool bRet;
2285
                    if (getCoordinateDimension() == 3)
48✔
2286
                    {
2287
                        bRet = poNewLineString->addPoint(
×
2288
                            dfX, dfY,
2289
                            padfZ[i] * (1 - dfRatio) + padfZ[i + 1] * dfRatio);
×
2290
                    }
2291
                    else
2292
                    {
2293
                        bRet = poNewLineString->addPoint(dfX, dfY);
48✔
2294
                    }
2295
                    if (!bRet)
48✔
2296
                        return nullptr;
×
2297

2298
                    // Check if dfDistanceTo is in same segment.
2299
                    if (dfLength <= dfDistanceTo &&
48✔
2300
                        (dfLength + dfSegLength) >= dfDistanceTo)
48✔
2301
                    {
2302
                        dfRatio = (dfDistanceTo - dfLength) / dfSegLength;
27✔
2303

2304
                        dfX = paoPoints[i].x * (1 - dfRatio) +
27✔
2305
                              paoPoints[i + 1].x * dfRatio;
27✔
2306
                        dfY = paoPoints[i].y * (1 - dfRatio) +
27✔
2307
                              paoPoints[i + 1].y * dfRatio;
27✔
2308

2309
                        if (getCoordinateDimension() == 3)
27✔
2310
                        {
2311
                            bRet = poNewLineString->addPoint(
×
2312
                                dfX, dfY,
2313
                                padfZ[i] * (1 - dfRatio) +
×
2314
                                    padfZ[i + 1] * dfRatio);
×
2315
                        }
2316
                        else
2317
                        {
2318
                            bRet = poNewLineString->addPoint(dfX, dfY);
27✔
2319
                        }
2320

2321
                        if (!bRet || poNewLineString->getNumPoints() < 2)
27✔
2322
                        {
2323
                            return nullptr;
×
2324
                        }
2325

2326
                        return poNewLineString.release();
27✔
2327
                    }
2328
                    i++;
21✔
2329
                    dfLength += dfSegLength;
21✔
2330
                    break;
21✔
2331
                }
2332

2333
                dfLength += dfSegLength;
319✔
2334
            }
2335
        }
2336
    }
2337

2338
    // Add points.
2339
    for (; i < nPointCount - 1; i++)
55✔
2340
    {
2341
        bool bRet;
2342
        if (getCoordinateDimension() == 3)
55✔
2343
            bRet = poNewLineString->addPoint(paoPoints[i].x, paoPoints[i].y,
×
2344
                                             padfZ[i]);
×
2345
        else
2346
            bRet = poNewLineString->addPoint(paoPoints[i].x, paoPoints[i].y);
55✔
2347
        if (!bRet)
55✔
2348
            return nullptr;
×
2349

2350
        const double dfDeltaX = paoPoints[i + 1].x - paoPoints[i].x;
55✔
2351
        const double dfDeltaY = paoPoints[i + 1].y - paoPoints[i].y;
55✔
2352
        const double dfSegLength =
2353
            sqrt(dfDeltaX * dfDeltaX + dfDeltaY * dfDeltaY);
55✔
2354

2355
        if (dfSegLength > 0)
55✔
2356
        {
2357
            if ((dfLength <= dfDistanceTo) &&
55✔
2358
                ((dfLength + dfSegLength) >= dfDistanceTo))
55✔
2359
            {
2360
                const double dfRatio = (dfDistanceTo - dfLength) / dfSegLength;
26✔
2361

2362
                const double dfX = paoPoints[i].x * (1 - dfRatio) +
26✔
2363
                                   paoPoints[i + 1].x * dfRatio;
26✔
2364
                const double dfY = paoPoints[i].y * (1 - dfRatio) +
26✔
2365
                                   paoPoints[i + 1].y * dfRatio;
26✔
2366

2367
                if (getCoordinateDimension() == 3)
26✔
2368
                    bRet = poNewLineString->addPoint(
×
2369
                        dfX, dfY,
2370
                        padfZ[i] * (1 - dfRatio) + padfZ[i + 1] * dfRatio);
×
2371
                else
2372
                    bRet = poNewLineString->addPoint(dfX, dfY);
26✔
2373
                if (!bRet)
26✔
2374
                    return nullptr;
×
2375

2376
                return poNewLineString.release();
26✔
2377
            }
2378

2379
            dfLength += dfSegLength;
29✔
2380
        }
2381
    }
2382

2383
    bool bRet;
2384
    if (getCoordinateDimension() == 3)
×
2385
        bRet = poNewLineString->addPoint(paoPoints[nPointCount - 1].x,
×
2386
                                         paoPoints[nPointCount - 1].y,
×
2387
                                         padfZ[nPointCount - 1]);
×
2388
    else
2389
        bRet = poNewLineString->addPoint(paoPoints[nPointCount - 1].x,
×
2390
                                         paoPoints[nPointCount - 1].y);
×
2391

2392
    if (!bRet || poNewLineString->getNumPoints() < 2)
×
2393
    {
2394
        return nullptr;
×
2395
    }
2396

2397
    return poNewLineString.release();
×
2398
}
2399

2400
/************************************************************************/
2401
/*                            getEnvelope()                             */
2402
/************************************************************************/
2403

2404
void OGRSimpleCurve::getEnvelope(OGREnvelope *psEnvelope) const
5,644,230✔
2405

2406
{
2407
    if (IsEmpty())
5,644,230✔
2408
    {
2409
        psEnvelope->MinX = 0.0;
3✔
2410
        psEnvelope->MaxX = 0.0;
3✔
2411
        psEnvelope->MinY = 0.0;
3✔
2412
        psEnvelope->MaxY = 0.0;
3✔
2413
        return;
3✔
2414
    }
2415

2416
    double dfMinX = paoPoints[0].x;
5,644,220✔
2417
    double dfMaxX = paoPoints[0].x;
5,644,220✔
2418
    double dfMinY = paoPoints[0].y;
5,644,220✔
2419
    double dfMaxY = paoPoints[0].y;
5,644,220✔
2420

2421
    for (int iPoint = 1; iPoint < nPointCount; iPoint++)
31,877,000✔
2422
    {
2423
        if (dfMaxX < paoPoints[iPoint].x)
26,232,800✔
2424
            dfMaxX = paoPoints[iPoint].x;
7,499,570✔
2425
        if (dfMaxY < paoPoints[iPoint].y)
26,232,800✔
2426
            dfMaxY = paoPoints[iPoint].y;
7,448,790✔
2427
        if (dfMinX > paoPoints[iPoint].x)
26,232,800✔
2428
            dfMinX = paoPoints[iPoint].x;
4,729,660✔
2429
        if (dfMinY > paoPoints[iPoint].y)
26,232,800✔
2430
            dfMinY = paoPoints[iPoint].y;
5,544,350✔
2431
    }
2432

2433
    psEnvelope->MinX = dfMinX;
5,644,220✔
2434
    psEnvelope->MaxX = dfMaxX;
5,644,220✔
2435
    psEnvelope->MinY = dfMinY;
5,644,220✔
2436
    psEnvelope->MaxY = dfMaxY;
5,644,220✔
2437
}
2438

2439
/************************************************************************/
2440
/*                            getEnvelope()                             */
2441
/************************************************************************/
2442

2443
void OGRSimpleCurve::getEnvelope(OGREnvelope3D *psEnvelope) const
637,237✔
2444

2445
{
2446
    getEnvelope(static_cast<OGREnvelope *>(psEnvelope));
637,237✔
2447

2448
    if (IsEmpty() || padfZ == nullptr)
637,237✔
2449
    {
2450
        psEnvelope->MinZ = 0.0;
259,721✔
2451
        psEnvelope->MaxZ = 0.0;
259,721✔
2452
        return;
259,721✔
2453
    }
2454

2455
    double dfMinZ = padfZ[0];
377,516✔
2456
    double dfMaxZ = padfZ[0];
377,516✔
2457

2458
    for (int iPoint = 1; iPoint < nPointCount; iPoint++)
1,549,830✔
2459
    {
2460
        if (dfMinZ > padfZ[iPoint])
1,172,320✔
2461
            dfMinZ = padfZ[iPoint];
370,010✔
2462
        if (dfMaxZ < padfZ[iPoint])
1,172,320✔
2463
            dfMaxZ = padfZ[iPoint];
230,759✔
2464
    }
2465

2466
    psEnvelope->MinZ = dfMinZ;
377,516✔
2467
    psEnvelope->MaxZ = dfMaxZ;
377,516✔
2468
}
2469

2470
/************************************************************************/
2471
/*                               Equals()                               */
2472
/************************************************************************/
2473

2474
OGRBoolean OGRSimpleCurve::Equals(const OGRGeometry *poOther) const
48,061✔
2475

2476
{
2477
    if (poOther == this)
48,061✔
2478
        return TRUE;
1✔
2479

2480
    if (poOther->getGeometryType() != getGeometryType())
48,060✔
2481
        return FALSE;
1✔
2482

2483
    if (IsEmpty() && poOther->IsEmpty())
48,059✔
2484
        return TRUE;
1✔
2485

2486
    // TODO(schwehr): Test the SRS.
2487

2488
    auto poOLine = poOther->toSimpleCurve();
48,058✔
2489
    if (getNumPoints() != poOLine->getNumPoints())
48,058✔
2490
        return FALSE;
8✔
2491

2492
    for (int iPoint = 0; iPoint < getNumPoints(); iPoint++)
251,632✔
2493
    {
2494
        if (getX(iPoint) != poOLine->getX(iPoint) ||
431,524✔
2495
            getY(iPoint) != poOLine->getY(iPoint) ||
431,524✔
2496
            getZ(iPoint) != poOLine->getZ(iPoint))
203,582✔
2497
            return FALSE;
14,047✔
2498
    }
2499

2500
    return TRUE;
34,003✔
2501
}
2502

2503
/************************************************************************/
2504
/*                             transform()                              */
2505
/************************************************************************/
2506

2507
OGRErr OGRSimpleCurve::transform(OGRCoordinateTransformation *poCT)
2,350✔
2508

2509
{
2510
    /* -------------------------------------------------------------------- */
2511
    /*   Make a copy of the points to operate on, so as to be able to       */
2512
    /*   keep only valid reprojected points if partial reprojection enabled */
2513
    /*   or keeping intact the original geometry if only full reprojection  */
2514
    /*   allowed.                                                           */
2515
    /* -------------------------------------------------------------------- */
2516
    double *xyz = static_cast<double *>(
2517
        VSI_MALLOC_VERBOSE(sizeof(double) * nPointCount * 3));
2,350✔
2518
    int *pabSuccess =
2519
        static_cast<int *>(VSI_CALLOC_VERBOSE(sizeof(int), nPointCount));
2,350✔
2520
    if (xyz == nullptr || pabSuccess == nullptr)
2,350✔
2521
    {
2522
        VSIFree(xyz);
×
2523
        VSIFree(pabSuccess);
×
2524
        return OGRERR_NOT_ENOUGH_MEMORY;
×
2525
    }
2526

2527
    for (int i = 0; i < nPointCount; i++)
49,657✔
2528
    {
2529
        xyz[i] = paoPoints[i].x;
47,307✔
2530
        xyz[i + nPointCount] = paoPoints[i].y;
47,307✔
2531
        if (padfZ)
47,307✔
2532
            xyz[i + nPointCount * 2] = padfZ[i];
20,354✔
2533
        else
2534
            xyz[i + nPointCount * 2] = 0.0;
26,953✔
2535
    }
2536

2537
    /* -------------------------------------------------------------------- */
2538
    /*      Transform and reapply.                                          */
2539
    /* -------------------------------------------------------------------- */
2540
    poCT->Transform(nPointCount, xyz, xyz + nPointCount, xyz + nPointCount * 2,
2,350✔
2541
                    nullptr, pabSuccess);
2,350✔
2542

2543
    const char *pszEnablePartialReprojection = nullptr;
2,350✔
2544

2545
    int j = 0;  // Used after for.
2,350✔
2546
    for (int i = 0; i < nPointCount; i++)
49,657✔
2547
    {
2548
        if (pabSuccess[i])
47,307✔
2549
        {
2550
            xyz[j] = xyz[i];
47,307✔
2551
            xyz[j + nPointCount] = xyz[i + nPointCount];
47,307✔
2552
            xyz[j + 2 * nPointCount] = xyz[i + 2 * nPointCount];
47,307✔
2553
            j++;
47,307✔
2554
        }
2555
        else
2556
        {
2557
            if (pszEnablePartialReprojection == nullptr)
×
2558
                pszEnablePartialReprojection = CPLGetConfigOption(
×
2559
                    "OGR_ENABLE_PARTIAL_REPROJECTION", nullptr);
2560
            if (pszEnablePartialReprojection == nullptr)
×
2561
            {
2562
                static bool bHasWarned = false;
2563
                if (!bHasWarned)
×
2564
                {
2565
                    // Check that there is at least one valid reprojected point
2566
                    // and issue an error giving an hint to use
2567
                    // OGR_ENABLE_PARTIAL_REPROJECTION.
2568
                    bool bHasOneValidPoint = j != 0;
×
2569
                    for (; i < nPointCount && !bHasOneValidPoint; i++)
×
2570
                    {
2571
                        if (pabSuccess[i])
×
2572
                            bHasOneValidPoint = true;
×
2573
                    }
2574
                    if (bHasOneValidPoint)
×
2575
                    {
2576
                        bHasWarned = true;
×
2577
                        CPLError(CE_Failure, CPLE_AppDefined,
×
2578
                                 "Full reprojection failed, but partial is "
2579
                                 "possible if you define "
2580
                                 "OGR_ENABLE_PARTIAL_REPROJECTION "
2581
                                 "configuration option to TRUE");
2582
                    }
2583
                }
2584

2585
                CPLFree(xyz);
×
2586
                CPLFree(pabSuccess);
×
2587
                return OGRERR_FAILURE;
×
2588
            }
2589
            else if (!CPLTestBool(pszEnablePartialReprojection))
×
2590
            {
2591
                CPLFree(xyz);
×
2592
                CPLFree(pabSuccess);
×
2593
                return OGRERR_FAILURE;
×
2594
            }
2595
        }
2596
    }
2597

2598
    if (j == 0 && nPointCount != 0)
2,350✔
2599
    {
2600
        CPLFree(xyz);
×
2601
        CPLFree(pabSuccess);
×
2602
        return OGRERR_FAILURE;
×
2603
    }
2604

2605
    setPoints(j, xyz, xyz + nPointCount,
2,350✔
2606
              (padfZ) ? xyz + nPointCount * 2 : nullptr);
2,350✔
2607
    CPLFree(xyz);
2,350✔
2608
    CPLFree(pabSuccess);
2,350✔
2609

2610
    assignSpatialReference(poCT->GetTargetCS());
2,350✔
2611

2612
    return OGRERR_NONE;
2,350✔
2613
}
2614

2615
/************************************************************************/
2616
/*                               IsEmpty()                              */
2617
/************************************************************************/
2618

2619
OGRBoolean OGRSimpleCurve::IsEmpty() const
7,770,860✔
2620
{
2621
    return (nPointCount == 0);
7,770,860✔
2622
}
2623

2624
/************************************************************************/
2625
/*                     OGRSimpleCurve::segmentize()                     */
2626
/************************************************************************/
2627

2628
bool OGRSimpleCurve::segmentize(double dfMaxLength)
63✔
2629
{
2630
    if (dfMaxLength <= 0)
63✔
2631
    {
2632
        CPLError(CE_Failure, CPLE_AppDefined,
×
2633
                 "dfMaxLength must be strictly positive");
2634
        return false;
×
2635
    }
2636
    if (nPointCount < 2)
63✔
2637
        return true;
×
2638

2639
    // So as to make sure that the same line followed in both directions
2640
    // result in the same segmentized line.
2641
    if (paoPoints[0].x < paoPoints[nPointCount - 1].x ||
63✔
2642
        (paoPoints[0].x == paoPoints[nPointCount - 1].x &&
56✔
2643
         paoPoints[0].y < paoPoints[nPointCount - 1].y))
48✔
2644
    {
2645
        reversePoints();
13✔
2646
        bool bRet = segmentize(dfMaxLength);
13✔
2647
        reversePoints();
13✔
2648
        return bRet;
13✔
2649
    }
2650

2651
    int nNewPointCount = 0;
50✔
2652
    const double dfSquareMaxLength = dfMaxLength * dfMaxLength;
50✔
2653

2654
    // First pass to compute new number of points
2655
    constexpr double REL_EPSILON_LENGTH_SQUARE = 1e-5;
50✔
2656
    constexpr double REL_EPSILON_ROUND = 1e-2;
50✔
2657
    for (int i = 0; i < nPointCount; i++)
707✔
2658
    {
2659
        nNewPointCount++;
707✔
2660

2661
        if (i == nPointCount - 1)
707✔
2662
            break;
49✔
2663

2664
        // Must be kept in sync with the second pass loop
2665
        const double dfX = paoPoints[i + 1].x - paoPoints[i].x;
658✔
2666
        const double dfY = paoPoints[i + 1].y - paoPoints[i].y;
658✔
2667
        const double dfSquareDist = dfX * dfX + dfY * dfY;
658✔
2668
        if (dfSquareDist - dfSquareMaxLength >
658✔
2669
            REL_EPSILON_LENGTH_SQUARE * dfSquareMaxLength)
658✔
2670
        {
2671
            const double dfIntermediatePoints = floor(
285✔
2672
                sqrt(dfSquareDist / dfSquareMaxLength) - REL_EPSILON_ROUND);
285✔
2673
            const int nIntermediatePoints =
2674
                DoubleToIntClamp(dfIntermediatePoints);
285✔
2675

2676
            // TODO(schwehr): Can these be tighter?
2677
            // Limit allocation of paoNewPoints to a few GB of memory.
2678
            // An OGRRawPoint is 2 doubles.
2679
            // kMax is a guess of what a reasonable max might be.
2680
            constexpr int kMax = 2 << 26;
285✔
2681
            if (nNewPointCount > kMax || nIntermediatePoints > kMax)
285✔
2682
            {
2683
                CPLError(CE_Failure, CPLE_AppDefined,
1✔
2684
                         "Too many points in a segment: %d or %d",
2685
                         nNewPointCount, nIntermediatePoints);
2686
                return false;
1✔
2687
            }
2688

2689
            nNewPointCount += nIntermediatePoints;
284✔
2690
        }
2691
    }
2692

2693
    if (nPointCount == nNewPointCount)
49✔
2694
        return true;
8✔
2695

2696
    // Allocate new arrays
2697
    OGRRawPoint *paoNewPoints = static_cast<OGRRawPoint *>(
2698
        VSI_MALLOC_VERBOSE(sizeof(OGRRawPoint) * nNewPointCount));
41✔
2699
    if (paoNewPoints == nullptr)
41✔
2700
        return false;
×
2701
    double *padfNewZ = nullptr;
41✔
2702
    double *padfNewM = nullptr;
41✔
2703
    if (padfZ != nullptr)
41✔
2704
    {
2705
        padfNewZ = static_cast<double *>(
2706
            VSI_MALLOC_VERBOSE(sizeof(double) * nNewPointCount));
2✔
2707
        if (padfNewZ == nullptr)
2✔
2708
        {
2709
            VSIFree(paoNewPoints);
×
2710
            return false;
×
2711
        }
2712
    }
2713
    if (padfM != nullptr)
41✔
2714
    {
2715
        padfNewM = static_cast<double *>(
2716
            VSI_MALLOC_VERBOSE(sizeof(double) * nNewPointCount));
2✔
2717
        if (padfNewM == nullptr)
2✔
2718
        {
2719
            VSIFree(paoNewPoints);
×
2720
            VSIFree(padfNewZ);
×
2721
            return false;
×
2722
        }
2723
    }
2724

2725
    // Second pass to fill new arrays
2726
    // Must be kept in sync with the first pass loop
2727
    nNewPointCount = 0;
41✔
2728
    for (int i = 0; i < nPointCount; i++)
606✔
2729
    {
2730
        paoNewPoints[nNewPointCount] = paoPoints[i];
606✔
2731

2732
        if (padfZ != nullptr)
606✔
2733
        {
2734
            padfNewZ[nNewPointCount] = padfZ[i];
4✔
2735
        }
2736

2737
        if (padfM != nullptr)
606✔
2738
        {
2739
            padfNewM[nNewPointCount] = padfM[i];
4✔
2740
        }
2741

2742
        nNewPointCount++;
606✔
2743

2744
        if (i == nPointCount - 1)
606✔
2745
            break;
41✔
2746

2747
        const double dfX = paoPoints[i + 1].x - paoPoints[i].x;
565✔
2748
        const double dfY = paoPoints[i + 1].y - paoPoints[i].y;
565✔
2749
        const double dfSquareDist = dfX * dfX + dfY * dfY;
565✔
2750

2751
        // Must be kept in sync with the initial pass loop
2752
        if (dfSquareDist - dfSquareMaxLength >
565✔
2753
            REL_EPSILON_LENGTH_SQUARE * dfSquareMaxLength)
565✔
2754
        {
2755
            const double dfIntermediatePoints = floor(
282✔
2756
                sqrt(dfSquareDist / dfSquareMaxLength) - REL_EPSILON_ROUND);
282✔
2757
            const int nIntermediatePoints =
2758
                DoubleToIntClamp(dfIntermediatePoints);
282✔
2759
            const double dfRatioX =
282✔
2760
                dfX / (static_cast<double>(nIntermediatePoints) + 1);
282✔
2761
            const double dfRatioY =
282✔
2762
                dfY / (static_cast<double>(nIntermediatePoints) + 1);
282✔
2763

2764
            for (int j = 1; j <= nIntermediatePoints; j++)
21,296✔
2765
            {
2766
                // coverity[overflow_const]
2767
                const int newI = nNewPointCount + j - 1;
21,014✔
2768
                paoNewPoints[newI].x = paoPoints[i].x + j * dfRatioX;
21,014✔
2769
                paoNewPoints[newI].y = paoPoints[i].y + j * dfRatioY;
21,014✔
2770
                if (padfZ != nullptr)
21,014✔
2771
                {
2772
                    // No interpolation.
2773
                    padfNewZ[newI] = padfZ[i];
10✔
2774
                }
2775
                if (padfM != nullptr)
21,014✔
2776
                {
2777
                    // No interpolation.
2778
                    padfNewM[newI] = padfM[i];
2✔
2779
                }
2780
            }
2781

2782
            nNewPointCount += nIntermediatePoints;
282✔
2783
        }
2784
    }
2785

2786
    CPLFree(paoPoints);
41✔
2787
    paoPoints = paoNewPoints;
41✔
2788
    nPointCount = nNewPointCount;
41✔
2789
    m_nPointCapacity = nNewPointCount;
41✔
2790

2791
    if (padfZ != nullptr)
41✔
2792
    {
2793
        CPLFree(padfZ);
2✔
2794
        padfZ = padfNewZ;
2✔
2795
    }
2796
    if (padfM != nullptr)
41✔
2797
    {
2798
        CPLFree(padfM);
2✔
2799
        padfM = padfNewM;
2✔
2800
    }
2801
    return true;
41✔
2802
}
2803

2804
/************************************************************************/
2805
/*                               swapXY()                               */
2806
/************************************************************************/
2807

2808
void OGRSimpleCurve::swapXY()
102✔
2809
{
2810
    for (int i = 0; i < nPointCount; i++)
652✔
2811
    {
2812
        std::swap(paoPoints[i].x, paoPoints[i].y);
550✔
2813
    }
2814
}
102✔
2815

2816
/************************************************************************/
2817
/*                       OGRSimpleCurvePointIterator                    */
2818
/************************************************************************/
2819

2820
class OGRSimpleCurvePointIterator final : public OGRPointIterator
2821
{
2822
    CPL_DISALLOW_COPY_ASSIGN(OGRSimpleCurvePointIterator)
2823

2824
    const OGRSimpleCurve *poSC = nullptr;
2825
    int iCurPoint = 0;
2826

2827
  public:
2828
    explicit OGRSimpleCurvePointIterator(const OGRSimpleCurve *poSCIn)
169✔
2829
        : poSC(poSCIn)
169✔
2830
    {
2831
    }
169✔
2832

2833
    OGRBoolean getNextPoint(OGRPoint *p) override;
2834
};
2835

2836
/************************************************************************/
2837
/*                            getNextPoint()                            */
2838
/************************************************************************/
2839

2840
OGRBoolean OGRSimpleCurvePointIterator::getNextPoint(OGRPoint *p)
697✔
2841
{
2842
    if (iCurPoint >= poSC->getNumPoints())
697✔
2843
        return FALSE;
133✔
2844
    poSC->getPoint(iCurPoint, p);
564✔
2845
    iCurPoint++;
564✔
2846
    return TRUE;
564✔
2847
}
2848

2849
/************************************************************************/
2850
/*                         getPointIterator()                           */
2851
/************************************************************************/
2852

2853
OGRPointIterator *OGRSimpleCurve::getPointIterator() const
169✔
2854
{
2855
    return new OGRSimpleCurvePointIterator(this);
169✔
2856
}
2857

2858
/************************************************************************/
2859
/*                  OGRLineString( const OGRLineString& )               */
2860
/************************************************************************/
2861

2862
/**
2863
 * \brief Copy constructor.
2864
 *
2865
 * Note: before GDAL 2.1, only the default implementation of the constructor
2866
 * existed, which could be unsafe to use.
2867
 *
2868
 * @since GDAL 2.1
2869
 */
2870

2871
OGRLineString::OGRLineString(const OGRLineString &) = default;
2872

2873
/************************************************************************/
2874
/*                  OGRLineString( OGRLineString&& )                    */
2875
/************************************************************************/
2876

2877
/**
2878
 * \brief Move constructor.
2879
 *
2880
 * @since GDAL 3.11
2881
 */
2882

2883
OGRLineString::OGRLineString(OGRLineString &&) = default;
2884

2885
/************************************************************************/
2886
/*                    operator=( const OGRLineString& )                 */
2887
/************************************************************************/
2888

2889
/**
2890
 * \brief Assignment operator.
2891
 *
2892
 * Note: before GDAL 2.1, only the default implementation of the operator
2893
 * existed, which could be unsafe to use.
2894
 *
2895
 * @since GDAL 2.1
2896
 */
2897

2898
OGRLineString &OGRLineString::operator=(const OGRLineString &other)
9✔
2899
{
2900
    if (this != &other)
9✔
2901
    {
2902
        OGRSimpleCurve::operator=(other);
8✔
2903
    }
2904
    return *this;
9✔
2905
}
2906

2907
/************************************************************************/
2908
/*                    operator=( OGRLineString&& )                      */
2909
/************************************************************************/
2910

2911
/**
2912
 * \brief Move assignment operator.
2913
 *
2914
 * @since GDAL 3.11
2915
 */
2916

2917
OGRLineString &OGRLineString::operator=(OGRLineString &&other)
4✔
2918
{
2919
    if (this != &other)
4✔
2920
    {
2921
        OGRSimpleCurve::operator=(std::move(other));
4✔
2922
    }
2923
    return *this;
4✔
2924
}
2925

2926
/************************************************************************/
2927
/*                          getGeometryType()                           */
2928
/************************************************************************/
2929

2930
OGRwkbGeometryType OGRLineString::getGeometryType() const
870,239✔
2931

2932
{
2933
    if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
870,239✔
2934
        return wkbLineStringZM;
44,081✔
2935
    else if (flags & OGR_G_MEASURED)
826,158✔
2936
        return wkbLineStringM;
1,188✔
2937
    else if (flags & OGR_G_3D)
824,970✔
2938
        return wkbLineString25D;
147,542✔
2939
    else
2940
        return wkbLineString;
677,428✔
2941
}
2942

2943
/************************************************************************/
2944
/*                          getGeometryName()                           */
2945
/************************************************************************/
2946

2947
const char *OGRLineString::getGeometryName() const
10,581✔
2948

2949
{
2950
    return "LINESTRING";
10,581✔
2951
}
2952

2953
/************************************************************************/
2954
/*                          curveToLine()                               */
2955
/************************************************************************/
2956

2957
OGRLineString *OGRLineString::CurveToLine(
952✔
2958
    CPL_UNUSED double /* dfMaxAngleStepSizeDegrees */,
2959
    CPL_UNUSED const char *const * /* papszOptions */) const
2960
{
2961
    return clone();
952✔
2962
}
2963

2964
/************************************************************************/
2965
/*                          get_LinearArea()                            */
2966
/************************************************************************/
2967

2968
/**
2969
 * \brief Compute area of ring / closed linestring.
2970
 *
2971
 * The area is computed according to Green's Theorem:
2972
 *
2973
 * Area is "Sum(x(i)*(y(i+1) - y(i-1)))/2" for i = 0 to pointCount-1,
2974
 * assuming the last point is a duplicate of the first.
2975
 *
2976
 * @return computed area.
2977
 */
2978

2979
double OGRSimpleCurve::get_LinearArea() const
61,805✔
2980

2981
{
2982
    if (nPointCount < 2 ||
123,609✔
2983
        (WkbSize() != 0 && /* if not a linearring, check it is closed */
61,804✔
2984
         (paoPoints[0].x != paoPoints[nPointCount - 1].x ||
60✔
2985
          paoPoints[0].y != paoPoints[nPointCount - 1].y)))
59✔
2986
    {
2987
        return 0;
2✔
2988
    }
2989

2990
    double dfAreaSum =
61,803✔
2991
        paoPoints[0].x * (paoPoints[1].y - paoPoints[nPointCount - 1].y);
61,803✔
2992

2993
    for (int i = 1; i < nPointCount - 1; i++)
3,360,260✔
2994
    {
2995
        dfAreaSum += paoPoints[i].x * (paoPoints[i + 1].y - paoPoints[i - 1].y);
3,298,460✔
2996
    }
2997

2998
    dfAreaSum += paoPoints[nPointCount - 1].x *
61,803✔
2999
                 (paoPoints[0].y - paoPoints[nPointCount - 2].y);
61,803✔
3000

3001
    return 0.5 * fabs(dfAreaSum);
61,803✔
3002
}
3003

3004
/************************************************************************/
3005
/*                             getCurveGeometry()                       */
3006
/************************************************************************/
3007

3008
OGRGeometry *
3009
OGRLineString::getCurveGeometry(const char *const *papszOptions) const
3,197✔
3010
{
3011
    return OGRGeometryFactory::curveFromLineString(this, papszOptions);
3,197✔
3012
}
3013

3014
/************************************************************************/
3015
/*                      TransferMembersAndDestroy()                     */
3016
/************************************************************************/
3017
//! @cond Doxygen_Suppress
3018
OGRLineString *OGRLineString::TransferMembersAndDestroy(OGRLineString *poSrc,
590✔
3019
                                                        OGRLineString *poDst)
3020
{
3021
    if (poSrc->Is3D())
590✔
3022
        poDst->flags |= OGR_G_3D;
101✔
3023
    if (poSrc->IsMeasured())
590✔
3024
        poDst->flags |= OGR_G_MEASURED;
47✔
3025
    poDst->assignSpatialReference(poSrc->getSpatialReference());
590✔
3026
    poDst->nPointCount = poSrc->nPointCount;
590✔
3027
    poDst->m_nPointCapacity = poSrc->m_nPointCapacity;
590✔
3028
    poDst->paoPoints = poSrc->paoPoints;
590✔
3029
    poDst->padfZ = poSrc->padfZ;
590✔
3030
    poDst->padfM = poSrc->padfM;
590✔
3031
    poSrc->nPointCount = 0;
590✔
3032
    poSrc->m_nPointCapacity = 0;
590✔
3033
    poSrc->paoPoints = nullptr;
590✔
3034
    poSrc->padfZ = nullptr;
590✔
3035
    poSrc->padfM = nullptr;
590✔
3036
    delete poSrc;
590✔
3037
    return poDst;
590✔
3038
}
3039

3040
//! @endcond
3041
/************************************************************************/
3042
/*                         CastToLinearRing()                           */
3043
/************************************************************************/
3044

3045
/**
3046
 * \brief Cast to linear ring.
3047
 *
3048
 * The passed in geometry is consumed and a new one returned (or NULL in case
3049
 * of failure)
3050
 *
3051
 * @param poLS the input geometry - ownership is passed to the method.
3052
 * @return new geometry.
3053
 */
3054

3055
OGRLinearRing *OGRLineString::CastToLinearRing(OGRLineString *poLS)
526✔
3056
{
3057
    if (poLS->nPointCount < 2 || !poLS->get_IsClosed())
526✔
3058
    {
3059
        CPLError(CE_Failure, CPLE_AppDefined,
2✔
3060
                 "Cannot convert non-closed linestring to linearring");
3061
        delete poLS;
2✔
3062
        return nullptr;
2✔
3063
    }
3064
    OGRLinearRing *poLR = new OGRLinearRing();
524✔
3065
    TransferMembersAndDestroy(poLS, poLR);
524✔
3066
    return poLR;
524✔
3067
}
3068

3069
/************************************************************************/
3070
/*                               clone()                                */
3071
/************************************************************************/
3072

3073
OGRLineString *OGRLineString::clone() const
300,838✔
3074
{
3075
    auto ret = new (std::nothrow) OGRLineString(*this);
300,838✔
3076
    if (ret)
300,838✔
3077
    {
3078
        if (ret->getNumPoints() != getNumPoints())
300,838✔
3079
        {
3080
            delete ret;
×
3081
            ret = nullptr;
×
3082
        }
3083
    }
3084
    return ret;
300,838✔
3085
}
3086

3087
//! @cond Doxygen_Suppress
3088

3089
/************************************************************************/
3090
/*                     GetCasterToLineString()                          */
3091
/************************************************************************/
3092

3093
static OGRLineString *CasterToLineString(OGRCurve *poCurve)
156✔
3094
{
3095
    return poCurve->toLineString();
156✔
3096
}
3097

3098
OGRCurveCasterToLineString OGRLineString::GetCasterToLineString() const
156✔
3099
{
3100
    return ::CasterToLineString;
156✔
3101
}
3102

3103
/************************************************************************/
3104
/*                        GetCasterToLinearRing()                       */
3105
/************************************************************************/
3106

3107
OGRLinearRing *OGRLineString::CasterToLinearRing(OGRCurve *poCurve)
526✔
3108
{
3109
    return OGRLineString::CastToLinearRing(poCurve->toLineString());
526✔
3110
}
3111

3112
OGRCurveCasterToLinearRing OGRLineString::GetCasterToLinearRing() const
526✔
3113
{
3114
    return OGRLineString::CasterToLinearRing;
526✔
3115
}
3116

3117
/************************************************************************/
3118
/*                            get_Area()                                */
3119
/************************************************************************/
3120

3121
double OGRLineString::get_Area() const
61,804✔
3122
{
3123
    return get_LinearArea();
61,804✔
3124
}
3125

3126
/************************************************************************/
3127
/*                        GetGeodesicAreaOrLength()                     */
3128
/************************************************************************/
3129

3130
static bool GetGeodesicAreaOrLength(const OGRLineString *poLS,
44✔
3131
                                    const OGRSpatialReference *poSRSOverride,
3132
                                    double *pdfArea, double *pdfLength)
3133
{
3134
    if (!poSRSOverride)
44✔
3135
        poSRSOverride = poLS->getSpatialReference();
11✔
3136

3137
    if (!poSRSOverride)
44✔
3138
    {
3139
        CPLError(CE_Failure, CPLE_AppDefined,
2✔
3140
                 "Cannot compute %s on ellipsoid due to missing SRS",
3141
                 pdfArea ? "area" : "length");
3142
        return false;
2✔
3143
    }
3144

3145
    OGRErr eErr = OGRERR_NONE;
42✔
3146
    double dfSemiMajor = poSRSOverride->GetSemiMajor(&eErr);
42✔
3147
    if (eErr != OGRERR_NONE)
42✔
3148
        return false;
2✔
3149
    const double dfInvFlattening = poSRSOverride->GetInvFlattening(&eErr);
40✔
3150
    if (eErr != OGRERR_NONE)
40✔
3151
        return false;
×
3152

3153
    geod_geodesic g;
3154
    geod_init(&g, dfSemiMajor,
40✔
3155
              dfInvFlattening != 0 ? 1.0 / dfInvFlattening : 0.0);
3156

3157
    std::vector<double> adfLat;
80✔
3158
    std::vector<double> adfLon;
80✔
3159
    const int nPointCount = poLS->getNumPoints();
40✔
3160
    adfLat.reserve(nPointCount);
40✔
3161
    adfLon.reserve(nPointCount);
40✔
3162

3163
    OGRSpatialReference oGeogCRS;
80✔
3164
    if (oGeogCRS.CopyGeogCSFrom(poSRSOverride) != OGRERR_NONE)
40✔
3165
    {
3166
        CPLError(CE_Failure, CPLE_AppDefined,
×
3167
                 "Cannot reproject geometry to geographic CRS");
3168
        return false;
×
3169
    }
3170
    oGeogCRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
40✔
3171
    auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
3172
        OGRCreateCoordinateTransformation(poSRSOverride, &oGeogCRS));
80✔
3173
    if (!poCT)
40✔
3174
    {
3175
        CPLError(CE_Failure, CPLE_AppDefined,
×
3176
                 "Cannot reproject geometry to geographic CRS");
3177
        return false;
×
3178
    }
3179
    for (int i = 0; i < nPointCount; ++i)
896✔
3180
    {
3181
        adfLon.push_back(poLS->getX(i));
856✔
3182
        adfLat.push_back(poLS->getY(i));
856✔
3183
    }
3184
#ifdef __GNUC__
3185
#pragma GCC diagnostic push
3186
#pragma GCC diagnostic ignored "-Wnull-dereference"
3187
#endif
3188
    std::vector<int> anSuccess;
80✔
3189
    anSuccess.resize(adfLon.size());
40✔
3190
#ifdef __GNUC__
3191
#pragma GCC diagnostic pop
3192
#endif
3193
    poCT->Transform(adfLon.size(), adfLon.data(), adfLat.data(), nullptr,
40✔
3194
                    anSuccess.data());
3195
    double dfToDegrees =
3196
        oGeogCRS.GetAngularUnits(nullptr) / CPLAtof(SRS_UA_DEGREE_CONV);
40✔
3197
    if (std::fabs(dfToDegrees - 1) <= 1e-10)
40✔
3198
        dfToDegrees = 1.0;
40✔
3199
    for (int i = 0; i < nPointCount; ++i)
896✔
3200
    {
3201
        if (!anSuccess[i])
856✔
3202
        {
3203
            CPLError(CE_Failure, CPLE_AppDefined,
×
3204
                     "Cannot reproject geometry to geographic CRS");
3205
            return false;
×
3206
        }
3207
        adfLon[i] *= dfToDegrees;
856✔
3208
        adfLat[i] *= dfToDegrees;
856✔
3209
    }
3210

3211
    geod_polygonarea(&g, adfLat.data(), adfLon.data(),
40✔
3212
                     static_cast<int>(adfLat.size()), pdfArea, pdfLength);
40✔
3213
    return true;
40✔
3214
}
3215

3216
/************************************************************************/
3217
/*                        get_GeodesicArea()                            */
3218
/************************************************************************/
3219

3220
double
3221
OGRLineString::get_GeodesicArea(const OGRSpatialReference *poSRSOverride) const
22✔
3222
{
3223
    double dfArea = 0;
22✔
3224
    if (!GetGeodesicAreaOrLength(this, poSRSOverride, &dfArea, nullptr))
22✔
3225
        return -1.0;
2✔
3226
    return std::fabs(dfArea);
20✔
3227
}
3228

3229
/************************************************************************/
3230
/*                        get_GeodesicLength()                          */
3231
/************************************************************************/
3232

3233
double OGRLineString::get_GeodesicLength(
22✔
3234
    const OGRSpatialReference *poSRSOverride) const
3235
{
3236
    double dfLength = 0;
22✔
3237
    if (!GetGeodesicAreaOrLength(this, poSRSOverride, nullptr, &dfLength))
22✔
3238
        return -1;
2✔
3239
    return dfLength;
20✔
3240
}
3241

3242
/************************************************************************/
3243
/*                       get_AreaOfCurveSegments()                      */
3244
/************************************************************************/
3245

3246
double OGRLineString::get_AreaOfCurveSegments() const
31✔
3247
{
3248
    return 0;
31✔
3249
}
3250

3251
/************************************************************************/
3252
/*                            isClockwise()                             */
3253
/************************************************************************/
3254

3255
/**
3256
 * \brief Returns TRUE if the ring has clockwise winding (or less than 2 points)
3257
 *
3258
 * Assumes that the line is closed.
3259
 *
3260
 * @return TRUE if clockwise otherwise FALSE.
3261
 */
3262

3263
int OGRLineString::isClockwise() const
79,821✔
3264

3265
{
3266
    // WARNING: keep in sync OGRLineString::isClockwise(),
3267
    // OGRCurve::isClockwise() and OGRWKBIsClockwiseRing()
3268

3269
    if (nPointCount < 2)
79,821✔
3270
        return TRUE;
1✔
3271

3272
    bool bUseFallback = false;
79,820✔
3273

3274
    // Find the lowest rightmost vertex.
3275
    int v = 0;  // Used after for.
79,820✔
3276
    for (int i = 1; i < nPointCount - 1; i++)
3,789,120✔
3277
    {
3278
        // => v < end.
3279
        if (paoPoints[i].y < paoPoints[v].y ||
3,709,300✔
3280
            (paoPoints[i].y == paoPoints[v].y &&
3,222,750✔
3281
             paoPoints[i].x > paoPoints[v].x))
50,998✔
3282
        {
3283
            v = i;
515,160✔
3284
            bUseFallback = false;
515,160✔
3285
        }
3286
        else if (paoPoints[i].y == paoPoints[v].y &&
3,194,140✔
3287
                 paoPoints[i].x == paoPoints[v].x)
22,390✔
3288
        {
3289
            // Two vertex with same coordinates are the lowest rightmost
3290
            // vertex.  Cannot use that point as the pivot (#5342).
3291
            bUseFallback = true;
36✔
3292
        }
3293
    }
3294

3295
    // Previous.
3296
    int next = v - 1;
79,820✔
3297
    if (next < 0)
79,820✔
3298
    {
3299
        next = nPointCount - 1 - 1;
28,187✔
3300
    }
3301

3302
    constexpr double EPSILON = 1.0E-5;
79,820✔
3303
    const auto epsilonEqual = [](double a, double b, double eps)
177,681✔
3304
    { return ::fabs(a - b) < eps; };
177,681✔
3305

3306
    if (epsilonEqual(paoPoints[next].x, paoPoints[v].x, EPSILON) &&
96,133✔
3307
        epsilonEqual(paoPoints[next].y, paoPoints[v].y, EPSILON))
16,321✔
3308
    {
3309
        // Don't try to be too clever by retrying with a next point.
3310
        // This can lead to false results as in the case of #3356.
3311
        bUseFallback = true;
226✔
3312
    }
3313

3314
    const double dx0 = paoPoints[next].x - paoPoints[v].x;
79,799✔
3315
    const double dy0 = paoPoints[next].y - paoPoints[v].y;
79,799✔
3316

3317
    // Following.
3318
    next = v + 1;
79,799✔
3319
    if (next >= nPointCount - 1)
79,799✔
3320
    {
3321
        next = 0;
17,999✔
3322
    }
3323

3324
    if (epsilonEqual(paoPoints[next].x, paoPoints[v].x, EPSILON) &&
81,538✔
3325
        epsilonEqual(paoPoints[next].y, paoPoints[v].y, EPSILON))
1,734✔
3326
    {
3327
        // Don't try to be too clever by retrying with a next point.
3328
        // This can lead to false results as in the case of #3356.
3329
        bUseFallback = true;
256✔
3330
    }
3331

3332
    const double dx1 = paoPoints[next].x - paoPoints[v].x;
79,810✔
3333
    const double dy1 = paoPoints[next].y - paoPoints[v].y;
79,810✔
3334

3335
    const double crossproduct = dx1 * dy0 - dx0 * dy1;
79,810✔
3336

3337
    if (!bUseFallback)
79,810✔
3338
    {
3339
        if (crossproduct > 0)  // CCW
79,438✔
3340
            return FALSE;
44,774✔
3341
        else if (crossproduct < 0)  // CW
34,664✔
3342
            return TRUE;
34,646✔
3343
    }
3344

3345
    // This is a degenerate case: the extent of the polygon is less than EPSILON
3346
    // or 2 nearly identical points were found.
3347
    // Try with Green Formula as a fallback, but this is not a guarantee
3348
    // as we'll probably be affected by numerical instabilities.
3349

3350
    double dfSum =
390✔
3351
        paoPoints[0].x * (paoPoints[1].y - paoPoints[nPointCount - 1].y);
390✔
3352

3353
    for (int i = 1; i < nPointCount - 1; i++)
45,657✔
3354
    {
3355
        dfSum += paoPoints[i].x * (paoPoints[i + 1].y - paoPoints[i - 1].y);
45,267✔
3356
    }
3357

3358
    dfSum += paoPoints[nPointCount - 1].x *
390✔
3359
             (paoPoints[0].y - paoPoints[nPointCount - 2].y);
390✔
3360

3361
    return dfSum < 0;
390✔
3362
}
3363

3364
//! @endcond
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc