Coverage Report

Created: 2026-02-14 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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