GeographicLib 2.5
AuxLatitude.hpp
Go to the documentation of this file.
1/**
2 * \file AuxLatitude.hpp
3 * \brief Header for the GeographicLib::AuxLatitude class
4 *
5 * This file is an implementation of the methods described in
6 * - C. F. F. Karney,
7 * <a href="https://doi.org/10.1080/00396265.2023.2217604">
8 * On auxiliary latitudes,</a>
9 * Survey Review 56(395), 165--180 (2024);
10 * preprint
11 * <a href="https://arxiv.org/abs/2212.05818">arXiv:2212.05818</a>.
12 * .
13 * Copyright (c) Charles Karney (2022-2023) <karney@alum.mit.edu> and licensed
14 * under the MIT/X11 License. For more information, see
15 * https://geographiclib.sourceforge.io/
16 **********************************************************************/
17
18#if !defined(GEOGRAPHICLIB_AUXLATITUDE_HPP)
19#define GEOGRAPHICLIB_AUXLATITUDE_HPP 1
20
21#include <utility>
24
25#if !defined(GEOGRAPHICLIB_AUXLATITUDE_ORDER)
26/**
27 * The order of the series approximation used in AuxLatitude.
28 * GEOGRAPHICLIB_AUXLATITUDE_ORDER can be set to one of [4, 6, 8]. Use order
29 * appropriate for double precision, 6, also for GEOGRAPHICLIB_PRECISION == 5
30 * to enable truncation errors to be measured easily.
31 **********************************************************************/
32# define GEOGRAPHICLIB_AUXLATITUDE_ORDER \
33 (GEOGRAPHICLIB_PRECISION == 2 || GEOGRAPHICLIB_PRECISION == 5 ? 6 : \
34 (GEOGRAPHICLIB_PRECISION == 1 ? 4 : 8))
35#endif
36
37namespace GeographicLib {
38
39 /**
40 * \brief Conversions between auxiliary latitudes.
41 *
42 * This class is an implementation of the methods described in
43 * - C. F. F. Karney,
44 * <a href="https://doi.org/10.1080/00396265.2023.2217604">
45 * On auxiliary latitudes,</a>
46 * Survey Review 56(395), 165--180 (2024);
47 * preprint
48 * <a href="https://arxiv.org/abs/2212.05818">arXiv:2212.05818</a>.
49 *
50 * The provides accurate conversions between geographic (\e phi, &phi;),
51 * parametric (\e beta, &beta;), geocentric (\e theta, &theta;), rectifying
52 * (\e mu, &mu;), conformal (\e chi, &chi;), and authalic (\e xi, &xi;)
53 * latitudes for an ellipsoid of revolution. A latitude is represented by
54 * the class AuxAngle in order to maintain precision close to the poles.
55 *
56 * The class implements two methods for the conversion:
57 * - Direct evaluation of the defining equations, the \e exact method. These
58 * equations are formulated so as to preserve relative accuracy of the
59 * tangent of the latitude, ensuring high accuracy near the equator and the
60 * poles. Newton's method is used for those conversions that can't be
61 * expressed in closed form.
62 * - Expansions in powers of \e n, the third flattening, the \e series
63 * method. This delivers full accuracy for abs(\e f) &le; 1/150. Here, \e
64 * f is the flattening of the ellipsoid.
65 *
66 * The series method is the preferred method of conversion for any conversion
67 * involving &mu;, &chi;, or &xi;, with abs(\e f) &le; 1/150. The equations
68 * for the conversions between &phi;, &beta;, and &theta; are sufficiently
69 * simple that the exact method should be used for such conversions and also
70 * for conversions with with abs(\e f) &gt; 1/150.
71 *
72 * Example of use:
73 * \include example-AuxLatitude.cpp
74 **********************************************************************/
76 typedef Math::real real;
77 AuxLatitude(const std::pair<real, real>& axes);
78 public:
79 /**
80 * The floating-point type for real numbers. This just connects to the
81 * template parameters for the class.
82 **********************************************************************/
83 /**
84 * The different auxiliary latitudes.
85 **********************************************************************/
86 enum aux {
87 /**
88 * Geographic latitude, \e phi, &phi;
89 * @hideinitializer
90 **********************************************************************/
91 GEOGRAPHIC = 0,
92 /**
93 * Parametric latitude, \e beta, &beta;
94 * @hideinitializer
95 **********************************************************************/
96 PARAMETRIC = 1,
97 /**
98 * %Geocentric latitude, \e theta, &theta;
99 * @hideinitializer
100 **********************************************************************/
101 GEOCENTRIC = 2,
102 /**
103 * Rectifying latitude, \e mu, &mu;
104 * @hideinitializer
105 **********************************************************************/
106 RECTIFYING = 3,
107 /**
108 * Conformal latitude, \e chi, &chi;
109 * @hideinitializer
110 **********************************************************************/
111 CONFORMAL = 4,
112 /**
113 * Authalic latitude, \e xi, &xi;
114 * @hideinitializer
115 **********************************************************************/
116 AUTHALIC = 5,
117 /**
118 * The total number of auxiliary latitudes
119 * @hideinitializer
120 **********************************************************************/
121 AUXNUMBER = 6,
122 /**
123 * An alias for GEOGRAPHIC
124 * @hideinitializer
125 **********************************************************************/
126 PHI = GEOGRAPHIC,
127 /**
128 * An alias for PARAMETRIC
129 * @hideinitializer
130 **********************************************************************/
131 BETA = PARAMETRIC,
132 /**
133 * An alias for GEOCENTRIC
134 * @hideinitializer
135 **********************************************************************/
136 THETA = GEOCENTRIC,
137 /**
138 * An alias for RECTIFYING
139 * @hideinitializer
140 **********************************************************************/
141 MU = RECTIFYING,
142 /**
143 * An alias for CONFORMAL
144 * @hideinitializer
145 **********************************************************************/
146 CHI = CONFORMAL,
147 /**
148 * An alias for AUTHALIC
149 * @hideinitializer
150 **********************************************************************/
151 XI = AUTHALIC,
152 /**
153 * An alias for GEOGRAPHIC
154 * @hideinitializer
155 **********************************************************************/
156 COMMON = GEOGRAPHIC,
157 /**
158 * An alias for GEOGRAPHIC
159 * @hideinitializer
160 **********************************************************************/
161 GEODETIC = GEOGRAPHIC,
162 /**
163 * An alias for PARAMETRIC
164 * @hideinitializer
165 **********************************************************************/
166 REDUCED = PARAMETRIC,
167 };
168 /**
169 * Constructor
170 *
171 * @param[in] a equatorial radius.
172 * @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
173 * Negative \e f gives a prolate ellipsoid.
174 * @exception GeographicErr if \e a or (1 &minus; \e f) \e a is not
175 * positive.
176 *
177 * \note the constructor does not precompute the coefficients for the
178 * Fourier series for the series conversions. These are computed and saved
179 * when first needed.
180 **********************************************************************/
181 AuxLatitude(real a, real f);
182 /**
183 * Construct and return an AuxLatitude object specified in terms of the
184 * semi-axes
185 *
186 * @param[in] a equatorial radius.
187 * @param[in] b polar semi-axis.
188 * @exception GeographicErr if \e a or \e b is not positive.
189 *
190 * This allows a new AuxAngle to be initialized as an angle in radians with
191 * @code
192 * AuxLatitude aux(AuxLatitude::axes(a, b));
193 * @endcode
194 **********************************************************************/
195 static AuxLatitude axes(real a, real b) {
196 return AuxLatitude(std::pair<real, real>(a, b));
197 }
198 /**
199 * Convert between any two auxiliary latitudes specified as AuxAngle.
200 *
201 * @param[in] auxin an AuxLatitude::aux indicating the type of
202 * auxiliary latitude \e zeta.
203 * @param[in] auxout an AuxLatitude::aux indicating the type of
204 * auxiliary latitude \e eta.
205 * @param[in] zeta the input auxiliary latitude as an AuxAngle
206 * @param[in] exact if true use the exact equations instead of the Taylor
207 * series [default false].
208 * @return the output auxiliary latitude \e eta as an AuxAngle.
209 *
210 * With \e exact = false, the Fourier coefficients for a specific \e auxin
211 * and \e auxout are computed and saved on the first call; the saved
212 * coefficients are used on subsequent calls. The series method is
213 * accurate for abs(\e f) &le; 1/150; for other \e f, the exact method
214 * should be used.
215 **********************************************************************/
216 AuxAngle Convert(int auxin, int auxout, const AuxAngle& zeta,
217 bool exact = false) const;
218 /**
219 * Convert between any two auxiliary latitudes specified in degrees.
220 *
221 * @param[in] auxin an AuxLatitude::aux indicating the type of
222 * auxiliary latitude \e zeta.
223 * @param[in] auxout an AuxLatitude::aux indicating the type of
224 * auxiliary latitude \e eta.
225 * @param[in] zeta the input auxiliary latitude in degrees.
226 * @param[in] exact if true use the exact equations instead of the Taylor
227 * series [default false].
228 * @return the output auxiliary latitude \e eta in degrees.
229 *
230 * With \e exact = false, the Fourier coefficients for a specific \e auxin
231 * and \e auxout are computed and saved on the first call; the saved
232 * coefficients are used on subsequent calls. The series method is
233 * accurate for abs(\e f) &le; 1/150; for other \e f, the exact method
234 * should be used.
235 **********************************************************************/
236 Math::real Convert(int auxin, int auxout, real zeta, bool exact = false)
237 const;
238 /**
239 * Convert geographic latitude to an auxiliary latitude \e eta.
240 *
241 * @param[in] auxout an AuxLatitude::aux indicating the auxiliary
242 * latitude returned.
243 * @param[in] phi the geographic latitude.
244 * @param[out] diff optional pointer to the derivative d tan(\e eta) / d
245 * tan(\e phi).
246 * @return the auxiliary latitude \e eta.
247 *
248 * This uses the exact equations.
249 **********************************************************************/
250 AuxAngle ToAuxiliary(int auxout, const AuxAngle& phi, real* diff = nullptr)
251 const;
252 /**
253 * Convert an auxiliary latitude \e zeta to geographic latitude.
254 *
255 * @param[in] auxin an AuxLatitude::aux indicating the type of
256 * auxiliary latitude \e zeta.
257 * @param[in] zeta the input auxiliary latitude.
258 * @param[out] niter optional pointer to the number of iterations.
259 * @return the geographic latitude \e phi.
260 *
261 * This uses the exact equations.
262 **********************************************************************/
263 AuxAngle FromAuxiliary(int auxin, const AuxAngle& zeta,
264 int* niter = nullptr) const;
265 /**
266 * Return the rectifying radius.
267 *
268 * @param[in] exact if true use the exact expression instead of the Taylor
269 * series [default false].
270 * @return the rectifying radius in the same units as \e a.
271 **********************************************************************/
272 Math::real RectifyingRadius(bool exact = false) const;
273 /**
274 * Return the authalic radius squared.
275 *
276 * @param[in] exact if true use the exact expression instead of the Taylor
277 * series [default false].
278 * @return the authalic radius squared in the same units as \e a.
279 **********************************************************************/
280 Math::real AuthalicRadiusSquared(bool exact = false) const;
281 /**
282 * @return \e a the equatorial radius of the ellipsoid (meters).
283 **********************************************************************/
284 Math::real EquatorialRadius() const { return _a; }
285 /**
286 * @return \e b the polar semi-axis of the ellipsoid (meters).
287 **********************************************************************/
288 Math::real PolarSemiAxis() const { return _b; }
289 /**
290 * @return \e f, the flattening of the ellipsoid.
291 **********************************************************************/
292 Math::real Flattening() const { return _f; }
293 /**
294 * Use Clenshaw to sum a Fouier series.
295 *
296 * @param[in] sinp if true sum the sine series, else sum the cosine series.
297 * @param[in] szeta sin(\e zeta).
298 * @param[in] czeta cos(\e zeta).
299 * @param[in] c the array of coefficients.
300 * @param[in] K the number of coefficients.
301 * @return the Clenshaw sum.
302 *
303 * The result returned is \f$ \sum_0^{K-1} c_k \sin (2k+2)\zeta \f$, if \e
304 * sinp is true; with \e sinp false, replace sin by cos.
305 **********************************************************************/
306 // Clenshaw applied to sum(c[k] * sin( (2*k+2) * zeta), i, 0, K-1);
307 // if !sinp then subst sine->cosine.
308 static Math::real Clenshaw(bool sinp, real szeta, real czeta,
309 const real c[], int K);
310 /**
311 * The order of the series expansions. This is set at compile time to
312 * either 4, 6, or 8, by the preprocessor macro
313 * GEOGRAPHICLIB_AUXLATITUDE_ORDER.
314 * @hideinitializer
315 **********************************************************************/
316 static const int Lmax = GEOGRAPHICLIB_AUXLATITUDE_ORDER;
317 /**
318 * A global instantiation of Ellipsoid with the parameters for the WGS84
319 * ellipsoid.
320 **********************************************************************/
321 static const AuxLatitude& WGS84();
322 private:
323 // Maximum number of iterations for Newton's method
324 static const int numit_ = 1000;
325 real tol_, bmin_, bmax_; // Static consts for Newton's method
326 // the function atanh(e * sphi)/e + sphi / (1 - (e * sphi)^2);
327 protected:
328 /**
329 * Convert geographic latitude to parametric latitude
330 *
331 * @param[in] phi geographic latitude.
332 * @param[out] diff optional pointer to the derivative d tan(\e beta) / d
333 * tan(\e phi).
334 * @return \e beta, the parametric latitude
335 **********************************************************************/
336 AuxAngle Parametric(const AuxAngle& phi, real* diff = nullptr) const;
337 /**
338 * Convert geographic latitude to geocentric latitude
339 *
340 * @param[in] phi geographic latitude.
341 * @param[out] diff optional pointer to the derivative d tan(\e theta) / d
342 * tan(\e phi).
343 * @return \e theta, the geocentric latitude.
344 **********************************************************************/
345 AuxAngle Geocentric(const AuxAngle& phi, real* diff = nullptr) const;
346 /**
347 * Convert geographic latitude to rectifying latitude
348 *
349 * @param[in] phi geographic latitude.
350 * @param[out] diff optional pointer to the derivative d tan(\e mu) / d
351 * tan(\e phi).
352 * @return \e mu, the rectifying latitude.
353 **********************************************************************/
354 AuxAngle Rectifying(const AuxAngle& phi, real* diff = nullptr) const;
355 /**
356 * Convert geographic latitude to conformal latitude
357 *
358 * @param[in] phi geographic latitude.
359 * @param[out] diff optional pointer to the derivative d tan(\e chi) / d
360 * tan(\e phi).
361 * @return \e chi, the conformal latitude.
362 **********************************************************************/
363 AuxAngle Conformal(const AuxAngle& phi, real* diff = nullptr) const;
364 /**
365 * Convert geographic latitude to authalic latitude
366 *
367 * @param[in] phi geographic latitude.
368 * @param[out] diff optional pointer to the derivative d tan(\e xi) / d
369 * tan(\e phi).
370 * @return \e xi, the authalic latitude.
371 **********************************************************************/
372 AuxAngle Authalic(const AuxAngle& phi, real* diff = nullptr) const;
373 /// \cond SKIP
374 // Ellipsoid parameters
375 real _a, _b, _f, _fm1, _e2, _e2m1, _e12, _e12p1, _n, _e, _e1, _n2, _q;
376 // To hold computed Fourier coefficients
377 mutable real _c[Lmax * AUXNUMBER * AUXNUMBER];
378 // 1d index into AUXNUMBER x AUXNUMBER data
379 static int ind(int auxout, int auxin) {
380 return (auxout >= 0 && auxout < AUXNUMBER &&
381 auxin >= 0 && auxin < AUXNUMBER) ?
382 AUXNUMBER * auxout + auxin : -1;
383 }
384 // the function sqrt(1 + tphi^2), convert tan to sec
385 static real sc(real tphi)
386 { using std::hypot; return hypot(real(1), tphi); }
387 // the function tphi / sqrt(1 + tphi^2), convert tan to sin
388 static real sn(real tphi) {
389 using std::isinf; using std::copysign;
390 return isinf(tphi) ? copysign(real(1), tphi) : tphi / sc(tphi);
391 }
392 // Populate [_c[Lmax * k], _c[Lmax * (k + 1)])
393 void fillcoeff(int auxin, int auxout, int k) const;
394 // the function atanh(e * sphi)/e; works for e^2 = 0 and e^2 < 0
395 real atanhee(real tphi) const;
396 /// \endcond
397 private:
398 // the function atanh(e * sphi)/e + sphi / (1 - (e * sphi)^2);
399 real q(real tphi) const;
400 // The divided difference of (q(1) - q(sphi)) / (1 - sphi)
401 real Dq(real tphi) const;
402 };
403
404} // namespace GeographicLib
405
406#endif // GEOGRAPHICLIB_AUXLATITUDE_HPP
Header for the GeographicLib::AuxAngle class.
#define GEOGRAPHICLIB_AUXLATITUDE_ORDER
#define GEOGRAPHICLIB_EXPORT
Definition Constants.hpp:67
GeographicLib::Math::real real
Definition GeodSolve.cpp:28
Header for GeographicLib::Math class.
An accurate representation of angles.
Definition AuxAngle.hpp:47
Conversions between auxiliary latitudes.
Math::real EquatorialRadius() const
Math::real Flattening() const
Math::real PolarSemiAxis() const
static AuxLatitude axes(real a, real b)
static Math::real Clenshaw(bool sinp, real szeta, real czeta, const real c[], int K)
Geocentric coordinates
Namespace for GeographicLib.