GEOS 3.14.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/Quadrant.h>
20#include <geos/algorithm/CircularArcs.h>
21#include <geos/algorithm/Orientation.h>
22#include <geos/triangulate/quadedge/TrianglePredicate.h>
23
24namespace geos {
25namespace geom {
26
29class GEOS_DLL CircularArc {
30public:
31
32 using CoordinateXY = geom::CoordinateXY;
33
34 CircularArc(const CoordinateXY& q0, const CoordinateXY& q1, const CoordinateXY& q2)
35 : p0(q0)
36 , p1(q1)
37 , p2(q2)
38 , m_center_known(false)
39 , m_radius_known(false)
40 , m_orientation_known(false)
41 {}
42
43 const CoordinateXY& p0;
44 const CoordinateXY& p1;
45 const CoordinateXY& p2;
46
51 int orientation() const {
52 if (!m_orientation_known) {
53 m_orientation = algorithm::Orientation::index(p0, p1, p2);
54 m_orientation_known = true;
55 }
56 return m_orientation;
57 }
58
60 const CoordinateXY& getCenter() const {
61 if (!m_center_known) {
62 m_center = algorithm::CircularArcs::getCenter(p0, p1, p2);
63 m_center_known = true;
64 }
65
66 return m_center;
67 }
68
70 double getRadius() const {
71 if (!m_radius_known) {
72 m_radius = getCenter().distance(p0);
73 m_radius_known = true;
74 }
75
76 return m_radius;
77 }
78
80 bool isCircle() const {
81 return p0.equals(p2);
82 }
83
85 bool isLinear() const {
86 return std::isnan(getRadius());
87 }
88
90 double getAngle() const {
91 if (isCircle()) {
92 return 2*MATH_PI;
93 }
94
100 auto t0 = theta0();
101 auto t2 = theta2();
102
103 if (orientation() == algorithm::Orientation::COUNTERCLOCKWISE) {
104 std::swap(t0, t2);
105 }
106
107 if (t0 < t2) {
108 t0 += 2*MATH_PI;
109 }
110
111 auto diff = t0-t2;
112
113 return diff;
114 }
115
117 double getLength() const {
118 if (isLinear()) {
119 return p0.distance(p2);
120 }
121
122 return getAngle()*getRadius();
123 }
124
126 double getArea() const {
127 if (isLinear()) {
128 return 0;
129 }
130
131 auto R = getRadius();
132 auto theta = getAngle();
133 return R*R/2*(theta - std::sin(theta));
134 }
135
137 double theta0() const {
138 return std::atan2(p0.y - getCenter().y, p0.x - getCenter().x);
139 }
140
142 double theta2() const {
143 return std::atan2(p2.y - getCenter().y, p2.x - getCenter().x);
144 }
145
149 bool containsPointOnCircle(const CoordinateXY& q) const {
150 double theta = std::atan2(q.y - getCenter().y, q.x - getCenter().x);
151 return containsAngle(theta);
152 }
153
156 bool containsPoint(const CoordinateXY& q) {
157 if (q == p0 || q == p1 || q == p2) {
158 return true;
159 }
160
161 auto dist = std::abs(q.distance(getCenter()) - getRadius());
162
163 if (dist > 1e-8) {
164 return false;
165 }
166
167 if (triangulate::quadedge::TrianglePredicate::isInCircleNormalized(p0, p1, p2, q) != geom::Location::BOUNDARY) {
168 return false;
169 }
170
171 return containsPointOnCircle(q);
172 }
173
175 bool containsAngle(double theta) const {
176 auto t0 = theta0();
177 auto t2 = theta2();
178
179 if (theta == t0 || theta == t2) {
180 return true;
181 }
182
183 if (orientation() == algorithm::Orientation::COUNTERCLOCKWISE) {
184 std::swap(t0, t2);
185 }
186
187 t2 -= t0;
188 theta -= t0;
189
190 if (t2 < 0) {
191 t2 += 2*MATH_PI;
192 }
193 if (theta < 0) {
194 theta += 2*MATH_PI;
195 }
196
197 return theta >= t2;
198 }
199
203 bool isUpwardAtPoint(const CoordinateXY& q) const {
204 auto quad = geom::Quadrant::quadrant(getCenter(), q);
205 bool isUpward;
206
207 if (orientation() == algorithm::Orientation::CLOCKWISE) {
208 isUpward = (quad == geom::Quadrant::SW || quad == geom::Quadrant::NW);
209 } else {
210 isUpward = (quad == geom::Quadrant::SE || quad == geom::Quadrant::NE);
211 }
212
213 return isUpward;
214 }
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
263private:
264 mutable CoordinateXY m_center;
265 mutable double m_radius;
266 mutable int m_orientation;
267 mutable bool m_center_known = false;
268 mutable bool m_radius_known = false;
269 mutable bool m_orientation_known = false;
270};
271
272}
273}
Definition CircularArc.h:29
bool containsPointOnCircle(const CoordinateXY &q) const
Definition CircularArc.h:149
bool isUpwardAtPoint(const CoordinateXY &q) const
Definition CircularArc.h:203
bool isCircle() const
Return whether this arc forms a complete circle.
Definition CircularArc.h:80
bool containsAngle(double theta) const
Check to see if a given angle lies on this arc.
Definition CircularArc.h:175
const CoordinateXY & getCenter() const
Return the center point of the circle associated with this arc.
Definition CircularArc.h:60
int orientation() const
Definition CircularArc.h:51
bool isLinear() const
Returns whether this arc forms a straight line (p0, p1, and p2 are collinear)
Definition CircularArc.h:85
double getAngle() const
Return the inner angle of the sector associated with this arc.
Definition CircularArc.h:90
bool containsPoint(const CoordinateXY &q)
Definition CircularArc.h:156
double getLength() const
Return the length of the arc.
Definition CircularArc.h:117
double getArea() const
Return the area enclosed by the arc p0-p1-p2 and the line segment p2-p0.
Definition CircularArc.h:126
double getRadius() const
Return the radius of the circle associated with this arc.
Definition CircularArc.h:70
double theta0() const
Return the angle of p0.
Definition CircularArc.h:137
double theta2() const
Return the angle of p2.
Definition CircularArc.h:142
Basic namespace for all GEOS functionalities.
Definition geos.h:39