GEOS 3.15.0dev
CircularArc.h
1/**********************************************************************
2 *
3 * GEOS - Geometry Engine Open Source
4 * http://geos.osgeo.org
5 *
6 * Copyright (C) 2024 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#include <geos/triangulate/quadedge/TrianglePredicate.h>
24
25namespace geos {
26namespace geom {
27
30class GEOS_DLL CircularArc {
31public:
32
33 using CoordinateXY = geom::CoordinateXY;
34
35 CircularArc() : CircularArc({0, 0}, {0, 0}, {0, 0}) {}
36
37 CircularArc(const CoordinateXY& q0, const CoordinateXY& q1, const CoordinateXY& q2)
38 : p0(q0)
39 , p1(q1)
40 , p2(q2)
41 , m_center_known(false)
42 , m_radius_known(false)
43 , m_orientation_known(false)
44 {}
45
46 CircularArc(double theta0, double theta2, const CoordinateXY& center, double radius, int orientation)
47 : p0(algorithm::CircularArcs::createPoint(center, radius, theta0)),
48 p1(algorithm::CircularArcs::createPoint(center, radius, algorithm::CircularArcs::getMidpointAngle(theta0, theta2, orientation==algorithm::Orientation::COUNTERCLOCKWISE))),
49 p2(algorithm::CircularArcs::createPoint(center, radius, theta2)),
50 m_center(center),
51 m_radius(radius),
52 m_orientation(orientation),
53 m_center_known(true),
54 m_radius_known(true),
55 m_orientation_known(true)
56 {}
57
58 CircularArc(const CoordinateXY& q0, const CoordinateXY& q2, const CoordinateXY& center, double radius, int orientation)
59 : p0(q0),
60 p1(algorithm::CircularArcs::getMidpoint(q0, q2, center, radius, orientation==algorithm::Orientation::COUNTERCLOCKWISE)),
61 p2(q2),
62 m_center(center),
63 m_radius(radius),
64 m_orientation(orientation),
65 m_center_known(true),
66 m_radius_known(true),
67 m_orientation_known(true)
68 {}
69
70 CoordinateXY p0;
71 CoordinateXY p1;
72 CoordinateXY p2;
73
78 int getOrientation() const {
79 if (!m_orientation_known) {
80 m_orientation = algorithm::Orientation::index(p0, p1, p2);
81 m_orientation_known = true;
82 }
83 return m_orientation;
84 }
85
86 bool isCCW() const {
87 return getOrientation() == algorithm::Orientation::COUNTERCLOCKWISE;
88 }
89
91 const CoordinateXY& getCenter() const {
92 if (!m_center_known) {
93 m_center = algorithm::CircularArcs::getCenter(p0, p1, p2);
94 m_center_known = true;
95 }
96
97 return m_center;
98 }
99
101 double getRadius() const {
102 if (!m_radius_known) {
103 m_radius = getCenter().distance(p0);
104 m_radius_known = true;
105 }
106
107 return m_radius;
108 }
109
111 bool isCircle() const {
112 return p0.equals(p2);
113 }
114
116 bool isLinear() const {
117 return !std::isfinite(getRadius());
118 }
119
121 double getAngle() const {
122 if (isCircle()) {
123 return 2*MATH_PI;
124 }
125
131 auto t0 = theta0();
132 auto t2 = theta2();
133
134 if (getOrientation() == algorithm::Orientation::COUNTERCLOCKWISE) {
135 std::swap(t0, t2);
136 }
137
138 if (t0 < t2) {
139 t0 += 2*MATH_PI;
140 }
141
142 auto diff = t0-t2;
143
144 return diff;
145 }
146
148 double getLength() const {
149 if (isLinear()) {
150 return p0.distance(p2);
151 }
152
153 return getAngle()*getRadius();
154 }
155
157 double getArea() const {
158 if (isLinear()) {
159 return 0;
160 }
161
162 auto R = getRadius();
163 auto theta = getAngle();
164 return R*R/2*(theta - std::sin(theta));
165 }
166
168 double getSagitta() const {
169 CoordinateXY midpoint = algorithm::CircularArcs::getMidpoint(p0, p2, getCenter(), getRadius(), isCCW());
170 return algorithm::Distance::pointToSegment(midpoint, p0, p2);
171 }
172
174 double theta0() const {
175 return algorithm::CircularArcs::getAngle(p0, getCenter());
176 }
177
179 double theta2() const {
180 return algorithm::CircularArcs::getAngle(p2, getCenter());
181 }
182
186 bool containsPointOnCircle(const CoordinateXY& q) const {
187 double theta = std::atan2(q.y - getCenter().y, q.x - getCenter().x);
188 return containsAngle(theta);
189 }
190
193 bool containsPoint(const CoordinateXY& q) const {
194 if (q == p0 || q == p1 || q == p2) {
195 return true;
196 }
197
198 //auto dist = std::abs(q.distance(getCenter()) - getRadius());
199
200 //if (dist > 1e-8) {
201 // return false;
202 //}
203
204 if (triangulate::quadedge::TrianglePredicate::isInCircleRobust(p0, p1, p2, q) != geom::Location::BOUNDARY) {
205 return false;
206 }
207
208 return containsPointOnCircle(q);
209 }
210
212 bool containsAngle(double theta) const {
213 auto t0 = theta0();
214 auto t2 = theta2();
215
216 if (theta == t0 || theta == t2) {
217 return true;
218 }
219
220 if (getOrientation() == algorithm::Orientation::COUNTERCLOCKWISE) {
221 std::swap(t0, t2);
222 }
223
224 t2 -= t0;
225 theta -= t0;
226
227 if (t2 < 0) {
228 t2 += 2*MATH_PI;
229 }
230 if (theta < 0) {
231 theta += 2*MATH_PI;
232 }
233
234 return theta >= t2;
235 }
236
240 bool isUpwardAtPoint(const CoordinateXY& q) const {
241 auto quad = geom::Quadrant::quadrant(getCenter(), q);
242 bool isUpward;
243
244 if (getOrientation() == algorithm::Orientation::CLOCKWISE) {
245 isUpward = (quad == geom::Quadrant::SW || quad == geom::Quadrant::NW);
246 } else {
247 isUpward = (quad == geom::Quadrant::SE || quad == geom::Quadrant::NE);
248 }
249
250 return isUpward;
251 }
252
253 // Split an arc at a specified point.
254 // The point is assumed to be o the arc.
255 std::pair<CircularArc, CircularArc> splitAtPoint(const CoordinateXY& q) const {
256 return {
257 CircularArc(p0, q, getCenter(), getRadius(), getOrientation()),
258 CircularArc(q, p2, getCenter(), getRadius(), getOrientation())
259 };
260 }
261
262 class Iterator {
263 public:
264 using iterator_category = std::forward_iterator_tag;
265 using difference_type = std::ptrdiff_t;
266 using value_type = geom::CoordinateXY;
267 using pointer = const geom::CoordinateXY*;
268 using reference = const geom::CoordinateXY&;
269
270 Iterator(const CircularArc& arc, int i) : m_arc(arc), m_i(i) {}
271
272 reference operator*() const {
273 return m_i == 0 ? m_arc.p0 : (m_i == 1 ? m_arc.p1 : m_arc.p2);
274 }
275
276 Iterator& operator++() {
277 m_i++;
278 return *this;
279 }
280
281 Iterator operator++(int) {
282 Iterator ret = *this;
283 m_i++;
284 return ret;
285 }
286
287 bool operator==(const Iterator& other) const {
288 return m_i == other.m_i;
289 }
290
291 bool operator!=(const Iterator& other) const {
292 return !(*this == other);
293 }
294
295 private:
296 const CircularArc& m_arc;
297 int m_i;
298
299 };
300
301 Iterator begin() const {
302 return Iterator(*this, 0);
303 }
304
305 Iterator end() const {
306 return Iterator(*this, 3);
307 }
308
309private:
310 mutable CoordinateXY m_center;
311 mutable double m_radius;
312 mutable int m_orientation;
313 mutable bool m_center_known = false;
314 mutable bool m_radius_known = false;
315 mutable bool m_orientation_known = false;
316};
317
318}
319}
Definition CircularArc.h:30
bool containsPointOnCircle(const CoordinateXY &q) const
Definition CircularArc.h:186
bool isUpwardAtPoint(const CoordinateXY &q) const
Definition CircularArc.h:240
bool isCircle() const
Return whether this arc forms a complete circle.
Definition CircularArc.h:111
bool containsAngle(double theta) const
Check to see if a given angle lies on this arc.
Definition CircularArc.h:212
int getOrientation() const
Definition CircularArc.h:78
const CoordinateXY & getCenter() const
Return the center point of the circle associated with this arc.
Definition CircularArc.h:91
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:168
bool isLinear() const
Returns whether this arc forms a straight line (p0, p1, and p2 are collinear)
Definition CircularArc.h:116
double getAngle() const
Return the inner angle of the sector associated with this arc.
Definition CircularArc.h:121
double getLength() const
Return the length of the arc.
Definition CircularArc.h:148
double getArea() const
Return the area enclosed by the arc p0-p1-p2 and the line segment p2-p0.
Definition CircularArc.h:157
double getRadius() const
Return the radius of the circle associated with this arc.
Definition CircularArc.h:101
bool containsPoint(const CoordinateXY &q) const
Definition CircularArc.h:193
double theta0() const
Return the angle of p0.
Definition CircularArc.h:174
double theta2() const
Return the angle of p2.
Definition CircularArc.h:179
Basic namespace for all GEOS functionalities.
Definition geos.h:38