/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 | 7.88M | : Curve(other), |
36 | 7.88M | points(other.points->clone()), |
37 | 7.88M | envelope(other.envelope) |
38 | 7.88M | { |
39 | 7.88M | } |
40 | | |
41 | | SimpleCurve::SimpleCurve(const std::shared_ptr<const CoordinateSequence>& newCoords, |
42 | | bool isLinear, |
43 | | const GeometryFactory& factory) |
44 | 218k | : Curve(factory), |
45 | 218k | points(newCoords), |
46 | 218k | envelope(computeEnvelopeInternal(isLinear)) |
47 | 218k | { |
48 | 218k | } |
49 | | |
50 | | SimpleCurve::SimpleCurve(std::unique_ptr<CoordinateSequence>&& newCoords, |
51 | | bool isLinear, |
52 | | const GeometryFactory& factory) |
53 | 5.01M | : Curve(factory), |
54 | 5.01M | points(newCoords ? std::move(newCoords) : std::make_shared<CoordinateSequence>()), |
55 | 5.01M | envelope(computeEnvelopeInternal(isLinear)) |
56 | 5.01M | { |
57 | 5.01M | } |
58 | | |
59 | | void |
60 | | SimpleCurve::apply_ro(CoordinateFilter* filter) const |
61 | 0 | { |
62 | 0 | assert(points.get()); |
63 | 0 | points->apply_ro(filter); |
64 | 0 | } |
65 | | |
66 | | void |
67 | | SimpleCurve::apply_ro(CoordinateSequenceFilter& filter) const |
68 | 873k | { |
69 | 873k | std::size_t npts = points->size(); |
70 | 873k | if (!npts) { |
71 | 2.13k | return; |
72 | 2.13k | } |
73 | 2.06M | for (std::size_t i = 0; i < npts; ++i) { |
74 | 1.78M | filter.filter_ro(*points, i); |
75 | 1.78M | if (filter.isDone()) { |
76 | 595k | break; |
77 | 595k | } |
78 | 1.78M | } |
79 | 871k | } |
80 | | |
81 | | void |
82 | | SimpleCurve::apply_rw(const CoordinateFilter* filter) |
83 | 232k | { |
84 | 232k | assert(points.get()); |
85 | 232k | if (points.use_count() > 1) { |
86 | 0 | points = points->clone(); |
87 | 0 | } |
88 | 232k | const_cast<CoordinateSequence*>(points.get())->apply_rw(filter); |
89 | 232k | } |
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 | 5.23M | { |
138 | 5.23M | if (isEmpty()) { |
139 | 118k | return Envelope(); |
140 | 118k | } |
141 | | |
142 | 5.11M | if (isLinear) { |
143 | 5.11M | return points->getEnvelope(); |
144 | 5.11M | } |
145 | 344 | else { |
146 | 344 | Envelope e; |
147 | 33.6k | for (std::size_t i = 2; i < points->size(); i += 2) { |
148 | 33.3k | algorithm::CircularArcs::expandEnvelope(e, |
149 | 33.3k | points->getAt<CoordinateXY>(i-2), |
150 | 33.3k | points->getAt<CoordinateXY>(i-1), |
151 | 33.3k | points->getAt<CoordinateXY>(i)); |
152 | 33.3k | } |
153 | 344 | return e; |
154 | 344 | } |
155 | 5.11M | } |
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 | 0 | { |
196 | 0 | operation::BoundaryOp bop(*this); |
197 | 0 | return bop.getBoundary(); |
198 | 0 | } |
199 | | |
200 | | const CoordinateXY* |
201 | | SimpleCurve::getCoordinate() const |
202 | 0 | { |
203 | 0 | if (isEmpty()) { |
204 | 0 | return nullptr; |
205 | 0 | } |
206 | 0 | return &(points->getAt<CoordinateXY>(0)); |
207 | 0 | } |
208 | | |
209 | | uint8_t |
210 | | SimpleCurve::getCoordinateDimension() const |
211 | 1.64M | { |
212 | 1.64M | return (uint8_t) points->getDimension(); |
213 | 1.64M | } |
214 | | |
215 | | const Coordinate& |
216 | | SimpleCurve::getCoordinateN(std::size_t n) const |
217 | 164 | { |
218 | 164 | assert(points.get()); |
219 | 164 | return points->getAt(n); |
220 | 164 | } |
221 | | |
222 | | std::unique_ptr<CoordinateSequence> |
223 | | SimpleCurve::getCoordinates() const |
224 | 0 | { |
225 | 0 | assert(points.get()); |
226 | 0 | return points->clone(); |
227 | 0 | } |
228 | | |
229 | | const CoordinateSequence* |
230 | | SimpleCurve::getCoordinatesRO() const |
231 | 11.6M | { |
232 | 11.6M | assert(nullptr != points.get()); |
233 | 11.6M | return points.get(); |
234 | 11.6M | } |
235 | | |
236 | | const std::shared_ptr<const CoordinateSequence>& |
237 | | SimpleCurve::getSharedCoordinates() const |
238 | 0 | { |
239 | 0 | assert(nullptr != points.get()); |
240 | 0 | return points; |
241 | 0 | } |
242 | | |
243 | | const SimpleCurve* |
244 | | SimpleCurve::getCurveN(std::size_t) const |
245 | 653 | { |
246 | 653 | return this; |
247 | 653 | } |
248 | | |
249 | | std::unique_ptr<Point> |
250 | | SimpleCurve::getEndPoint() const |
251 | 0 | { |
252 | 0 | if (isEmpty()) { |
253 | 0 | return nullptr; |
254 | 0 | } |
255 | 0 | return getPointN(getNumPoints() - 1); |
256 | 0 | } |
257 | | |
258 | | std::size_t |
259 | | SimpleCurve::getNumCurves() const |
260 | 1.30k | { |
261 | 1.30k | return 1; |
262 | 1.30k | } |
263 | | |
264 | | std::size_t |
265 | | SimpleCurve::getNumPoints() const |
266 | 82 | { |
267 | 82 | assert(points.get()); |
268 | 82 | return points->getSize(); |
269 | 82 | } |
270 | | |
271 | | std::unique_ptr<Point> |
272 | | SimpleCurve::getPointN(std::size_t n) const |
273 | 0 | { |
274 | 0 | assert(getFactory()); |
275 | 0 | assert(points.get()); |
276 | |
|
277 | 0 | return points->applyAt(n, [this](const auto& c) { |
278 | 0 | return getFactory()->createPoint(c); |
279 | 0 | }); Unexecuted instantiation: SimpleCurve.cpp:auto geos::geom::SimpleCurve::getPointN(unsigned long) const::$_0::operator()<geos::geom::Coordinate>(geos::geom::Coordinate const&) const Unexecuted instantiation: SimpleCurve.cpp:auto geos::geom::SimpleCurve::getPointN(unsigned long) const::$_0::operator()<geos::geom::CoordinateXYM>(geos::geom::CoordinateXYM const&) const Unexecuted instantiation: SimpleCurve.cpp:auto geos::geom::SimpleCurve::getPointN(unsigned long) const::$_0::operator()<geos::geom::CoordinateXYZM>(geos::geom::CoordinateXYZM const&) const Unexecuted instantiation: SimpleCurve.cpp:auto geos::geom::SimpleCurve::getPointN(unsigned long) const::$_0::operator()<geos::geom::CoordinateXY>(geos::geom::CoordinateXY const&) const |
280 | 0 | } |
281 | | |
282 | | std::unique_ptr<Point> |
283 | | SimpleCurve::getStartPoint() const |
284 | 0 | { |
285 | 0 | if (isEmpty()) { |
286 | 0 | return nullptr; |
287 | 0 | } |
288 | 0 | return getPointN(0); |
289 | 0 | } |
290 | | |
291 | | bool |
292 | | SimpleCurve::hasM() const |
293 | 6.99M | { |
294 | 6.99M | return points->hasM(); |
295 | 6.99M | } |
296 | | |
297 | | bool |
298 | | SimpleCurve::hasZ() const |
299 | 7.34M | { |
300 | 7.34M | return points->hasZ(); |
301 | 7.34M | } |
302 | | |
303 | | bool |
304 | | SimpleCurve::isClosed() const |
305 | 2.75M | { |
306 | 2.75M | if (isEmpty()) { |
307 | 15 | return false; |
308 | 15 | } |
309 | | |
310 | 2.75M | return points->front<CoordinateXY>().equals2D(points->back<CoordinateXY>()); |
311 | 2.75M | } |
312 | | |
313 | | bool |
314 | | SimpleCurve::isCoordinate(CoordinateXY& pt) const |
315 | 0 | { |
316 | 0 | assert(points.get()); |
317 | 0 | std::size_t npts = points->getSize(); |
318 | 0 | for (std::size_t i = 0; i < npts; i++) { |
319 | 0 | if (points->getAt<CoordinateXY>(i) == pt) { |
320 | 0 | return true; |
321 | 0 | } |
322 | 0 | } |
323 | 0 | return false; |
324 | 0 | } |
325 | | |
326 | | bool |
327 | | SimpleCurve::isEmpty() const |
328 | 31.4M | { |
329 | 31.4M | assert(points.get()); |
330 | 31.4M | return points->isEmpty(); |
331 | 31.4M | } |
332 | | |
333 | | /*public*/ |
334 | | void |
335 | | SimpleCurve::normalize() |
336 | 0 | { |
337 | 0 | util::ensureNoCurvedComponents(*this); |
338 | |
|
339 | 0 | if (isEmpty()) return; |
340 | 0 | assert(points.get()); |
341 | 0 | if (isClosed()) { |
342 | 0 | normalizeClosed(); |
343 | 0 | return; |
344 | 0 | } |
345 | 0 | std::size_t npts = points->getSize(); |
346 | 0 | std::size_t n = npts / 2; |
347 | 0 | for (std::size_t i = 0; i < n; i++) { |
348 | 0 | std::size_t j = npts - 1 - i; |
349 | 0 | if (!(points->getAt<CoordinateXY>(i) == points->getAt<CoordinateXY>(j))) { |
350 | 0 | if (points->getAt<CoordinateXY>(i).compareTo(points->getAt<CoordinateXY>(j)) > 0) { |
351 | 0 | if (points.use_count() > 1) { |
352 | 0 | points = points->clone(); |
353 | 0 | } |
354 | 0 | const_cast<CoordinateSequence*>(points.get())->reverse(); |
355 | 0 | } |
356 | 0 | return; |
357 | 0 | } |
358 | 0 | } |
359 | 0 | } |
360 | | |
361 | | /*private*/ |
362 | | void |
363 | | SimpleCurve::normalizeClosed() |
364 | 0 | { |
365 | 0 | if (isEmpty()) { |
366 | 0 | return; |
367 | 0 | } |
368 | | |
369 | 0 | const auto& ringCoords = getCoordinatesRO(); |
370 | |
|
371 | 0 | auto coords = detail::make_unique<CoordinateSequence>(0u, ringCoords->hasZ(), ringCoords->hasM()); |
372 | 0 | coords->reserve(ringCoords->size()); |
373 | | // exclude last point (repeated) |
374 | 0 | coords->add(*ringCoords, 0, ringCoords->size() - 2); |
375 | |
|
376 | 0 | const CoordinateXY* minCoordinate = coords->minCoordinate(); |
377 | |
|
378 | 0 | CoordinateSequence::scroll(coords.get(), minCoordinate); |
379 | 0 | coords->closeRing(true); |
380 | |
|
381 | 0 | if (coords->size() >= 4 && algorithm::Orientation::isCCW(coords.get())) { |
382 | 0 | coords->reverse(); |
383 | 0 | } |
384 | |
|
385 | 0 | points = std::move(coords); |
386 | 0 | } |
387 | | |
388 | | } // namespace geos::geom |
389 | | } // namespace geos |