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 
24 namespace geos {
25 namespace geom {
26 
29 class GEOS_DLL CircularArc {
30 public:
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 
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 
263 private:
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 }
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: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
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
const CoordinateXY & getCenter() const
Return the center point of the circle associated with this arc.
Definition: CircularArc.h:60
double theta0() const
Return the angle of p0.
Definition: CircularArc.h:137
double theta2() const
Return the angle of p2.
Definition: CircularArc.h:142
static int quadrant(double dx, double dy)
Definition: Quadrant.h:67
static geom::Location isInCircleNormalized(const CoordinateXY &a, const CoordinateXY &b, const CoordinateXY &c, const CoordinateXY &p)
Basic namespace for all GEOS functionalities.
Definition: Angle.h:25