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 CoordinateXY getReverseDirectionPoint() const;
114
115 Envelope getEnvelope() const;
116
118 double getLength() const;
119
124 int getOrientation() const {
125 if (!m_orientation_known) {
126 m_orientation = algorithm::Orientation::index(p0(), p1(), p2());
127 m_orientation_known = true;
128 }
129 return m_orientation;
130 }
131
133 double getRadius() const {
134 if (!m_radius_known) {
135 if (isCCW()) {
136 m_radius = getCenter().distance(p0());
137 } else {
138 m_radius = getCenter().distance(p2());
139 }
140 m_radius_known = true;
141 }
142
143 return m_radius;
144 }
145
147 double getSagitta() const {
148 CoordinateXY midpoint = algorithm::CircularArcs::getMidpoint(p0(), p2(), getCenter(), getRadius(), isCCW());
149 return algorithm::Distance::pointToSegment(midpoint, p0(), p2());
150 }
151
152 bool isCCW() const {
153 return getOrientation() == algorithm::Orientation::COUNTERCLOCKWISE;
154 }
155
157 bool isCircle() const {
158 return p0().equals(p2());
159 }
160
162 bool isLinear() const {
163 return !std::isfinite(getRadius());
164 }
165
167 double theta0() const {
168 return algorithm::CircularArcs::getAngle(p0(), getCenter());
169 }
170
172 double theta1() const {
173 return algorithm::CircularArcs::getAngle(p1(), getCenter());
174 }
175
177 double theta2() const {
178 return algorithm::CircularArcs::getAngle(p2(), getCenter());
179 }
181 bool containsAngle(double theta) const;
182
185 bool containsPoint(const CoordinateXY& q) const;
186
190 bool containsPointOnCircle(const CoordinateXY& q) const {
191 double theta = std::atan2(q.y - getCenter().y, q.x - getCenter().x);
192 return containsAngle(theta);
193 }
194
195 CoordinateXY closestPoint(const CoordinateXY& p) const;
196 std::array<CoordinateXY, 2> closestPoints(const CoordinateXY& p1, const CoordinateXY& p2) const;
197 std::array<CoordinateXY, 2> closestPoints(const CircularArc& other) const;
198
199 double distance(const CoordinateXY& p) const;
200 double distance(const CoordinateXY& p1, const CoordinateXY& p2) const;
201 double distance(const CircularArc& other) const;
202
206 bool isUpwardAtPoint(const CoordinateXY& q) const;
207
208 CircularArc reverse() const;
209
210 // Split an arc at a specified point.
211 // The point is assumed to be on the arc.
212 //std::pair<CircularArc, CircularArc> splitAtPoint(const CoordinateXY& q) const;
213
214 bool equals(const CircularArc& other, double tol) const;
215
216 class Iterator {
217 public:
218 using iterator_category = std::forward_iterator_tag;
219 using difference_type = std::ptrdiff_t;
220 using value_type = geom::CoordinateXY;
221 using pointer = const geom::CoordinateXY*;
222 using reference = const geom::CoordinateXY&;
223
224 Iterator(const CircularArc& arc, int i) : m_arc(arc), m_i(i) {}
225
226 reference operator*() const {
227 return m_i == 0 ? m_arc.p0() : (m_i == 1 ? m_arc.p1() : m_arc.p2());
228 }
229
230 Iterator& operator++() {
231 m_i++;
232 return *this;
233 }
234
235 Iterator operator++(int) {
236 Iterator ret = *this;
237 m_i++;
238 return ret;
239 }
240
241 bool operator==(const Iterator& other) const {
242 return m_i == other.m_i;
243 }
244
245 bool operator!=(const Iterator& other) const {
246 return !(*this == other);
247 }
248
249 private:
250 const CircularArc& m_arc;
251 int m_i;
252
253 };
254
255 Iterator begin() const {
256 return Iterator(*this, 0);
257 }
258
259 Iterator end() const {
260 return Iterator(*this, 3);
261 }
262
263 template<typename T=CoordinateXY>
264 const T& p0() const {
265 return m_seq->getAt<T>(m_pos);
266 }
267
268 template<typename T=CoordinateXY>
269 const T& p1() const {
270 return m_seq->getAt<T>(m_pos + 1);
271 }
272
273 template<typename T=CoordinateXY>
274 const T& p2() const {
275 return m_seq->getAt<T>(m_pos + 2);
276 }
277
278 std::string toString() const;
279
280 template<typename F>
281 auto applyAt(std::size_t i, F&& f) const {
282 return m_seq->applyAt(m_pos + i, f);
283 }
284
285private:
286 const CoordinateSequence* m_seq;
287 std::size_t m_pos;
288
289 mutable CoordinateXY m_center;
290 mutable double m_radius;
291 mutable int m_orientation;
292 mutable bool m_center_known = false;
293 mutable bool m_radius_known = false;
294 mutable bool m_orientation_known = false;
295 bool m_own_coordinates;
296};
297
298}
299}
Definition CircularArc.h:29
CoordinateXY getDirectionPoint() const
bool containsPointOnCircle(const CoordinateXY &q) const
Definition CircularArc.h:190
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:157
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:124
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:147
bool isLinear() const
Returns whether this arc forms a straight line (p0, p1, and p2 are collinear)
Definition CircularArc.h:162
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:133
bool containsPoint(const CoordinateXY &q) const
double theta0() const
Return the angle of p0.
Definition CircularArc.h:167
double theta1() const
Return the angle of p1.
Definition CircularArc.h:172
double theta2() const
Return the angle of p2.
Definition CircularArc.h:177
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