GEOS 3.15.0beta1
CircularArc.h
1/**********************************************************************
2 *
3 * GEOS - Geometry Engine Open Source
4 * http://geos.osgeo.org
5 *
6 * Copyright (C) 2024-2025 ISciences, LLC
7 *
8 * This is free software; you can redistribute and/or modify it under
9 * the terms of the GNU Lesser General Public Licence as published
10 * by the Free Software Foundation.
11 * See the COPYING file for more information.
12 *
13 **********************************************************************/
14
15#pragma once
16
17#include <geos/export.h>
18#include <geos/geom/Coordinate.h>
19#include <geos/geom/LineSegment.h>
20#include <geos/geom/Quadrant.h>
21#include <geos/algorithm/CircularArcs.h>
22#include <geos/algorithm/Orientation.h>
23
24// Forward declarations
25namespace geos::algorithm {
26class CurveToLineParams;
27}
28
29namespace geos {
30namespace geom {
31
34class GEOS_DLL CircularArc {
35public:
36
40
45 CircularArc(const CoordinateSequence&, std::size_t pos);
46 CircularArc(const CoordinateSequence&, std::size_t pos, const CoordinateXY& center, double radius, int orientation);
47
52 CircularArc(std::unique_ptr<CoordinateSequence>, std::size_t pos);
53 CircularArc(std::unique_ptr<CoordinateSequence>, std::size_t pos, const CoordinateXY& center, double radius, int orientation);
54
55 CircularArc(const CircularArc& other);
56
57 CircularArc(CircularArc&&) noexcept;
58
59 CircularArc& operator=(const CircularArc& other);
60 CircularArc& operator=(CircularArc&&) noexcept;
61
62 ~CircularArc();
63
67 template<typename CoordType>
68 static CircularArc create(const CoordType& p0, const CoordType& p1, const CoordType& p2)
69 {
70 auto seq = std::make_unique<CoordinateSequence>(3, CoordType::template has<Ordinate::Z>(), CoordType::template has<Ordinate::M>());
71 seq->setAt(p0, 0);
72 seq->setAt(p1, 1);
73 seq->setAt(p2, 2);
74
75 CircularArc ret(std::move(seq), 0);
76
77 return ret;
78 }
79
80 static CircularArc create(const CoordinateXY& p0, const CoordinateXY& p2, const CoordinateXY& center, double radius, int orientation);
81 static CircularArc create(const Coordinate& p0, const Coordinate& p2, const CoordinateXY& center, double radius, int orientation);
82 static CircularArc create(const CoordinateXYM& p0, const CoordinateXYM& p2, const CoordinateXY& center, double radius, int orientation);
83 static CircularArc create(const CoordinateXYZM& p0, const CoordinateXYZM& p2, const CoordinateXY& center, double radius, int orientation);
84
86 double getAngle() const;
87
89 double getArea() const;
90
92 const CoordinateXY& getCenter() const {
93 if (!m_center_known) {
94 if (isCCW()) {
95 m_center = algorithm::CircularArcs::getCenter(p0(), p1(), p2());
96 } else {
97 m_center = algorithm::CircularArcs::getCenter(p2(), p1(), p0());
98 }
99 m_center_known = true;
100 }
101
102 return m_center;
103 }
104
105 const CoordinateSequence* getCoordinateSequence() const {
106 return m_seq;
107 }
108
109 std::size_t getCoordinatePosition() const {
110 return m_pos;
111 }
112
116 CoordinateXY getDirectionPoint() const;
117
118 CoordinateXY getReverseDirectionPoint() const;
119
120 Envelope getEnvelope() const;
121
123 double getLength() const;
124
127 void addLinearizedPoints(CoordinateSequence& seq, const algorithm::CurveToLineParams& params) const;
128
133 int getOrientation() const {
134 if (!m_orientation_known) {
135 m_orientation = algorithm::Orientation::index(p0(), p1(), p2());
136 m_orientation_known = true;
137 }
138 return m_orientation;
139 }
140
142 double getRadius() const {
143 if (!m_radius_known) {
144 if (isCCW()) {
145 m_radius = getCenter().distance(p0());
146 } else {
147 m_radius = getCenter().distance(p2());
148 }
149 m_radius_known = true;
150 }
151
152 return m_radius;
153 }
154
156 double getSagitta() const {
157 CoordinateXY midpoint = algorithm::CircularArcs::getMidpoint(p0(), p2(), getCenter(), getRadius(), isCCW());
158 return algorithm::Distance::pointToSegment(midpoint, p0(), p2());
159 }
160
161 bool isCCW() const {
162 return getOrientation() == algorithm::Orientation::COUNTERCLOCKWISE;
163 }
164
166 bool isCircle() const {
167 return p0().equals(p2());
168 }
169
171 bool isLinear() const {
172 return !std::isfinite(getRadius());
173 }
174
176 double theta0() const {
177 return algorithm::CircularArcs::getAngle(p0(), getCenter());
178 }
179
181 double theta1() const {
182 return algorithm::CircularArcs::getAngle(p1(), getCenter());
183 }
184
186 double theta2() const {
187 return algorithm::CircularArcs::getAngle(p2(), getCenter());
188 }
189
190 bool containsAngle(double theta) const;
191
194 bool containsPoint(const CoordinateXY& q) const;
195
199 bool containsPointOnCircle(const CoordinateXY& q) const {
200 double theta = std::atan2(q.y - getCenter().y, q.x - getCenter().x);
201 return containsAngle(theta);
202 }
203
204 CoordinateXY closestPoint(const CoordinateXY& p) const;
205 std::array<CoordinateXY, 2> closestPoints(const CoordinateXY& p1, const CoordinateXY& p2) const;
206 std::array<CoordinateXY, 2> closestPoints(const CircularArc& other) const;
207
208 double distance(const CoordinateXY& p) const;
209 double distance(const CoordinateXY& p1, const CoordinateXY& p2) const;
210 double distance(const CircularArc& other) const;
211
215 bool isUpwardAtPoint(const CoordinateXY& q) const;
216
217 CircularArc reverse() const;
218
219 // Split an arc at a specified point.
220 // The point is assumed to be on the arc.
221 //std::pair<CircularArc, CircularArc> splitAtPoint(const CoordinateXY& q) const;
222
223 bool equals(const CircularArc& other, double tol) const;
224
225 class Iterator {
226 public:
227 using iterator_category = std::forward_iterator_tag;
228 using difference_type = std::ptrdiff_t;
229 using value_type = geom::CoordinateXY;
230 using pointer = const geom::CoordinateXY*;
231 using reference = const geom::CoordinateXY&;
232
233 Iterator(const CircularArc& arc, int i) : m_arc(arc), m_i(i) {}
234
235 reference operator*() const {
236 return m_i == 0 ? m_arc.p0() : (m_i == 1 ? m_arc.p1() : m_arc.p2());
237 }
238
239 Iterator& operator++() {
240 m_i++;
241 return *this;
242 }
243
244 Iterator operator++(int) {
245 Iterator ret = *this;
246 m_i++;
247 return ret;
248 }
249
250 bool operator==(const Iterator& other) const {
251 return m_i == other.m_i;
252 }
253
254 bool operator!=(const Iterator& other) const {
255 return !(*this == other);
256 }
257
258 private:
259 const CircularArc& m_arc;
260 int m_i;
261
262 };
263
264 Iterator begin() const {
265 return Iterator(*this, 0);
266 }
267
268 Iterator end() const {
269 return Iterator(*this, 3);
270 }
271
272 template<typename T=CoordinateXY>
273 const T& p0() const {
274 return m_seq->getAt<T>(m_pos);
275 }
276
277 template<typename T=CoordinateXY>
278 const T& p1() const {
279 return m_seq->getAt<T>(m_pos + 1);
280 }
281
282 template<typename T=CoordinateXY>
283 const T& p2() const {
284 return m_seq->getAt<T>(m_pos + 2);
285 }
286
287 std::string toString() const;
288
289 template<typename F>
290 auto applyAt(std::size_t i, F&& f) const {
291 return m_seq->applyAt(m_pos + i, f);
292 }
293
294private:
295 const CoordinateSequence* m_seq;
296 std::size_t m_pos;
297
298 mutable CoordinateXY m_center;
299 mutable double m_radius;
300 mutable int m_orientation;
301 mutable bool m_center_known = false;
302 mutable bool m_radius_known = false;
303 mutable bool m_orientation_known = false;
304 bool m_own_coordinates;
305};
306
307}
308}
static double pointToSegment(const geom::CoordinateXY &p, const geom::CoordinateXY &A, const geom::CoordinateXY &B)
static int index(const geom::CoordinateXY &p1, const geom::CoordinateXY &p2, const geom::CoordinateXY &q)
Returns the orientation index of the direction of the point q relative to a directed infinite line sp...
Definition CircularArc.h:34
CoordinateXY getDirectionPoint() const
bool containsPointOnCircle(const CoordinateXY &q) const
Definition CircularArc.h:199
bool isUpwardAtPoint(const CoordinateXY &q) const
static CircularArc create(const CoordType &p0, const CoordType &p1, const CoordType &p2)
Definition CircularArc.h:68
CircularArc(std::unique_ptr< CoordinateSequence >, std::size_t pos)
bool isCircle() const
Return whether this arc forms a complete circle.
Definition CircularArc.h:166
CircularArc(const CoordinateSequence &, std::size_t pos)
bool containsAngle(double theta) const
Check to see if a given angle lies on this arc.
int getOrientation() const
Definition CircularArc.h:133
const CoordinateXY & getCenter() const
Return the center point of the circle associated with this arc.
Definition CircularArc.h:92
double getSagitta() const
Return the distance from the centerpoint of the arc to the line segment formed by the end points of t...
Definition CircularArc.h:156
void addLinearizedPoints(CoordinateSequence &seq, const algorithm::CurveToLineParams &params) const
bool isLinear() const
Returns whether this arc forms a straight line (p0, p1, and p2 are collinear).
Definition CircularArc.h:171
double getAngle() const
Return the inner angle of the sector associated with this arc.
double getLength() const
Return the length of the arc.
double getArea() const
Return the area enclosed by the arc p0-p1-p2 and the line segment p2-p0.
double getRadius() const
Return the radius of the circle associated with this arc.
Definition CircularArc.h:142
bool containsPoint(const CoordinateXY &q) const
double theta0() const
Return the angle of p0.
Definition CircularArc.h:176
double theta1() const
Return the angle of p1.
Definition CircularArc.h:181
double theta2() const
Return the angle of p2.
Definition CircularArc.h:186
The internal representation of a list of coordinates inside a Geometry.
Definition CoordinateSequence.h:56
Coordinate is the lightweight class used to store coordinates.
Definition Coordinate.h:220
An Envelope defines a rectangulare region of the 2D coordinate plane.
Definition Envelope.h:59
Contains classes and interfaces implementing fundamental computational geometry algorithms.
Definition Angle.h:32
Definition Angle.h:26
Basic namespace for all GEOS functionalities.
Definition geos.h:38