Coverage Report

Created: 2026-08-13 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/geos/src/geom/SimpleCurve.cpp
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * GEOS - Geometry Engine Open Source
4
 * http://geos.osgeo.org
5
 *
6
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
7
 * Copyright (C) 2005 2006 Refractions Research Inc.
8
 * Copyright (C) 2011 Sandro Santilli <strk@kbt.io>
9
 * Copyright (C) 2024 ISciences, LLC
10
 *
11
 * This is free software; you can redistribute and/or modify it under
12
 * the terms of the GNU Lesser General Public Licence as published
13
 * by the Free Software Foundation.
14
 * See the COPYING file for more information.
15
 *
16
 **********************************************************************/
17
18
#include <geos/geom/SimpleCurve.h>
19
20
#include <geos/algorithm/CircularArcs.h>
21
#include <geos/algorithm/Orientation.h>
22
#include <geos/geom/CoordinateFilter.h>
23
#include <geos/geom/GeometryFactory.h>
24
#include <geos/geom/GeometryFilter.h>
25
#include <geos/operation/BoundaryOp.h>
26
#include <geos/geom/CoordinateSequence.h>
27
#include <geos/geom/CoordinateSequenceFilter.h>
28
#include <geos/util.h>
29
30
31
namespace geos {
32
namespace geom {
33
34
SimpleCurve::SimpleCurve(const SimpleCurve& other)
35
4.87M
    : Curve(other),
36
4.87M
      points(other.points->clone()),
37
4.87M
      envelope(other.envelope)
38
4.87M
{
39
4.87M
}
40
41
SimpleCurve::SimpleCurve(const std::shared_ptr<const CoordinateSequence>& newCoords,
42
                         bool isLinear,
43
                         const GeometryFactory& factory)
44
284k
    : Curve(factory),
45
284k
      points(newCoords),
46
284k
      envelope(computeEnvelopeInternal(isLinear))
47
284k
{
48
284k
}
49
50
SimpleCurve::SimpleCurve(std::unique_ptr<CoordinateSequence>&& newCoords,
51
                         bool isLinear,
52
                         const GeometryFactory& factory)
53
8.20M
    : Curve(factory),
54
8.20M
      points(newCoords ? std::move(newCoords) : std::make_shared<CoordinateSequence>()),
55
8.20M
      envelope(computeEnvelopeInternal(isLinear))
56
8.20M
{
57
8.20M
}
58
59
void
60
SimpleCurve::apply_ro(CoordinateFilter* filter) const
61
450k
{
62
450k
    assert(points.get());
63
450k
    points->apply_ro(filter);
64
450k
}
65
66
void
67
SimpleCurve::apply_ro(CoordinateSequenceFilter& filter) const
68
914k
{
69
914k
    std::size_t npts = points->size();
70
914k
    if (!npts) {
71
223k
        return;
72
223k
    }
73
3.02M
    for (std::size_t i = 0; i < npts; ++i) {
74
2.71M
        filter.filter_ro(*points, i);
75
2.71M
        if (filter.isDone()) {
76
379k
            break;
77
379k
        }
78
2.71M
    }
79
691k
}
80
81
void
82
SimpleCurve::apply_rw(const CoordinateFilter* filter)
83
835k
{
84
835k
    assert(points.get());
85
835k
    if (points.use_count() > 1) {
86
0
        points = points->clone();
87
0
    }
88
835k
    const_cast<CoordinateSequence*>(points.get())->apply_rw(filter);
89
835k
}
90
91
void
92
SimpleCurve::apply_rw(CoordinateSequenceFilter& filter)
93
0
{
94
0
    if (points.use_count() > 1) {
95
0
        points = points->clone();
96
0
    }
97
0
    std::size_t npts = points->size();
98
0
    if (!npts) {
99
0
        return;
100
0
    }
101
0
    for (std::size_t i = 0; i < npts; ++i) {
102
0
        filter.filter_rw(const_cast<CoordinateSequence&>(*points), i);
103
0
        if (filter.isDone()) {
104
0
            break;
105
0
        }
106
0
    }
107
0
    if (filter.isGeometryChanged()) {
108
0
        geometryChanged();
109
0
    }
110
0
}
111
112
int
113
SimpleCurve::compareToSameClass(const Geometry* ls) const
114
0
{
115
0
    const SimpleCurve* line = detail::down_cast<const SimpleCurve*>(ls);
116
117
    // MD - optimized implementation
118
0
    std::size_t mynpts = points->getSize();
119
0
    std::size_t othnpts = line->points->getSize();
120
0
    if (mynpts > othnpts) {
121
0
        return 1;
122
0
    }
123
0
    if (mynpts < othnpts) {
124
0
        return -1;
125
0
    }
126
0
    for (std::size_t i = 0; i < mynpts; i++) {
127
0
        int cmp = points->getAt<CoordinateXY>(i).compareTo(line->points->getAt<CoordinateXY>(i));
128
0
        if (cmp) {
129
0
            return cmp;
130
0
        }
131
0
    }
132
0
    return 0;
133
0
}
134
135
Envelope
136
SimpleCurve::computeEnvelopeInternal(bool isLinear) const
137
8.48M
{
138
8.48M
    if (isEmpty()) {
139
1.66M
        return Envelope();
140
1.66M
    }
141
142
6.82M
    if (isLinear) {
143
6.51M
        return points->getEnvelope();
144
6.51M
    }
145
306k
    else {
146
306k
        Envelope e;
147
964k
        for (std::size_t i = 2; i < points->size(); i += 2) {
148
657k
            algorithm::CircularArcs::expandEnvelope(e,
149
657k
                                                    points->getAt<CoordinateXY>(i-2),
150
657k
                                                    points->getAt<CoordinateXY>(i-1),
151
657k
                                                    points->getAt<CoordinateXY>(i));
152
657k
        }
153
306k
        return e;
154
306k
    }
155
6.82M
}
156
157
bool
158
SimpleCurve::equalsExact(const Geometry* other, double tolerance) const
159
0
{
160
0
    if (!isEquivalentClass(other)) {
161
0
        return false;
162
0
    }
163
164
0
    const SimpleCurve* otherCurve = detail::down_cast<const SimpleCurve*>(other);
165
0
    std::size_t npts = points->getSize();
166
0
    if (npts != otherCurve->points->getSize()) {
167
0
        return false;
168
0
    }
169
0
    for (std::size_t i = 0; i < npts; ++i) {
170
0
        if (!equal(points->getAt<CoordinateXY>(i), otherCurve->points->getAt<CoordinateXY>(i), tolerance)) {
171
0
            return false;
172
0
        }
173
0
    }
174
0
    return true;
175
0
}
176
177
bool
178
SimpleCurve::equalsIdentical(const Geometry* other_g) const
179
0
{
180
0
    if (!isEquivalentClass(other_g)) {
181
0
        return false;
182
0
    }
183
184
0
    const auto& other = static_cast<const SimpleCurve&>(*other_g);
185
186
0
    if (envelope != other.envelope) {
187
0
        return false;
188
0
    }
189
190
0
    return getCoordinatesRO()->equalsIdentical(*other.getCoordinatesRO());
191
0
}
192
193
std::unique_ptr<Geometry>
194
SimpleCurve::getBoundary() const
195
10.9k
{
196
10.9k
    operation::BoundaryOp bop(*this);
197
10.9k
    return bop.getBoundary();
198
10.9k
}
199
200
const CoordinateXY*
201
SimpleCurve::getCoordinate() const
202
13.0k
{
203
13.0k
    if (isEmpty()) {
204
0
        return nullptr;
205
0
    }
206
13.0k
    return &(points->getAt<CoordinateXY>(0));
207
13.0k
}
208
209
uint8_t
210
SimpleCurve::getCoordinateDimension() const
211
1.30M
{
212
1.30M
    return (uint8_t) points->getDimension();
213
1.30M
}
214
215
const Coordinate&
216
SimpleCurve::getCoordinateN(std::size_t n) const
217
38.3k
{
218
38.3k
    assert(points.get());
219
38.3k
    return points->getAt(n);
220
38.3k
}
221
222
std::unique_ptr<CoordinateSequence>
223
SimpleCurve::getCoordinates() const
224
38.5k
{
225
38.5k
    assert(points.get());
226
38.5k
    return points->clone();
227
38.5k
}
228
229
const CoordinateSequence*
230
SimpleCurve::getCoordinatesRO() const
231
7.88M
{
232
7.88M
    assert(nullptr != points.get());
233
7.88M
    return points.get();
234
7.88M
}
235
236
const std::shared_ptr<const CoordinateSequence>&
237
SimpleCurve::getSharedCoordinates() const
238
4.35M
{
239
4.35M
    assert(nullptr != points.get());
240
4.35M
    return points;
241
4.35M
}
242
243
const SimpleCurve*
244
SimpleCurve::getCurveN(std::size_t) const
245
162k
{
246
162k
    return this;
247
162k
}
248
249
const CoordinateXY&
250
SimpleCurve::getEndCoordinate() const
251
0
{
252
0
    if (isEmpty()) {
253
0
        return CoordinateXY::getNull();
254
0
    }
255
0
    return points->back<CoordinateXY>();
256
0
}
257
258
std::unique_ptr<Point>
259
SimpleCurve::getEndPoint() const
260
10.8k
{
261
10.8k
    if (isEmpty()) {
262
0
        return nullptr;
263
0
    }
264
10.8k
    return getPointN(getNumPoints() - 1);
265
10.8k
}
266
267
std::size_t
268
SimpleCurve::getNumCurves() const
269
326k
{
270
326k
    return isEmpty() ? 0 : 1;
271
326k
}
272
273
std::size_t
274
SimpleCurve::getNumPoints() const
275
264k
{
276
264k
    assert(points.get());
277
264k
    return points->getSize();
278
264k
}
279
280
std::unique_ptr<Point>
281
SimpleCurve::getPointN(std::size_t n) const
282
26.2k
{
283
26.2k
    assert(getFactory());
284
26.2k
    assert(points.get());
285
286
26.2k
    return points->applyAt(n, [this](const auto& c) {
287
26.2k
        return getFactory()->createPoint(c);
288
26.2k
    });
SimpleCurve.cpp:auto geos::geom::SimpleCurve::getPointN(unsigned long) const::$_0::operator()<geos::geom::Coordinate>(geos::geom::Coordinate const&) const
Line
Count
Source
286
22.0k
    return points->applyAt(n, [this](const auto& c) {
287
22.0k
        return getFactory()->createPoint(c);
288
22.0k
    });
Unexecuted instantiation: SimpleCurve.cpp:auto geos::geom::SimpleCurve::getPointN(unsigned long) const::$_0::operator()<geos::geom::CoordinateXYM>(geos::geom::CoordinateXYM const&) const
SimpleCurve.cpp:auto geos::geom::SimpleCurve::getPointN(unsigned long) const::$_0::operator()<geos::geom::CoordinateXYZM>(geos::geom::CoordinateXYZM const&) const
Line
Count
Source
286
4.22k
    return points->applyAt(n, [this](const auto& c) {
287
4.22k
        return getFactory()->createPoint(c);
288
4.22k
    });
Unexecuted instantiation: SimpleCurve.cpp:auto geos::geom::SimpleCurve::getPointN(unsigned long) const::$_0::operator()<geos::geom::CoordinateXY>(geos::geom::CoordinateXY const&) const
289
26.2k
}
290
291
const CoordinateXY&
292
SimpleCurve::getStartCoordinate() const
293
0
{
294
0
    if (isEmpty()) {
295
0
        return CoordinateXY::getNull();
296
0
    }
297
0
    return points->front<CoordinateXY>();
298
0
}
299
300
std::unique_ptr<Point>
301
SimpleCurve::getStartPoint() const
302
10.8k
{
303
10.8k
    if (isEmpty()) {
304
0
        return nullptr;
305
0
    }
306
10.8k
    return getPointN(0);
307
10.8k
}
308
309
bool
310
SimpleCurve::hasM() const
311
4.30M
{
312
4.30M
    return points->hasM();
313
4.30M
}
314
315
bool
316
SimpleCurve::hasZ() const
317
4.31M
{
318
4.31M
    return points->hasZ();
319
4.31M
}
320
321
bool
322
SimpleCurve::isClosed() const
323
2.61M
{
324
2.61M
    if (isEmpty()) {
325
248
        return false;
326
248
    }
327
328
2.61M
    return points->front<CoordinateXY>().equals2D(points->back<CoordinateXY>());
329
2.61M
}
330
331
bool
332
SimpleCurve::isCoordinate(CoordinateXY& pt) const
333
0
{
334
0
    assert(points.get());
335
0
    std::size_t npts = points->getSize();
336
0
    for (std::size_t i = 0; i < npts; i++) {
337
0
        if (points->getAt<CoordinateXY>(i) == pt) {
338
0
            return true;
339
0
        }
340
0
    }
341
0
    return false;
342
0
}
343
344
bool
345
SimpleCurve::isEmpty() const
346
34.9M
{
347
34.9M
    assert(points.get());
348
34.9M
    return points->isEmpty();
349
34.9M
}
350
351
std::unique_ptr<SimpleCurve>
352
SimpleCurve::clone() const
353
2.49k
{
354
2.49k
    return std::unique_ptr<SimpleCurve>(static_cast<SimpleCurve*>(cloneImpl()));
355
2.49k
}
356
357
std::unique_ptr<SimpleCurve>
358
SimpleCurve::reverse() const
359
146
{
360
146
    return std::unique_ptr<SimpleCurve>(static_cast<SimpleCurve*>(reverseImpl()));
361
146
}
362
363
} // namespace geos::geom
364
} // namespace geos