Coverage Report

Created: 2026-09-01 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/geos/src/geom/CoordinateSequence.cpp
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * GEOS - Geometry Engine Open Source
4
 * http://geos.osgeo.org
5
 *
6
 * Copyright (C) 2022 ISciences LLC
7
 * Copyright (C) 2006 Refractions Research Inc.
8
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
9
 *
10
 * This is free software; you can redistribute and/or modify it under
11
 * the terms of the GNU Lesser General Public Licence as published
12
 * by the Free Software Foundation.
13
 * See the COPYING file for more information.
14
 *
15
 **********************************************************************/
16
17
#include <geos/constants.h>
18
#include <geos/profiler.h>
19
#include <geos/geom/CoordinateFilter.h>
20
#include <geos/geom/CoordinateSequence.h>
21
#include <geos/geom/Coordinate.h>
22
#include <geos/geom/Envelope.h>
23
#include <geos/util/IllegalArgumentException.h>
24
#include <geos/util.h>
25
26
#include <cstdio>
27
#include <cstring>
28
#include <algorithm>
29
#include <vector>
30
#include <cassert>
31
#include <iterator>
32
#include <sstream>
33
34
namespace geos {
35
namespace geom { // geos::geom
36
37
#if PROFILE
38
static Profiler* profiler = Profiler::instance();
39
#endif
40
41
// If GEOS_COORDSEQ_PADZ is defined:
42
// - XY sequences will be stored as XYZ
43
// - XYM sequences will be stored as XYZM
44
// This prevents incorrect results when an XYZ Coordinate is read from
45
// a sequence storing XY or XYM. When GEOS is changed to check
46
// coordinate types throughout the library, this can be undefined to
47
// store coordinates efficiently.
48
#define GEOS_COORDSEQ_PADZ
49
50
CoordinateSequence::CoordinateSequence() :
51
985k
    CoordinateSequence(0, 0) {}
52
53
CoordinateSequence::CoordinateSequence(std::size_t sz, bool hasz, bool hasm, bool init) :
54
#ifdef GEOS_COORDSEQ_PADZ
55
151M
    m_vect(sz * (3u + hasm)),
56
151M
    m_stride(static_cast<std::uint8_t>(3u + hasm)),
57
#else
58
    m_vect(sz * (2u + hasm + hasz)),
59
    m_stride(static_cast<std::uint8_t>(2u + hasm + hasz)),
60
#endif
61
151M
    m_hasdim(true),
62
151M
    m_hasz(hasz),
63
151M
    m_hasm(hasm)
64
151M
{
65
151M
    if (init) {
66
146M
        initialize();
67
146M
    }
68
151M
}
69
70
CoordinateSequence::CoordinateSequence(std::size_t sz, std::size_t dim) :
71
#ifdef GEOS_COORDSEQ_PADZ
72
2.47M
    m_vect(sz * std::max(static_cast<std::uint8_t>(dim), static_cast<std::uint8_t>(3))),
73
2.47M
    m_stride(std::max(static_cast<std::uint8_t>(dim), static_cast<std::uint8_t>(3))),
74
#else
75
    m_vect(sz * static_cast<std::uint8_t>(dim)),
76
    m_stride(static_cast<std::uint8_t>(dim)),
77
#endif
78
2.47M
    m_hasdim(dim > 0),
79
2.47M
    m_hasz(dim >= 3),
80
2.47M
    m_hasm(dim == 4)
81
2.47M
{
82
2.47M
    if (dim == 1 || dim > 4) {
83
0
        throw util::IllegalArgumentException("Declared dimension must be 2, 3, or 4");
84
0
    }
85
2.47M
    initialize();
86
2.47M
}
87
88
CoordinateSequence::CoordinateSequence(const std::initializer_list<Coordinate>& list) :
89
9.60M
    m_stride(3),
90
9.60M
    m_hasdim(false),
91
9.60M
    m_hasz(false),
92
9.60M
    m_hasm(false)
93
9.60M
{
94
9.60M
    reserve(list.size());
95
9.60M
    add(list.begin(), list.end());
96
9.60M
}
97
98
CoordinateSequence::CoordinateSequence(const std::initializer_list<CoordinateXY>& list) :
99
#ifdef GEOS_COORDSEQ_PADZ
100
7.26k
    m_stride(3),
101
#else
102
    m_stride(2),
103
#endif
104
7.26k
    m_hasdim(true),
105
7.26k
    m_hasz(false),
106
7.26k
    m_hasm(false)
107
7.26k
{
108
7.26k
    reserve(list.size());
109
7.26k
    add(list.begin(), list.end());
110
7.26k
}
111
112
CoordinateSequence::CoordinateSequence(const std::initializer_list<CoordinateXYM>& list) :
113
#ifdef GEOS_COORDSEQ_PADZ
114
0
    m_stride(4),
115
#else
116
    m_stride(3),
117
#endif
118
0
    m_hasdim(true),
119
0
    m_hasz(false),
120
0
    m_hasm(true)
121
0
{
122
0
    reserve(list.size());
123
0
    add(list.begin(), list.end());
124
0
}
125
126
CoordinateSequence::CoordinateSequence(const std::initializer_list<CoordinateXYZM>& list) :
127
0
    m_stride(4),
128
0
    m_hasdim(true),
129
0
    m_hasz(true),
130
0
    m_hasm(true)
131
0
{
132
0
    reserve(list.size());
133
0
    add(list.begin(), list.end());
134
0
}
135
136
template<typename T>
137
void fillVector(std::vector<double> & v)
138
149M
{
139
149M
    const T c;
140
149M
    T* from = reinterpret_cast<T*>(v.data());
141
149M
    T* to = reinterpret_cast<T*>(v.data() + v.size());
142
149M
    std::fill(from, to, c);
143
149M
}
void geos::geom::fillVector<geos::geom::Coordinate>(std::__1::vector<double, std::__1::allocator<double> >&)
Line
Count
Source
138
129M
{
139
129M
    const T c;
140
129M
    T* from = reinterpret_cast<T*>(v.data());
141
129M
    T* to = reinterpret_cast<T*>(v.data() + v.size());
142
129M
    std::fill(from, to, c);
143
129M
}
void geos::geom::fillVector<geos::geom::CoordinateXYZM>(std::__1::vector<double, std::__1::allocator<double> >&)
Line
Count
Source
138
19.9M
{
139
19.9M
    const T c;
140
19.9M
    T* from = reinterpret_cast<T*>(v.data());
141
19.9M
    T* to = reinterpret_cast<T*>(v.data() + v.size());
142
19.9M
    std::fill(from, to, c);
143
19.9M
}
Unexecuted instantiation: void geos::geom::fillVector<geos::geom::CoordinateXY>(std::__1::vector<double, std::__1::allocator<double> >&)
Unexecuted instantiation: void geos::geom::fillVector<geos::geom::CoordinateXYM>(std::__1::vector<double, std::__1::allocator<double> >&)
144
145
void
146
CoordinateSequence::initialize()
147
149M
{
148
149M
    switch(getCoordinateType()) {
149
129M
        case CoordinateType::XYZ: fillVector<Coordinate>(m_vect); break;
150
19.9M
        case CoordinateType::XYZM: fillVector<CoordinateXYZM>(m_vect); break;
151
0
        case CoordinateType::XY: fillVector<CoordinateXY>(m_vect); break;
152
0
        case CoordinateType::XYM: fillVector<CoordinateXYM>(m_vect); break;
153
149M
    }
154
149M
}
155
156
void
157
CoordinateSequence::add(const CoordinateSequence& cs, std::size_t from, std::size_t to)
158
67.8M
{
159
67.8M
    if (cs.stride() == stride() && cs.hasM() == hasM()) {
160
67.5M
        m_vect.insert(m_vect.end(),
161
67.5M
                      std::next(cs.m_vect.cbegin(), static_cast<std::ptrdiff_t>(from * stride())),
162
67.5M
                      std::next(cs.m_vect.cbegin(), static_cast<std::ptrdiff_t>((to + 1u)*stride())));
163
67.5M
    } else {
164
283k
        std::size_t pos = size();
165
283k
        make_space(pos, to - from + 1);
166
167
283k
        switch(cs.getCoordinateType()) {
168
0
            case CoordinateType::XY:   cs.forEach<CoordinateXY>(from, to, [this, &pos](const CoordinateXY& c) { setAt(c, pos++); }); break;
169
555k
            case CoordinateType::XYZ:  cs.forEach<Coordinate>(from, to, [this, &pos](const Coordinate& c) { setAt(c, pos++); }); break;
170
204
            case CoordinateType::XYZM: cs.forEach<CoordinateXYZM>(from, to, [this, &pos](const CoordinateXYZM& c) { setAt(c, pos++); }); break;
171
0
            case CoordinateType::XYM:  cs.forEach<CoordinateXYM>(from, to, [this, &pos](const CoordinateXYM& c) { setAt(c, pos++); }); break;
172
283k
        }
173
283k
    }
174
67.8M
}
175
176
void
177
CoordinateSequence::add(const CoordinateSequence& cs)
178
177k
{
179
177k
    add(cs, 0, cs.size() - 1);
180
177k
}
181
182
void
183
CoordinateSequence::add(const CoordinateSequence& cs, std::size_t from, std::size_t to, bool allowRepeated)
184
46.1M
{
185
46.1M
    if (allowRepeated) {
186
0
        add(cs, from, to);
187
0
        return;
188
0
    }
189
190
46.1M
    std::size_t first = from;
191
192
    // Check for case where first point(s) of `cs` duplicate last points of `this`
193
46.1M
    if (!isEmpty()) {
194
11.1M
        while(first <= to && cs.getAt<CoordinateXY>(first).equals2D(back<CoordinateXY>())) {
195
5.42M
            first++;
196
5.42M
        }
197
5.72M
    }
198
199
46.1M
    if (first > to) {
200
        // No unique points to add.
201
898
        return;
202
898
    }
203
204
46.1M
    std::size_t last = first + 1;
205
46.1M
    const CoordinateXY* last_unique = &cs.getAt<CoordinateXY>(first);
206
120M
    while(last <= to) {
207
74.7M
        const CoordinateXY* curr = &cs.getAt<CoordinateXY>(last);
208
74.7M
        if (curr->equals2D(*last_unique)) {
209
            // End of block
210
769k
            add(cs, first, last - 1);
211
13.9M
            do {
212
13.9M
                last++;
213
13.9M
            } while (last <= to && cs.getAt<CoordinateXY>(last).equals2D(*last_unique));
214
215
769k
            if (last != (to + 1) ) {
216
705k
                first = last;
217
705k
                last_unique = &cs.getAt<CoordinateXY>(first);
218
705k
            }
219
769k
            last++;
220
74.0M
        } else {
221
74.0M
            last_unique = curr;
222
74.0M
            last++;
223
74.0M
        }
224
74.7M
    }
225
226
46.1M
    if (last == (to + 1)) {
227
46.1M
        add(cs, first, to);
228
46.1M
    }
229
46.1M
}
230
231
void
232
39.0M
CoordinateSequence::add(const CoordinateSequence& cs, bool allowRepeated) {
233
39.0M
    if (!cs.isEmpty()) {
234
39.0M
        add(cs, 0, cs.size() - 1, allowRepeated);
235
39.0M
    }
236
39.0M
}
237
238
void
239
CoordinateSequence::add(const CoordinateSequence& cl, bool allowRepeated, bool forwardDirection)
240
831
{
241
831
    if (forwardDirection) {
242
831
        add(cl, allowRepeated);
243
831
    } else {
244
0
        CoordinateSequence rev(cl);
245
0
        rev.reverse();
246
0
        add(rev, allowRepeated);
247
0
        return;
248
0
    }
249
250
831
}
251
252
/*public*/
253
254
std::unique_ptr<CoordinateSequence>
255
CoordinateSequence::clone() const
256
9.68M
{
257
9.68M
    return detail::make_unique<CoordinateSequence>(*this);
258
9.68M
}
259
260
void
261
CoordinateSequence::closeRing(bool allowRepeated)
262
62.5k
{
263
62.5k
    if(!isEmpty() && (allowRepeated || front<CoordinateXY>() != back<CoordinateXY>())) {
264
43.5k
        const std::size_t n = stride();
265
43.5k
        const std::size_t old = m_vect.size();
266
43.5k
        m_vect.resize(old + n);
267
43.5k
        std::copy_n(m_vect.data(), n, m_vect.data() + old);
268
43.5k
    }
269
62.5k
}
270
271
std::size_t
272
CoordinateSequence::getDimension() const
273
7.87M
{
274
7.87M
    if (m_hasdim) {
275
5.83M
        return static_cast<std::size_t>(2 + hasM() + hasZ());
276
5.83M
    }
277
278
2.04M
    if (m_vect.empty()) {
279
765
        return 3;
280
765
    }
281
282
2.04M
    assert(stride() >= 3);
283
2.04M
    m_hasdim = true;
284
2.04M
    if (!std::isnan(getAt<Coordinate>(0).z)) {
285
1.10M
        m_hasz = true;
286
1.10M
    }
287
288
2.04M
    return getDimension();
289
2.04M
}
290
291
292
double
293
CoordinateSequence::getOrdinate(std::size_t index, std::size_t ordinateIndex) const
294
7.68k
{
295
7.68k
    switch(ordinateIndex) {
296
0
        case CoordinateSequence::X:
297
0
            return getAt<CoordinateXY>(index).x;
298
0
        case CoordinateSequence::Y:
299
0
            return getAt<CoordinateXY>(index).y;
300
3.93k
        case CoordinateSequence::Z:
301
3.93k
            return hasZ() ? getAt<Coordinate>(index).z : DoubleNotANumber;
302
3.74k
        case CoordinateSequence::M:
303
3.74k
            return getCoordinateType() == CoordinateType::XYZM ? getAt<CoordinateXYZM>(index).m :
304
3.74k
                                                                 getCoordinateType() == CoordinateType::XYM ? getAt<CoordinateXYM>(index).m :
305
0
                                                                                                               DoubleNotANumber;
306
0
        default:
307
0
            return DoubleNotANumber;
308
7.68k
    }
309
7.68k
}
310
311
bool
312
CoordinateSequence::hasRepeatedPoints() const
313
4.86M
{
314
    // Iterate over the array of doubles and check x/y values directly.
315
    // This is about 30% faster than retrieving/comparing CoordinateXY&.
316
28.9M
    for (std::size_t i = stride(); i < m_vect.size(); i += stride()) {
317
24.1M
        if (m_vect[i - stride()] == m_vect[i] && m_vect[i + 1 - stride()] == m_vect[i+1]) {
318
53.8k
            return true;
319
53.8k
        }
320
24.1M
    }
321
4.81M
    return false;
322
4.86M
}
323
324
bool
325
CoordinateSequence::hasRepeatedOrInvalidPoints() const
326
0
{
327
    // Check first points
328
0
    if (! (std::isfinite(m_vect[0]) && std::isfinite(m_vect[1]) )) {
329
0
        return true;
330
0
    }
331
    // Iterate over the array of doubles and check x/y values directly.
332
    // This is about 30% faster than retrieving/comparing CoordinateXY&.
333
0
    for (std::size_t i = stride(); i < m_vect.size(); i += stride()) {
334
0
        if (! (std::isfinite(m_vect[i]) && std::isfinite(m_vect[i+1]) )) {
335
0
            return true;
336
0
        }
337
0
        if (m_vect[i - stride()] == m_vect[i] && m_vect[i + 1 - stride()] == m_vect[i+1]) {
338
0
            return true;
339
0
        }
340
0
    }
341
0
    return false;
342
0
}
343
344
345
/*
346
 * Returns either the given coordinate array if its length is greater than the
347
 * given amount, or an empty coordinate array.
348
 */
349
CoordinateSequence*
350
CoordinateSequence::atLeastNCoordinatesOrNothing(std::size_t n,
351
        CoordinateSequence* c)
352
0
{
353
0
    if(c->getSize() >= n) {
354
0
        return c;
355
0
    }
356
0
    else {
357
        // FIXME: return NULL rather then empty coordinate array
358
0
        return new CoordinateSequence(0, c->getDimension());
359
0
    }
360
0
}
361
362
const CoordinateXY*
363
CoordinateSequence::minCoordinate() const
364
0
{
365
0
    if (isEmpty()) {
366
0
        return nullptr;
367
0
    }
368
0
    return &getAt<CoordinateXY>(minCoordinateIndex());
369
0
}
370
371
std::size_t
372
CoordinateSequence::minCoordinateIndex() const
373
0
{
374
0
    const CoordinateXY* minCoord = nullptr;
375
0
    std::size_t minIndex = std::numeric_limits<std::size_t>::max();
376
0
    const std::size_t p_size = getSize();
377
0
    for(std::size_t i = 0; i < p_size; i++) {
378
0
        if(minCoord == nullptr || minCoord->compareTo(getAt<CoordinateXY>(i)) > 0) {
379
0
            minCoord = &getAt<CoordinateXY>(i);
380
0
            minIndex = i;
381
0
        }
382
0
    }
383
0
    return minIndex;
384
0
}
385
386
size_t
387
CoordinateSequence::indexOf(const CoordinateXY* coordinate,
388
                            const CoordinateSequence* cl)
389
12
{
390
12
    std::size_t p_size = cl->size();
391
29
    for(std::size_t i = 0; i < p_size; ++i) {
392
29
        if((*coordinate) == cl->getAt<CoordinateXY>(i)) {
393
12
            return i;
394
12
        }
395
29
    }
396
0
    return NO_COORD_INDEX;
397
12
}
398
399
void
400
CoordinateSequence::scroll(CoordinateSequence* cl, const CoordinateXY* firstCoordinate)
401
0
{
402
0
    cl->scroll(firstCoordinate);
403
0
}
404
405
void
406
CoordinateSequence::scroll(const CoordinateXY* firstCoordinate)
407
0
{
408
0
    std::size_t ind = indexOf(firstCoordinate, this);
409
0
    if(ind == 0 || ind == std::numeric_limits<std::size_t>::max()) {
410
0
        return;    // not found or already first
411
0
    }
412
413
0
    scroll(ind);
414
0
}
415
416
void
417
CoordinateSequence::scroll(size_t ind)
418
0
{
419
0
    std::rotate(m_vect.begin(),
420
0
        std::next(m_vect.begin(), static_cast<std::ptrdiff_t>(ind * stride())),
421
0
        m_vect.end());
422
0
}
423
424
int
425
CoordinateSequence::increasingDirection(const CoordinateSequence& pts)
426
51.0M
{
427
51.0M
    std::size_t ptsize = pts.size();
428
51.1M
    for(std::size_t i = 0, n = ptsize / 2; i < n; ++i) {
429
51.1M
        std::size_t j = ptsize - 1 - i;
430
        // skip equal points on both ends
431
51.1M
        int comp = pts[i].compareTo(pts[j]);
432
51.1M
        if(comp != 0) {
433
51.0M
            return comp;
434
51.0M
        }
435
51.1M
    }
436
    // array must be a palindrome - defined to be in positive direction
437
45.1k
    return 1;
438
51.0M
}
439
440
/* public */
441
bool
442
CoordinateSequence::isRing() const
443
139k
{
444
139k
    if (size() < 4)
445
4.24k
        return false;
446
447
135k
    if (front<CoordinateXY>() != back<CoordinateXY>())
448
25.8k
        return false;
449
450
109k
    return true;
451
135k
}
452
453
void
454
CoordinateSequence::reverse()
455
24.4k
{
456
24.4k
    auto mid = m_vect.size() / 2;
457
24.4k
    auto last = m_vect.size() - stride();
458
880k
    for (std::size_t i = 0; i < mid; i += stride()) {
459
856k
        switch(stride()) {
460
78.7k
            case 4: std::swap(m_vect[i + 3], m_vect[last - i + 3]); // fall-through
461
856k
            case 3: std::swap(m_vect[i + 2], m_vect[last - i + 2]); // fall-through
462
856k
            case 2: std::swap(m_vect[i + 1], m_vect[last - i + 1]);
463
856k
                    std::swap(m_vect[i],     m_vect[last - i]);
464
465
856k
        }
466
856k
    }
467
24.4k
}
468
469
void
470
CoordinateSequence::sort()
471
37.9k
{
472
37.9k
    switch(getCoordinateType()) {
473
0
        case CoordinateType::XY:   std::sort(items<CoordinateXY>().begin(), items<CoordinateXY>().end()); return;
474
26.7k
        case CoordinateType::XYZ:  std::sort(items<Coordinate>().begin(), items<Coordinate>().end()); return;
475
11.1k
        case CoordinateType::XYZM: std::sort(items<CoordinateXYZM>().begin(), items<CoordinateXYZM>().end()); return;
476
0
        case CoordinateType::XYM:  std::sort(items<CoordinateXYM>().begin(), items<CoordinateXYM>().end()); return;
477
37.9k
    }
478
37.9k
}
479
480
bool
481
CoordinateSequence::equals(const CoordinateSequence* cl1,
482
                           const CoordinateSequence* cl2)
483
0
{
484
0
    if(cl1 == cl2) {
485
0
        return true;
486
0
    }
487
488
0
    if(cl1 == nullptr || cl2 == nullptr) {
489
0
        return false;
490
0
    }
491
492
0
    std::size_t npts1 = cl1->getSize();
493
0
    if(npts1 != cl2->getSize()) {
494
0
        return false;
495
0
    }
496
0
    for(std::size_t i = 0; i < npts1; i++) {
497
0
        if(!(cl1->getAt<CoordinateXY>(i) == cl2->getAt<CoordinateXY>(i))) {
498
0
            return false;
499
0
        }
500
0
    }
501
0
    return true;
502
0
}
503
504
bool
505
CoordinateSequence::equalsIdentical(const CoordinateSequence& other) const
506
0
{
507
0
    if (this == &other) {
508
0
        return true;
509
0
    }
510
511
0
    if (size() != other.size()) {
512
0
        return false;
513
0
    }
514
515
0
    if (hasZ() != other.hasZ()) {
516
0
        return false;
517
0
    }
518
519
0
    if (hasM() != other.hasM()) {
520
0
        return false;
521
0
    }
522
523
0
    assert(getCoordinateType() == other.getCoordinateType());
524
525
0
    for (std::size_t i = 0; i < m_vect.size(); i++) {
526
0
        const double& a = m_vect[i];
527
0
        const double& b = other.m_vect[i];
528
0
        if (a != b && !(std::isnan(a) && std::isnan(b))) {
529
0
            return false;
530
0
        }
531
0
    }
532
533
0
    return true;
534
0
}
535
536
void
537
CoordinateSequence::expandEnvelope(Envelope& env) const
538
757
{
539
757
    const std::size_t p_size = getSize();
540
19.4k
    for(std::size_t i = 0; i < p_size; i++) {
541
18.6k
        env.expandToInclude(getAt<CoordinateXY>(i));
542
18.6k
    }
543
757
}
544
545
Envelope
546
40.9M
CoordinateSequence::getEnvelope() const {
547
40.9M
    if (isEmpty()) {
548
0
        return {};
549
0
    }
550
551
40.9M
    double xmin = std::numeric_limits<double>::infinity();
552
40.9M
    double ymin = std::numeric_limits<double>::infinity();
553
40.9M
    double xmax = -std::numeric_limits<double>::infinity();
554
40.9M
    double ymax = -std::numeric_limits<double>::infinity();
555
556
140M
    for (std::size_t i = 0; i < m_vect.size(); i += stride()) {
557
99.8M
        xmin = std::min(xmin, m_vect[i]);
558
99.8M
        xmax = std::max(xmax, m_vect[i]);
559
99.8M
        ymin = std::min(ymin, m_vect[i+1]);
560
99.8M
        ymax = std::max(ymax, m_vect[i+1]);
561
99.8M
    }
562
563
40.9M
    return {xmin, xmax, ymin, ymax};
564
40.9M
}
565
566
567
void
568
CoordinateSequence::setOrdinate(std::size_t index, std::size_t ordinateIndex, double value)
569
17.3k
{
570
17.3k
    switch(ordinateIndex) {
571
0
        case CoordinateSequence::X:
572
0
        getAt<CoordinateXY>(index).x = value;
573
0
        break;
574
0
        case CoordinateSequence::Y:
575
0
        getAt<CoordinateXY>(index).y = value;
576
0
        break;
577
7.74k
        case CoordinateSequence::Z:
578
7.74k
        {
579
7.74k
            if (!hasZ()) {
580
0
                throw util::IllegalArgumentException("Coordinate type is not XYZ or XYZM");
581
0
            }
582
7.74k
            getAt<Coordinate>(index).z = value;
583
7.74k
        }
584
0
        break;
585
9.61k
        case CoordinateSequence::M:
586
9.61k
        {
587
9.61k
            if (!hasM()) {
588
0
                throw util::IllegalArgumentException("Coordinate type is not XYM or XYZM.");
589
0
            }
590
9.61k
            if (getCoordinateType() == CoordinateType::XYZM) {
591
9.61k
                getAt<CoordinateXYZM>(index).m = value;
592
9.61k
            } else {
593
0
                getAt<CoordinateXYM>(index).m = value;
594
0
            }
595
9.61k
            break;
596
9.61k
        }
597
0
        default: {
598
0
            std::stringstream ss;
599
0
            ss << "Unknown ordinate index " << ordinateIndex;
600
0
            throw util::IllegalArgumentException(ss.str());
601
0
            break;
602
9.61k
        }
603
17.3k
    }
604
17.3k
}
605
606
void
607
CoordinateSequence::setPoints(const std::vector<Coordinate>& v)
608
0
{
609
0
    m_stride = 3;
610
0
    m_hasdim = false;
611
0
    m_hasz = false;
612
0
    m_hasm = false;
613
614
0
    m_vect.resize(m_stride * v.size());
615
0
    const double* cbuf = reinterpret_cast<const double*>(v.data());
616
0
    m_vect.assign(cbuf, cbuf + m_vect.size());
617
0
}
618
619
void
620
CoordinateSequence::setPoints(const std::vector<CoordinateXY>& v)
621
0
{
622
0
    m_stride = 3;
623
0
    m_hasdim = false;
624
0
    m_hasz = false;
625
0
    m_hasm = false;
626
627
0
    m_vect.resize(m_stride * v.size());
628
0
    for (std::size_t i = 0; i < v.size(); i++) {
629
0
        setAt(v[i], i);
630
0
    }
631
0
}
632
633
void
634
CoordinateSequence::setZM(bool p_hasZ, bool p_hasM)
635
0
{
636
0
    if (p_hasZ != hasZ() || p_hasM != hasM()) {
637
0
        CoordinateSequence newSeq(0, p_hasZ, p_hasM);
638
0
        newSeq.add(*this);
639
0
        *this = std::move(newSeq);
640
0
    }
641
642
    // Make sure we don't carry over Z values that were hiding in a
643
    // self-declared 2D sequence.
644
0
    if (!p_hasZ && (getCoordinateType() == CoordinateType::XYZ || getCoordinateType() == CoordinateType::XYZM)) {
645
0
        const Coordinate& nullCoord = Coordinate::getNull();
646
0
        for (std::size_t i = 2; i < m_vect.size(); i += stride()) {
647
0
            m_vect[i] = nullCoord.z;
648
0
        }
649
0
    }
650
0
}
651
652
void
653
CoordinateSequence::swap(std::size_t i, std::size_t j)
654
0
{
655
0
    using difference_type = decltype(m_vect)::difference_type;
656
657
0
    if (i != j) {
658
0
        std::swap_ranges(std::next(m_vect.begin(), static_cast<difference_type>(i*stride())),
659
0
                         std::next(m_vect.begin(), static_cast<difference_type>(i+1) * stride()),
660
0
                         std::next(m_vect.begin(), static_cast<difference_type>(j*stride())));
661
0
    }
662
0
}
663
664
void
665
CoordinateSequence::toVector(std::vector<Coordinate>& out) const
666
9.90k
{
667
9.90k
    if (getCoordinateType() == CoordinateType::XYZ) {
668
7.19k
        const Coordinate* cbuf = reinterpret_cast<const Coordinate*>(m_vect.data());
669
7.19k
        out.insert(out.end(), cbuf, cbuf + size());
670
7.19k
    } else if (hasZ()) {
671
42.5k
        for (const auto& c : items<Coordinate>()) {
672
42.5k
            out.emplace_back(c.x, c.y, c.z);
673
42.5k
        }
674
2.17k
    } else {
675
14.2k
        for (const auto& c : items<CoordinateXY>()) {
676
14.2k
            out.emplace_back(c.x, c.y);
677
14.2k
        }
678
539
    }
679
9.90k
}
680
681
void
682
CoordinateSequence::toVector(std::vector<CoordinateXY>& out) const
683
0
{
684
0
    if (stride() == 2) {
685
0
        const CoordinateXY* cbuf = reinterpret_cast<const CoordinateXY*>(m_vect.data());
686
0
        out.insert(out.end(), cbuf, cbuf + size());
687
0
    } else {
688
0
        for (const CoordinateXY& c : items<CoordinateXY>()) {
689
0
            out.emplace_back(c.x, c.y);
690
0
        }
691
0
    }
692
0
}
693
694
void
695
CoordinateSequence::pop_back()
696
0
{
697
0
    switch (stride()) {
698
0
    case 4: m_vect.pop_back(); // fall through
699
0
    case 3: m_vect.pop_back(); // fall through
700
0
    case 2: m_vect.pop_back();
701
0
            m_vect.pop_back();
702
0
        break;
703
0
    default:
704
0
        assert(0);
705
0
    }
706
0
}
707
708
std::ostream&
709
operator<< (std::ostream& os, const CoordinateSequence& cs)
710
0
{
711
0
    os << "(";
712
713
0
    bool writeComma = false;
714
0
    auto write = [&os, &writeComma](const auto& coord) {
715
0
        if (writeComma) {
716
0
            os << ", ";
717
0
        } else {
718
0
            writeComma = true;
719
0
        }
720
721
0
        os << coord;
722
0
    };
Unexecuted instantiation: CoordinateSequence.cpp:auto geos::geom::operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, geos::geom::CoordinateSequence const&)::$_0::operator()<geos::geom::CoordinateXY>(geos::geom::CoordinateXY const&) const
Unexecuted instantiation: CoordinateSequence.cpp:auto geos::geom::operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, geos::geom::CoordinateSequence const&)::$_0::operator()<geos::geom::Coordinate>(geos::geom::Coordinate const&) const
Unexecuted instantiation: CoordinateSequence.cpp:auto geos::geom::operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, geos::geom::CoordinateSequence const&)::$_0::operator()<geos::geom::CoordinateXYM>(geos::geom::CoordinateXYM const&) const
Unexecuted instantiation: CoordinateSequence.cpp:auto geos::geom::operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, geos::geom::CoordinateSequence const&)::$_0::operator()<geos::geom::CoordinateXYZM>(geos::geom::CoordinateXYZM const&) const
723
724
0
    cs.forEach(write);
725
0
    os << ")";
726
727
0
    return os;
728
0
}
729
730
std::string
731
CoordinateSequence::toString() const
732
0
{
733
0
    std::ostringstream ss;
734
0
    ss << *this;
735
0
    return ss.str();
736
0
}
737
738
bool
739
operator== (const CoordinateSequence& s1, const CoordinateSequence& s2)
740
0
{
741
0
    return CoordinateSequence::equals(&s1, &s2);
742
0
}
743
744
bool
745
operator!= (const CoordinateSequence& s1, const CoordinateSequence& s2)
746
0
{
747
0
    return ! CoordinateSequence::equals(&s1, &s2);
748
0
}
749
750
} // namespace geos::geom
751
} // namespace geos