1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
/**
* \file AuxAngle.hpp
* \brief Header for the GeographicLib::AuxAngle class
*
* This file is an implementation of the methods described in
* - C. F. F. Karney,
* <a href="https://doi.org/10.1080/00396265.2023.2217604">
* On auxiliary latitudes,</a>
* Survey Review 56(395), 165--180 (2024);
* preprint
* <a href="https://arxiv.org/abs/2212.05818">arXiv:2212.05818</a>.
* .
* Copyright (c) Charles Karney (2022-2023) <karney@alum.mit.edu> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
**********************************************************************/
#if !defined(GEOGRAPHICLIB_AUXANGLE_HPP)
#define GEOGRAPHICLIB_AUXANGLE_HPP 1
#include <GeographicLib/Math.hpp>
namespace GeographicLib {
/**
* \brief An accurate representation of angles.
*
* This class is an implementation of the methods described in
* - C. F. F. Karney,
* <a href="https://doi.org/10.1080/00396265.2023.2217604">
* On auxiliary latitudes,</a>
* Survey Review 56(395), 165--180 (2024);
* preprint
* <a href="https://arxiv.org/abs/2212.05818">arXiv:2212.05818</a>.
*
* An angle is represented be the \e y and \e x coordinates of a point in the
* 2d plane. The two coordinates are proportional to the sine and cosine of
* the angle. This allows angles close to the cardinal points to be
* represented accurately. It also saves on unnecessary recomputations of
* trigonometric functions of the angle. Only angles in [−180°,
* 180°] can be represented. (A possible extension would be to keep
* count of the number of turns.)
*
* Example of use:
* \include example-AuxAngle.cpp
**********************************************************************/
class GEOGRAPHICLIB_EXPORT AuxAngle {
private:
typedef Math::real real;
real _y, _x;
public:
/**
* The constructor.
*
* @param[in] y the \e y coordinate.
* @param[in] x the \e x coordinate.
*
* \note the \e y coordinate is specified \e first.
* \warning either \e x or \e y can be infinite, but not both.
*
* The defaults (\e x = 1 and \e y = 0) are such that
* + no arguments gives an angle of 0;
* + 1 argument specifies the tangent of the angle.
**********************************************************************/
explicit AuxAngle(real y = 0, real x = 1) : _y(y), _x(x) {}
/**
* @return the \e y component. This is the sine of the angle if the
* AuxAngle has been normalized.
**********************************************************************/
Math::real y() const { return _y; }
/**
* @return the \e x component. This is the cosine of the angle if the
* AuxAngle has been normalized.
**********************************************************************/
Math::real x() const { return _x; }
/**
* @return a reference to the \e y component. This allows this component
* to be altered.
**********************************************************************/
Math::real& y() { return _y; }
/**
* @return a reference to the \e x component. This allows this component
* to be altered.
**********************************************************************/
Math::real& x() { return _x; }
/**
* @return the AuxAngle converted to the conventional angle measured in
* degrees.
**********************************************************************/
Math::real degrees() const;
/**
* @return the AuxAngle converted to the conventional angle measured in
* radians.
**********************************************************************/
Math::real radians() const;
/**
* @return the lambertian of the AuxAngle.
*
* \note the lambertian of an angle χ is
* lam(χ) = asinh(tan(χ)).
**********************************************************************/
Math::real lam() const;
/**
* @return the lambertian of the AuxAngle in degrees.
*
* \note the lambertian of an angle χ is
* lam(χ) = asinh(tan(χ)).
**********************************************************************/
Math::real lamd() const;
/**
* @return the tangent of the angle.
**********************************************************************/
Math::real tan() const { return _y / _x; }
/**
* @return a new normalized AuxAngle with the point lying on the unit
* circle and the \e y and \e x components are equal to the sine and
* cosine of the angle.
**********************************************************************/
AuxAngle normalized() const;
/**
* Normalize the AuxAngle in place so that the \e y and \e x components are
* equal to the sine and cosine of the angle.
**********************************************************************/
void normalize() { *this = normalized(); }
/**
* Set the quadrant for the AuxAngle.
*
* @param[in] p the AuxAngle from which the quadrant information is taken.
* @return the new AuxAngle in the same quadrant as \e p.
**********************************************************************/
AuxAngle copyquadrant(const AuxAngle& p) const;
/**
* Add an AuxAngle.
*
* @param[in] p the AuxAngle to be added.
* @return a reference to the new AuxAngle.
*
* The addition is done in place, altering the current AuxAngle.
*
* \warning Neither *this nor \e p should have an infinite component. If
* necessary, invoke AuxAngle::normalize on these angles first.
**********************************************************************/
AuxAngle& operator+=(const AuxAngle& p);
/**
* Construct and return an AuxAngle specied as an angle in degrees.
*
* @param[in] d the angle measured in degrees.
* @return the corresponding AuxAngle.
*
* This allows a new AuxAngle to be initialized as an angle in degrees with
* @code
* AuxAngle phi(AuxAngle::degrees(d));
* @endcode
**********************************************************************/
static AuxAngle degrees(real d);
/**
* Construct and return an AuxAngle specied as an angle in radians.
*
* @param[in] r the angle measured in radians.
* @return the corresponding AuxAngle.
*
* This allows a new AuxAngle to be initialized as an angle in radians with
* @code
* AuxAngle phi(AuxAngle::radians(r));
* @endcode
**********************************************************************/
static AuxAngle radians(real r);
/**
* Construct and return an AuxAngle specied by the lambertian of the angle.
*
* @param[in] psi the lambertian of the angle.
* @return the corresponding AuxAngle.
*
* This allows a new AuxAngle to be initialized given the lambertian with
* @code
* AuxAngle chi(AuxAngle::lam(psi));
* @endcode
*
* \note this sets the angle χ to gd(ψ) = atan(sinh(ψ)).
**********************************************************************/
static AuxAngle lam(real psi);
/**
* Construct and return an AuxAngle specied by the lambertian of the angle
* in degrees.
*
* @param[in] psid the lambertian of the angle in degrees.
* @return the corresponding AuxAngle.
*
* This allows a new AuxAngle to be initialized given the lambertian with
* @code
* AuxAngle chi(AuxAngle::lamd(psid));
* @endcode
*
* \note this sets the angle χ to gd(ψ) = atan(sinh(ψ)).
**********************************************************************/
static AuxAngle lamd(real psid);
/**
* @return a "NaN" AuxAngle.
**********************************************************************/
static AuxAngle NaN();
};
inline AuxAngle AuxAngle::degrees(real d) {
real y, x;
Math::sincosd(d, y, x);
return AuxAngle(y, x);
}
inline AuxAngle AuxAngle::radians(real r) {
using std::sin; using std::cos;
return AuxAngle(sin(r), cos(r));
}
inline AuxAngle AuxAngle::lam(real psi) {
using std::sinh;
return AuxAngle(sinh(psi));
}
inline AuxAngle AuxAngle::lamd(real psid) {
using std::sinh;
return AuxAngle(sinh(psid * Math::degree()));
}
inline Math::real AuxAngle::degrees() const {
return Math::atan2d(_y, _x);
}
inline Math::real AuxAngle::radians() const {
using std::atan2; return atan2(_y, _x);
}
inline Math::real AuxAngle::lam() const {
using std::asinh; return asinh( tan() );
}
inline Math::real AuxAngle::lamd() const {
using std::asinh; return asinh( tan() ) / Math::degree();
}
} // namespace GeographicLib
#endif // GEOGRAPHICLIB_AUXANGLE_HPP