GEOS 3.15.0dev
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
24namespace geos {
25namespace geom {
26
29class GEOS_DLL CircularArc {
30public:
31
35
40 CircularArc(const CoordinateSequence&, std::size_t pos);
41 CircularArc(const CoordinateSequence&, std::size_t pos, const CoordinateXY& center, double radius, int orientation);
42
47 CircularArc(std::unique_ptr<CoordinateSequence>, std::size_t pos);
48 CircularArc(std::unique_ptr<CoordinateSequence>, std::size_t pos, const CoordinateXY& center, double radius, int orientation);
49
50 CircularArc(const CircularArc& other);
51
52 CircularArc(CircularArc&&) noexcept;
53
54 CircularArc& operator=(const CircularArc& other);
55 CircularArc& operator=(CircularArc&&) noexcept;
56
57 ~CircularArc();
58
62 template<typename CoordType>
63 static CircularArc create(const CoordType& p0, const CoordType& p1, const CoordType& p2)
64 {
65 auto seq = std::make_unique<CoordinateSequence>(3, CoordType::template has<Ordinate::Z>(), CoordType::template has<Ordinate::M>());
66 seq->setAt(p0, 0);
67 seq->setAt(p1, 1);
68 seq->setAt(p2, 2);
69
70 CircularArc ret(std::move(seq), 0);
71
72 return ret;
73 }
74
75 static CircularArc create(const CoordinateXY& p0, const CoordinateXY& p2, const CoordinateXY& center, double radius, int orientation);
76 static CircularArc create(const Coordinate& p0, const Coordinate& p2, const CoordinateXY& center, double radius, int orientation);
77 static CircularArc create(const CoordinateXYM& p0, const CoordinateXYM& p2, const CoordinateXY& center, double radius, int orientation);
78 static CircularArc create(const CoordinateXYZM& p0, const CoordinateXYZM& p2, const CoordinateXY& center, double radius, int orientation);
79
81 double getAngle() const;
82
84 double getArea() const;
85
87 const CoordinateXY& getCenter() const {
88 if (!m_center_known) {
89 if (isCCW()) {
90 m_center = algorithm::CircularArcs::getCenter(p0(), p1(), p2());
91 } else {
92 m_center = algorithm::CircularArcs::getCenter(p2(), p1(), p0());
93 }
94 m_center_known = true;
95 }
96
97 return m_center;
98 }
99
100 const CoordinateSequence* getCoordinateSequence() const {
101 return m_seq;
102 }
103
104 std::size_t getCoordinatePosition() const {
105 return m_pos;
106 }
107
111 CoordinateXY getDirectionPoint() const;
112
113 Envelope getEnvelope() const;
114
116 double getLength() const;
117
122 int getOrientation() const {
123 if (!m_orientation_known) {
124 m_orientation = algorithm::Orientation::index(p0(), p1(), p2());
125 m_orientation_known = true;
126 }
127 return m_orientation;
128 }
129
131 double getRadius() const {
132 if (!m_radius_known) {
133 if (isCCW()) {
134 m_radius = getCenter().distance(p0());
135 } else {
136 m_radius = getCenter().distance(p2());
137 }
138 m_radius_known = true;
139 }
140
141 return m_radius;
142 }
143
145 double getSagitta() const {
146 CoordinateXY midpoint = algorithm::CircularArcs::getMidpoint(p0(), p2(), getCenter(), getRadius(), isCCW());
147 return algorithm::Distance::pointToSegment(midpoint, p0(), p2());
148 }
149
150 bool isCCW() const {
151 return getOrientation() == algorithm::Orientation::COUNTERCLOCKWISE;
152 }
153
155 bool isCircle() const {
156 return p0().equals(p2());
157 }
158
160 bool isLinear() const {
161 return !std::isfinite(getRadius());
162 }
163
165 double theta0() const {
166 return algorithm::CircularArcs::getAngle(p0(), getCenter());
167 }
168
170 double theta1() const {
171 return algorithm::CircularArcs::getAngle(p1(), getCenter());
172 }
173
175 double theta2() const {
176 return algorithm::CircularArcs::getAngle(p2(), getCenter());
177 }
179 bool containsAngle(double theta) const;
180
183 bool containsPoint(const CoordinateXY& q) const;
184
188 bool containsPointOnCircle(const CoordinateXY& q) const {
189 double theta = std::atan2(q.y - getCenter().y, q.x - getCenter().x);
190 return containsAngle(theta);
191 }
192
193 CoordinateXY closestPoint(const CoordinateXY& p) const;
194 std::array<CoordinateXY, 2> closestPoints(const CoordinateXY& p1, const CoordinateXY& p2) const;
195 std::array<CoordinateXY, 2> closestPoints(const CircularArc& other) const;
196
197 double distance(const CoordinateXY& p) const;
198 double distance(const CoordinateXY& p1, const CoordinateXY& p2) const;
199 double distance(const CircularArc& other) const;
200
204 bool isUpwardAtPoint(const CoordinateXY& q) const;
205
206 CircularArc reverse() const;
207
208 // Split an arc at a specified point.
209 // The point is assumed to be on the arc.
210 //std::pair<CircularArc, CircularArc> splitAtPoint(const CoordinateXY& q) const;
211
212 bool equals(const CircularArc& other, double tol) const;
213
214 class Iterator {
215 public:
216 using iterator_category = std::forward_iterator_tag;
217 using difference_type = std::ptrdiff_t;
218 using value_type = geom::CoordinateXY;
219 using pointer = const geom::CoordinateXY*;
220 using reference = const geom::CoordinateXY&;
221
222 Iterator(const CircularArc& arc, int i) : m_arc(arc), m_i(i) {}
223
224 reference operator*() const {
225 return m_i == 0 ? m_arc.p0() : (m_i == 1 ? m_arc.p1() : m_arc.p2());
226 }
227
228 Iterator& operator++() {
229 m_i++;
230 return *this;
231 }
232
233 Iterator operator++(int) {
234 Iterator ret = *this;
235 m_i++;
236 return ret;
237 }
238
239 bool operator==(const Iterator& other) const {
240 return m_i == other.m_i;
241 }
242
243 bool operator!=(const Iterator& other) const {
244 return !(*this == other);
245 }
246
247 private:
248 const CircularArc& m_arc;
249 int m_i;
250
251 };
252
253 Iterator begin() const {
254 return Iterator(*this, 0);
255 }
256
257 Iterator end() const {
258 return Iterator(*this, 3);
259 }
260
261 template<typename T=CoordinateXY>
262 const T& p0() const {
263 return m_seq->getAt<T>(m_pos);
264 }
265
266 template<typename T=CoordinateXY>
267 const T& p1() const {
268 return m_seq->getAt<T>(m_pos + 1);
269 }
270
271 template<typename T=CoordinateXY>
272 const T& p2() const {
273 return m_seq->getAt<T>(m_pos + 2);
274 }
275
276 std::string toString() const;
277
278 template<typename F>
279 auto applyAt(std::size_t i, F&& f) const {
280 return m_seq->applyAt(m_pos + i, f);
281 }
282
283private:
284 const CoordinateSequence* m_seq;
285 std::size_t m_pos;
286
287 mutable CoordinateXY m_center;
288 mutable double m_radius;
289 mutable int m_orientation;
290 mutable bool m_center_known = false;
291 mutable bool m_radius_known = false;
292 mutable bool m_orientation_known = false;
293 bool m_own_coordinates;
294};
295
296}
297}
Definition CircularArc.h:29
CoordinateXY getDirectionPoint() const
bool containsPointOnCircle(const CoordinateXY &q) const
Definition CircularArc.h:188
bool isUpwardAtPoint(const CoordinateXY &q) const
CircularArc(std::unique_ptr< CoordinateSequence >, std::size_t pos)
bool isCircle() const
Return whether this arc forms a complete circle.
Definition CircularArc.h:155
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:122
const CoordinateXY & getCenter() const
Return the center point of the circle associated with this arc.
Definition CircularArc.h:87
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:145
bool isLinear() const
Returns whether this arc forms a straight line (p0, p1, and p2 are collinear)
Definition CircularArc.h:160
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:131
bool containsPoint(const CoordinateXY &q) const
double theta0() const
Return the angle of p0.
Definition CircularArc.h:165
double theta1() const
Return the angle of p1.
Definition CircularArc.h:170
double theta2() const
Return the angle of p2.
Definition CircularArc.h:175
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
Basic namespace for all GEOS functionalities.
Definition geos.h:38