GeographicLib  2.6
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>
22 #include <GeographicLib/Math.hpp>
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 
37 namespace 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, 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
#define GEOGRAPHICLIB_EXPORT
Definition: Constants.hpp:59
An accurate representation of angles.
Definition: AuxAngle.hpp:51
Math::real Flattening() const
Geocentric coordinates
Definition: Geocentric.hpp:67
Header for GeographicLib::Math class.
Header for the GeographicLib::AuxAngle class.
Namespace for GeographicLib.
Definition: Accumulator.cpp:12
GeographicLib::Math::real real
Definition: Geod3Solve.cpp:25
Math::real EquatorialRadius() const
#define GEOGRAPHICLIB_AUXLATITUDE_ORDER
Definition: AuxLatitude.hpp:32
Conversions between auxiliary latitudes.
Definition: AuxLatitude.hpp:75
Math::real PolarSemiAxis() const
static AuxLatitude axes(real a, real b)