/src/geos/include/geos/algorithm/Angle.h
Line | Count | Source |
1 | | /********************************************************************** |
2 | | * |
3 | | * GEOS - Geometry Engine Open Source |
4 | | * http://geos.osgeo.org |
5 | | * |
6 | | * Copyright (C) 2009-2011 Sandro Santilli <strk@kbt.io> |
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 | | * Last port: algorithm/Angle.java r378 (JTS-1.12) |
16 | | * |
17 | | **********************************************************************/ |
18 | | |
19 | | #pragma once |
20 | | |
21 | | #include <geos/export.h> |
22 | | #include <geos/algorithm/Orientation.h> // for constants |
23 | | |
24 | | // Forward declarations |
25 | | namespace geos { |
26 | | namespace geom { |
27 | | class Coordinate; |
28 | | } |
29 | | } |
30 | | |
31 | | namespace geos { |
32 | | namespace algorithm { // geos::algorithm |
33 | | |
34 | | /// Utility functions for working with angles. |
35 | | // |
36 | | /// Unless otherwise noted, methods in this class express angles in radians. |
37 | | /// |
38 | | class GEOS_DLL Angle { |
39 | | public: |
40 | | |
41 | | static constexpr double PI_TIMES_2 = 2.0 * MATH_PI; |
42 | | static constexpr double PI_OVER_2 = MATH_PI / 2.0; |
43 | | static constexpr double PI_OVER_4 = MATH_PI / 4.0; |
44 | | |
45 | | /// Constant representing counterclockwise orientation |
46 | | static const int COUNTERCLOCKWISE = Orientation::COUNTERCLOCKWISE; |
47 | | |
48 | | /// Constant representing clockwise orientation |
49 | | static const int CLOCKWISE = Orientation::CLOCKWISE; |
50 | | |
51 | | /// Constant representing no orientation |
52 | | static const int NONE = Orientation::COLLINEAR; |
53 | | |
54 | | /// Converts from radians to degrees. |
55 | | /// |
56 | | /// @param radians an angle in radians |
57 | | /// @return the angle in degrees |
58 | | /// |
59 | | static double toDegrees(double radians); |
60 | | |
61 | | /// Converts from degrees to radians. |
62 | | /// |
63 | | /// @param angleDegrees an angle in degrees |
64 | | /// @return the angle in radians |
65 | | /// |
66 | | static double toRadians(double angleDegrees); |
67 | | |
68 | | /// \brief |
69 | | /// Returns the angle of the vector from p0 to p1, |
70 | | /// relative to the positive X-axis. |
71 | | /// |
72 | | /// The angle is normalized to be in the range [ -Pi, Pi ]. |
73 | | /// |
74 | | /// @return the normalized angle (in radians) that p0-p1 makes |
75 | | /// with the positive x-axis. |
76 | | /// |
77 | | static double angle(const geom::CoordinateXY& p0, |
78 | | const geom::CoordinateXY& p1); |
79 | | |
80 | | /// \brief |
81 | | /// Returns the angle that the vector from (0,0) to p, |
82 | | /// relative to the positive X-axis. |
83 | | // |
84 | | /// The angle is normalized to be in the range ( -Pi, Pi ]. |
85 | | /// |
86 | | /// @return the normalized angle (in radians) that p makes |
87 | | /// with the positive x-axis. |
88 | | /// |
89 | | static double angle(const geom::CoordinateXY& p); |
90 | | |
91 | | /// Tests whether the angle between p0-p1-p2 is acute. |
92 | | /// |
93 | | /// An angle is acute if it is less than 90 degrees. |
94 | | /// |
95 | | /// Note: this implementation is not precise (deterministic) for |
96 | | /// angles very close to 90 degrees. |
97 | | /// |
98 | | /// @param p0 an endpoint of the angle |
99 | | /// @param p1 the base of the angle |
100 | | /// @param p2 the other endpoint of the angle |
101 | | /// |
102 | | static bool isAcute(const geom::CoordinateXY& p0, |
103 | | const geom::CoordinateXY& p1, |
104 | | const geom::CoordinateXY& p2); |
105 | | |
106 | | /// Tests whether the angle between p0-p1-p2 is obtuse. |
107 | | /// |
108 | | /// An angle is obtuse if it is greater than 90 degrees. |
109 | | /// |
110 | | /// Note: this implementation is not precise (deterministic) for |
111 | | /// angles very close to 90 degrees. |
112 | | /// |
113 | | /// @param p0 an endpoint of the angle |
114 | | /// @param p1 the base of the angle |
115 | | /// @param p2 the other endpoint of the angle |
116 | | /// |
117 | | static bool isObtuse(const geom::CoordinateXY& p0, |
118 | | const geom::CoordinateXY& p1, |
119 | | const geom::CoordinateXY& p2); |
120 | | |
121 | | /// Returns the unoriented smallest angle between two vectors. |
122 | | /// |
123 | | /// The computed angle will be in the range [0, Pi). |
124 | | /// |
125 | | /// @param tip1 the tip of one vector |
126 | | /// @param tail the tail of each vector |
127 | | /// @param tip2 the tip of the other vector |
128 | | /// @return the angle between tail-tip1 and tail-tip2 |
129 | | /// |
130 | | static double angleBetween(const geom::CoordinateXY& tip1, |
131 | | const geom::CoordinateXY& tail, |
132 | | const geom::CoordinateXY& tip2); |
133 | | |
134 | | /// Returns the oriented smallest angle between two vectors. |
135 | | /// |
136 | | /// The computed angle will be in the range (-Pi, Pi]. |
137 | | /// A positive result corresponds to a counterclockwise rotation |
138 | | /// from v1 to v2; |
139 | | /// a negative result corresponds to a clockwise rotation. |
140 | | /// |
141 | | /// @param tip1 the tip of v1 |
142 | | /// @param tail the tail of each vector |
143 | | /// @param tip2 the tip of v2 |
144 | | /// @return the angle between v1 and v2, relative to v1 |
145 | | /// |
146 | | static double angleBetweenOriented(const geom::CoordinateXY& tip1, |
147 | | const geom::CoordinateXY& tail, |
148 | | const geom::CoordinateXY& tip2); |
149 | | |
150 | | /// Computes the angle of the unoriented bisector |
151 | | /// of the smallest angle between two vectors. |
152 | | /// The computed angle will be in the range (-Pi, Pi]. |
153 | | /// Collinear inputs are handled. |
154 | | /// |
155 | | /// @param tip1 the tip of v1 |
156 | | /// @param tail the tail of each vector |
157 | | /// @param tip2 the tip of v2 |
158 | | /// @return the angle of the bisector between v1 and v2 |
159 | | /// |
160 | | static double bisector(const geom::CoordinateXY& tip1, |
161 | | const geom::CoordinateXY& tail, |
162 | | const geom::CoordinateXY& tip2); |
163 | | |
164 | | /// Computes the interior angle between two segments of a ring. |
165 | | /// |
166 | | /// The ring is assumed to be oriented in a clockwise direction. |
167 | | /// The computed angle will be in the range [0, 2Pi] |
168 | | /// |
169 | | /// @param p0 |
170 | | /// a point of the ring |
171 | | /// @param p1 |
172 | | /// the next point of the ring |
173 | | /// @param p2 |
174 | | /// the next point of the ring |
175 | | /// @return the interior angle based at <code>p1</code> |
176 | | /// |
177 | | static double interiorAngle(const geom::CoordinateXY& p0, |
178 | | const geom::CoordinateXY& p1, |
179 | | const geom::CoordinateXY& p2); |
180 | | |
181 | | /// \brief |
182 | | /// Returns whether an angle must turn clockwise or counterclockwise |
183 | | /// to overlap another angle. |
184 | | /// |
185 | | /// @param ang1 an angle (in radians) |
186 | | /// @param ang2 an angle (in radians) |
187 | | /// @return whether a1 must turn CLOCKWISE, COUNTERCLOCKWISE or |
188 | | /// NONE to overlap a2. |
189 | | /// |
190 | | static int getTurn(double ang1, double ang2); |
191 | | |
192 | | /// \brief |
193 | | /// Computes the normalized value of an angle, which is the |
194 | | /// equivalent angle in the range ( -Pi, Pi ]. |
195 | | /// |
196 | | /// @param angle the angle to normalize |
197 | | /// @return an equivalent angle in the range (-Pi, Pi] |
198 | | /// |
199 | | static double normalize(double angle); |
200 | | |
201 | | /// \brief |
202 | | /// Computes the normalized positive value of an angle, |
203 | | /// which is the equivalent angle in the range [ 0, 2*Pi ). |
204 | | /// |
205 | | /// E.g.: |
206 | | /// - normalizePositive(0.0) = 0.0 |
207 | | /// - normalizePositive(-PI) = PI |
208 | | /// - normalizePositive(-2PI) = 0.0 |
209 | | /// - normalizePositive(-3PI) = PI |
210 | | /// - normalizePositive(-4PI) = 0 |
211 | | /// - normalizePositive(PI) = PI |
212 | | /// - normalizePositive(2PI) = 0.0 |
213 | | /// - normalizePositive(3PI) = PI |
214 | | /// - normalizePositive(4PI) = 0.0 |
215 | | /// |
216 | | /// @param angle the angle to normalize, in radians |
217 | | /// @return an equivalent positive angle |
218 | | /// |
219 | | static double normalizePositive(double angle); |
220 | | |
221 | | /// Returns true if angle x is within the counterclockwise |
222 | | /// arc from angle a to angle b |
223 | | /// |
224 | | /// @param angle angle to test |
225 | | /// @param from starting angle of arc |
226 | | /// @param to ending angle of arc |
227 | | /// |
228 | | /// @return true if `angle` is within [from, to] |
229 | | static bool isWithinCCW(double angle, double from, double to); |
230 | | |
231 | | /// Return which of the two provided angles would be encountered first when moving |
232 | | /// counterclockwise from the specified start angle. |
233 | | /// |
234 | | /// @param from the starting angle |
235 | | /// @param a the first candidate angle |
236 | | /// @param b the second candidate angle |
237 | | /// |
238 | | /// @return a or b |
239 | | static double nextCCW(double from, double a, double b); |
240 | | |
241 | | /// Return the fraction of an angle as a fraction of a larger angle |
242 | | /// |
243 | | /// @param x an angle between a and b |
244 | | /// @param a the starting angle |
245 | | /// @param b the ending angle |
246 | | /// |
247 | | /// @return a value in the range [0, 1] |
248 | | static double fractionCCW(double x, double a, double b); |
249 | | |
250 | | /// Computes the unoriented smallest difference between two angles. |
251 | | /// |
252 | | /// The angles are assumed to be normalized to the range [-Pi, Pi]. |
253 | | /// The result will be in the range [0, Pi]. |
254 | | /// |
255 | | /// @param ang1 the angle of one vector (in [-Pi, Pi] ) |
256 | | /// @param ang2 the angle of the other vector (in range [-Pi, Pi] ) |
257 | | /// @return the angle (in radians) between the two vectors |
258 | | /// (in range [0, Pi] ) |
259 | | /// |
260 | | static double diff(double ang1, double ang2); |
261 | | |
262 | | /// \brief |
263 | | /// Computes both sin and cos of an angle, snapping near-zero values |
264 | | /// to zero. |
265 | | /// |
266 | | /// The angle does not need to be normalized. Unlike std::sin |
267 | | /// and std::cos, this method will snap near-zero values to zero |
268 | | /// for (e.g.) sin(pi) and cos(pi/2). |
269 | | /// |
270 | | /// @param ang the input angle (in radians) |
271 | | /// @param rSin the result of sin(ang) |
272 | | /// @param rCos the result of cos(ang) |
273 | | /// |
274 | 0 | static inline void sinCosSnap(const double ang, double& rSin, double& rCos) { |
275 | 0 | rSin = std::sin(ang); |
276 | 0 | rCos = std::cos(ang); |
277 | | // snap near-zero values |
278 | 0 | if (std::fabs(rSin) < 5e-16) rSin = 0.0; |
279 | 0 | if (std::fabs(rCos) < 5e-16) rCos = 0.0; |
280 | 0 | } |
281 | | |
282 | | /// Projects a point by a given angle and distance. |
283 | | /// |
284 | | /// @param p the point to project |
285 | | /// @param angle the angle at which to project |
286 | | /// @param dist the distance to project |
287 | | /// @return the projected point |
288 | | /// |
289 | | static geom::CoordinateXY project(const geom::CoordinateXY& p, |
290 | | double angle, double dist); |
291 | | |
292 | | }; |
293 | | |
294 | | |
295 | | } // namespace geos::algorithm |
296 | | } // namespace geos |
297 | | |
298 | | |