GeographicLib  2.6
Cartesian3.hpp
Go to the documentation of this file.
1 /**
2  * \file Cartesian3.hpp
3  * \brief Header for GeographicLib::Triaxial::Cartesian3 class
4  *
5  * Copyright (c) Charles Karney (2025) <karney@alum.mit.edu> and licensed
6  * under the MIT/X11 License. For more information, see
7  * https://geographiclib.sourceforge.io/
8  **********************************************************************/
9 
10 #if !defined(GEOGRAPHICLIB_CARTESIAN3_HPP)
11 #define GEOGRAPHICLIB_CARTESIAN3_HPP 1
12 
13 #include <utility>
14 #include <functional>
15 #include <random>
17 
18 #if defined(_MSC_VER)
19 // Squelch warnings about dll vs random
20 # pragma warning (push)
21 # pragma warning (disable: 4251)
22 #endif
23 
24 namespace GeographicLib {
25  namespace Triaxial {
26 
27  /**
28  * \brief Transformations between Cartesian and triaxial coordinates
29  *
30  * The Cartesian3 class supports transformations between cartesian
31  * coordinates and various coordinates for a triaxial ellipsoid. Besides
32  * ellipsoidal coordinates defined in Ellipsoid3, the following coordinates
33  * are supported:
34  * * geodetic coordinates \f$(\phi, \lambda)\f$ defined by
35  * \f[
36  * \hat{\mathbf U} =
37  * [\cos\phi \cos\lambda, \cos\phi \sin\lambda, \sin\phi]^T,
38  * \f]
39  * where \f$\hat{\mathbf U}\f$ is the normal to the surface of the
40  * ellipsoid.
41  * * parametric coordinates \f$(\phi', \lambda')\f$ defined by
42  * \f[
43  * \mathbf R =
44  * [a \cos\phi' \cos\lambda', b \cos\phi' \sin\lambda',
45  * c \sin\phi']^T,
46  * \f]
47  * * geocentric coordinates \f$(\phi'', \lambda'')\f$ defined by
48  * \f[
49  * \hat{\mathbf R} =
50  * [\cos\phi'' \cos\lambda'', \cos\phi'' \sin\lambda'', \sin\phi'']^T.
51  * \f]
52  * .
53  * For each of thses 3 coordinates, the "north pole" is at \f$[0, 0, c]^T\f$
54  * and the origin for longitudes is \f$[a, 0, 0]^T\f$. We also define
55  * alternate versions (named "geodetic*", etc., where the north pole is
56  * placed at \f$[a, 0, 0]^T\f$ and the origin for longitude is \f$[0, 0,
57  * -c]\f$. This latter set of coordinates is appropriate for ellipsoids that
58  * are nearly prolate.
59  *
60  * Directions on the ellipsoid are easily specified in Cartesian coordinates
61  * as a vector tangent to the surface of the ellipsoid. This is converted to
62  * a heading by defined the angle the vector makes (measured clockwise) from
63  * the coordinate-specific north. This is defined as the direction of a line
64  * of constant (coordinate-specific) longitude. The resulting heading is
65  * denoted by \f$\alpha\f$ for ellopsoidal coordinates and by \f$\zeta\f$ for
66  * the other coordinates. The unstarred coordinates all share the same
67  * direction for north, and likewise for the starred coordinates. Note that
68  * the lines of constant longitude and latitude are only orthogonal (in
69  * general) for ellipsoidal coordinates.
70  *
71  * Arbitrary points (not necessarily lying on the ellipsoid) an additional
72  * "height" is required to specify the position. For ellipsoidal
73  * coordinates, we find the confocal ellipsoid on which the point lies and
74  * the height is then defined as \f$H = u - c\f$ where \f$u\f$ is the
75  * semiminor axes of the confocal ellipsoid; the ellipsoid latitude and
76  * longitude are those for the confocal ellipsoid For the other coordinates
77  * systems, we define \f$h\f$ a the height above the closest point on the
78  * ellipsoid and the latitude and longitude refer to the closest point.
79  *
80  * \note The family of confocal ellipsoids has semiaxes \f$[\sqrt{a^2 - c^2 +
81  * u^2}, \sqrt{b^2 - c^2 + u^2}, u]\f$.
82  *
83  * \note In the function names "any" stands for any of the seven coordinate
84  * systems enumerated by Cartesian3::coord. "cart2" refers to a point
85  * given in Cartesian coordinates that lies on the ellipsoid. On the other
86  * hand, "cart" refers to an arbitrary point.
87  *
88  * Example of use:
89  * \include example-Cartesian3.cpp
90  *
91  * <a href="Cart3Convert.1.html">Cart3Convert</a> is a command-line utility
92  * providing access to the functionality of Cartestian3.
93  **********************************************************************/
95  public:
96  /**
97  * A type to hold three-dimentional positions and directions in Cartesian
98  * coordinates.
99  **********************************************************************/
101  private:
102  using real = Math::real;
103 #if GEOGRAPHICLIB_PRECISION > 3
104  // <random> only supports "standard" floating point types
105  using random_prec = Math::extended;
106 #else
107  using random_prec = Math::real;
108 #endif
109  using ang = Angle;
110  static constexpr int maxit_ = 20;
111  static constexpr bool throw_ = true; // exception on convergence failure
112  const Ellipsoid3 _t;
113  const vec3 _axes, _axes2, _linecc2;
114  // mutable because using these objects in a non-const operation
115  mutable std::normal_distribution<random_prec> _norm;
116  mutable std::uniform_real_distribution<random_prec> _uni;
117 
118  static void roty(vec3& R, int n) {
119  // require n = -1, 0, 1
120  // Prolate convention has major axis in z direction, minor axis in -x
121  // direction, median axis is unchanged.
122  // If n = 0, do nothing otherwise...
123  // With n = +1, multiply by
124  // [ 0 0 -1]
125  // [ 0 1 0]
126  // [ 1 0 0]
127  // which transforms original x, y, z to prolate convention.
128  // With n = -1, multiply by
129  // [ 0 0 1]
130  // [ 0 1 0]
131  // [-1 0 0]
132  // which transforms prolate convention to original x, y, z.
133  if (n != 0) {
134  using std::swap;
135  R[1+n] = -R[1+n];
136  swap(R[0], R[2]);
137  }
138  }
139 
140  template<int n>
141  void cart2togeneric(vec3 R, ang& phi, ang& lam, bool alt) const;
142  template<int n>
143  void generictocart2(ang phi, ang lam, vec3& R, bool alt) const;
144  template<int n> ang meridianplane(ang lam, bool alt) const;
145  void cardinaldir(vec3 R, ang merid, vec3& N, vec3& E, bool alt) const;
146  template<int n>
147  void cart2togeneric(vec3 R, vec3 V, ang& phi, ang& lam, ang& zet, bool alt)
148  const;
149  template<int n>
150  void generictocart2(ang phi, ang lam, ang zet, vec3& R, vec3&V, bool alt)
151  const;
152  real cubic(vec3 R2) const;
153 
154  template<int n>
155  class funp {
156  private:
157  // Evaluate
158  // f(p) = sum( (R[0]/(p + l[0]))^n, k = 0..2) - 1
159  // and it derivative.
160  const real _d;
161  const vec3 _r, _l;
162  public:
163  funp(const vec3& R, const vec3& l)
164  : _d(std::numeric_limits<real>::epsilon()/2)
165  , _r(R)
166  , _l(l)
167  {
168  static_assert(n >= 1 && n <= 2, "Bad power in funp");
169  }
170  std::pair<real, real> operator()(real p) const;
171  };
172 
173  static real cartsolve(const std::function<std::pair<real, real>(real)>& f,
174  real p0, real pscale);
175  void carttoellip(vec3 R, Angle& bet, Angle& omg, real& H) const;
176  void elliptocart(Angle bet, Angle omg, real H, vec3& R) const;
177 
178  // real a() const { return t().a(); } // not needed
179  real b() const { return t().b(); }
180  real c() const { return t().c(); }
181  public:
182  /**
183  * Enumerator for all the coordinates.
184  **********************************************************************/
185  enum coord {
186  /**
187  * Geodetic coordinates, \e phi, \e lam, \e zet \e h;
188  * @hideinitializer
189  **********************************************************************/
190  GEODETIC = 0,
191  /**
192  * Parametric coordinates, \e phi', \e lam', \e zet, \e h;
193  * @hideinitializer
194  **********************************************************************/
195  PARAMETRIC = 1,
196  /**
197  * %Geocentric coordinates, \e phi'', \e lam'', \e zet, \e h;
198  * @hideinitializer
199  **********************************************************************/
200  GEOCENTRIC = 2,
201  /**
202  * Ellipsoidal coordinates, \e beta, \e omg, \e alp, \e H;
203  * @hideinitializer
204  **********************************************************************/
205  ELLIPSOIDAL = 3,
206  /**
207  * Geodetic coordinates with pole aligned with the major axis.
208  * @hideinitializer
209  **********************************************************************/
210  GEODETIC_X = 4 + GEODETIC,
211  /**
212  * Parametric coordinates with pole aligned with the major axis.
213  * @hideinitializer
214  **********************************************************************/
215  PARAMETRIC_X = 4 + PARAMETRIC,
216  /**
217  * %Geocentric coordinates with pole aligned with the major axis.
218  * @hideinitializer
219  **********************************************************************/
220  GEOCENTRIC_X = 4 + GEOCENTRIC,
221  /**
222  * An alias for GEODETIC;
223  * @hideinitializer
224  **********************************************************************/
225  PLANETODETIC = GEODETIC,
226  /**
227  * Another alias for GEODETIC;
228  * @hideinitializer
229  **********************************************************************/
230  GEOGRAPHIC = GEODETIC,
231  /**
232  * An alias for GEOCENTRIC;
233  * @hideinitializer
234  **********************************************************************/
235  PLANETOCENTRIC = GEOCENTRIC,
236  };
237  /** \name Transformations for points on the ellipsoid.
238  **********************************************************************/
239  ///@{
240  /**
241  * Constructor for a triaxial ellipsoid defined by Ellipsoid3 object.
242  *
243  * @param[in] t the Ellipsoid3 object.
244  **********************************************************************/
245  Cartesian3(const Ellipsoid3& t);
246  /**
247  * Constructor for a trixial ellipsoid with semi-axes.
248  *
249  * @param[in] a the largest semi-axis.
250  * @param[in] b the middle semi-axis.
251  * @param[in] c the smallest semi-axis.
252  * @exception GeographicErr if the required ordering is semiaxes is
253  * violated.
254  *
255  * The semi-axes must satisfy \e a &ge; \e b &ge; \e c &gt; 0.
256  * If \e a = \e c (a sphere), then the oblate limit is taken.
257  **********************************************************************/
258  Cartesian3(real a, real b, real c);
259  /**
260  * Alternate constructor for a triaxial ellipsoid.
261  *
262  * @param[in] b the middle semi-axis.
263  * @param[in] e2 the eccentricity squared \f$e^2 = (a^2 - c^2)/b^2\f$.
264  * @param[in] k2 the oblateness parameter squared \f$k^2 = (b^2 - c^2) /
265  * (a^2 - c^2)\f$.
266  * @param[in] kp2 the prolateness parameter squared \f$k'^2= (a^2 - b^2) /
267  * (a^2 - c^2)\f$.
268  * @exception GeographicErr if the required ordering is semiaxes is
269  * violated.
270  *
271  * \note The constructor normalizes \e k2 and \e kp2 to ensure then \e k2 +
272  * \e kp2 = 1.
273  **********************************************************************/
274  Cartesian3(real b, real e2, real k2, real kp2);
275  ///@}
276 
277  /** \name Transformations for points on the ellipsoid.
278  **********************************************************************/
279  ///@{
280  /**
281  * Convert latitude and longitude to a point on the surface.
282  *
283  * @param[in] coordin one of the coordinate types, Cartesian3::coord.
284  * @param[in] lat the latitude of the point.
285  * @param[in] lon the longitude of the point.
286  * @param[out] R the Cartesian position on the surface of the ellipsoid.
287  * @exception GeographicErr if \e coordin is not recognized.
288  **********************************************************************/
289  void anytocart2(coord coordin, Angle lat, Angle lon, vec3& R) const;
290  /**
291  * Convert latitude and longitude in degrees to a point on the surface.
292  *
293  * @param[in] coordin one of the coordinate types, Cartesian3::coord.
294  * @param[in] lat the latitude of the point (in degrees).
295  * @param[in] lon the longitude of the point (in degrees).
296  * @param[out] R the Cartesian position on the surface of the ellipsoid.
297  * @exception GeographicErr if \e coordin is not recognized.
298  **********************************************************************/
299  void anytocart2(coord coordin, real lat, real lon, vec3& R) const {
300  anytocart2(coordin, Angle(lat), Angle(lon), R);
301  }
302  /**
303  * Convert a point on the surface to latitude and longitude.
304  *
305  * @param[in] R the Cartesian position on the surface of the ellipsoid.
306  * @param[in] coordout one of the coordinate types, Cartesian3::coord.
307  * @param[out] lat the latitude of the point.
308  * @param[out] lon the longitude of the point.
309  * @exception GeographicErr if \e coordout is not recognized.
310  **********************************************************************/
311  void cart2toany(vec3 R, coord coordout, Angle& lat, Angle& lon) const;
312  /**
313  * Convert a point on the surface to latitude and longitude in degrees.
314  *
315  * @param[in] R the Cartesian position on the surface of the ellipsoid.
316  * @param[in] coordout one of the coordinate types, Cartesian3::coord.
317  * @param[out] lat the latitude of the point (in degrees).
318  * @param[out] lon the longitude of the point (in degrees).
319  * @exception GeographicErr if \e coordout is not recognized.
320  **********************************************************************/
321  void cart2toany(vec3 R, coord coordout, real& lat, real& lon) const {
322  Angle lata, lona; cart2toany(R, coordout, lata, lona);
323  lat = real(lata); lon = real(lona);
324  }
325  /**
326  * Convert between latitudes and longitudes.
327  *
328  * @param[in] coordin one of the coordinate types, Cartesian3::coord.
329  * @param[in] lat1 the \e coordin latitude of the point.
330  * @param[in] lon1 the \e coordin longitude of the point.
331  * @param[in] coordout one of the coordinate types, Cartesian3::coord.
332  * @param[out] lat2 the \e coordout latitude of the point.
333  * @param[out] lon2 the \e coordout longitude of the point.
334  * @exception GeographicErr if \e coordin or \e coordout is not recognized.
335  **********************************************************************/
336  void anytoany(coord coordin, Angle lat1, Angle lon1,
337  coord coordout, Angle& lat2, Angle& lon2) const;
338  /**
339  * Convert between latitudes and longitudes in degrees.
340  *
341  * @param[in] coordin one of the coordinate types, Cartesian3::coord.
342  * @param[in] lat1 the \e coordin latitude of the point (in degrees).
343  * @param[in] lon1 the \e coordin longitude of the point (in degrees).
344  * @param[in] coordout one of the coordinate types, Cartesian3::coord.
345  * @param[out] lat2 the \e coordout latitude of the point (in degrees).
346  * @param[out] lon2 the \e coordout longitude of the point (in degrees).
347  * @exception GeographicErr if \e coordin or \e coordout is not recognized.
348  **********************************************************************/
349  void anytoany(coord coordin, real lat1, real lon1,
350  coord coordout, real& lat2, real& lon2) const {
351  Angle lat2a, lon2a;
352  anytoany(coordin, Angle(lat1), Angle(lon1), coordout, lat2a, lon2a);
353  lat2 = real(lat2a); lon2 = real(lon2a);
354  }
355  ///@}
356 
357  /** \name Transformations for points and directions on the ellipsoid.
358  **********************************************************************/
359  ///@{
360  /**
361  * Convert latitiude, longitude, and azimuth to Cartesian position and
362  * direction.
363  *
364  * @param[in] coordin one of the coordinate types, Cartesian3::coord.
365  * @param[in] lat the latitude of the point.
366  * @param[in] lon the longitude of the point.
367  * @param[in] azi the azimuth of the heading.
368  * @param[out] R the Cartesian position on the surface of the ellipsoid.
369  * @param[out] V the Cartesian direction tangent to the ellipsoid.
370  * @exception GeographicErr if \e coordin is not recognized.
371  **********************************************************************/
372  void anytocart2(coord coordin, Angle lat, Angle lon, Angle azi,
373  vec3& R, vec3& V) const;
374  /**
375  * Convert latitiude, longitude, and azimuth in degrees to Cartesian
376  * position and direction.
377  *
378  * @param[in] coordin one of the coordinate types, Cartesian3::coord.
379  * @param[in] lat the latitude of the point (in degrees).
380  * @param[in] lon the longitude of the point (in degrees).
381  * @param[in] azi the azimuth of the heading (in degrees).
382  * @param[out] R the Cartesian position on the surface of the ellipsoid.
383  * @param[out] V the Cartesian direction tangent to the ellipsoid.
384  * @exception GeographicErr if \e coordin is not recognized.
385  **********************************************************************/
386  void anytocart2(coord coordin, real lat, real lon, real azi,
387  vec3& R, vec3& V) const {
388  anytocart2(coordin, Angle(lat), Angle(lon), Angle(azi), R, V);
389  }
390  /**
391  * Convert position and direction on surface to latitiude, longitude, and
392  * azimuth.
393  *
394  * @param[in] R the Cartesian position on the surface of the ellipsoid.
395  * @param[in] V the Cartesian direction tangent to the ellipsoid.
396  * @param[in] coordout one of the coordinate types, Cartesian3::coord.
397  * @param[out] lat the latitude of the point.
398  * @param[out] lon the longitude of the point.
399  * @param[out] azi the azimuth of the heading.
400  * @exception GeographicErr if \e coordout is not recognized.
401  **********************************************************************/
402  void cart2toany(vec3 R, vec3 V,
403  coord coordout, Angle& lat, Angle& lon, Angle& azi) const;
404  /**
405  * Convert position and direction on surface to latitiude, longitude, and
406  * azimuth in degrees.
407  *
408  * @param[in] R the Cartesian position on the surface of the ellipsoid.
409  * @param[in] V the Cartesian direction tangent to the ellipsoid.
410  * @param[in] coordout one of the coordinate types, Cartesian3::coord.
411  * @param[out] lat the latitude of the point (in degrees).
412  * @param[out] lon the longitude of the point (in degrees).
413  * @param[out] azi the azimuth of the heading (in degrees).
414  * @exception GeographicErr if \e coordout is not recognized.
415  **********************************************************************/
416  void cart2toany(vec3 R, vec3 V,
417  coord coordout, real& lat, real& lon, real& azi) const {
418  Angle lata, lona, azia; cart2toany(R, V, coordout, lata, lona, azia);
419  lat = real(lata); lon = real(lona), azi = real(azia);
420  }
421  ///@}
422 
423  /** \name Transformations for arbitrary points.
424  **********************************************************************/
425  ///@{
426  /**
427  * Convert latitiude, longitude, and height to a Cartesian position.
428  *
429  * @param[in] coordin one of the coordinate types, Cartesian3::coord.
430  * @param[in] lat the latitude of the point.
431  * @param[in] lon the longitude of the point.
432  * @param[in] h the height (in meters).
433  * @param[out] R the Cartesian position of the point.
434  * @exception GeographicErr if \e coordin is not recognized.
435  **********************************************************************/
436  void anytocart(coord coordin, Angle lat, Angle lon, real h, vec3& R) const;
437  /**
438  * Convert latitiude, longitude in degrees, and height to a Cartesian
439  * position.
440  *
441  * @param[in] coordin one of the coordinate types, Cartesian3::coord.
442  * @param[in] lat the latitude of the point (in degrees).
443  * @param[in] lon the longitude of the point (in degrees).
444  * @param[in] h the height (in meters).
445  * @param[out] R the Cartesian position of the point.
446  * @exception GeographicErr if \e coordin is not recognized.
447  **********************************************************************/
448  void anytocart(coord coordin, real lat, real lon, real h, vec3& R) const {
449  anytocart(coordin, Angle(lat), Angle(lon), h, R);
450  }
451  /**
452  * Convert a Cartesian position to latitiude, longitude, and height.
453  *
454  * @param[in] R the Cartesian position of the point.
455  * @param[in] coordout one of the coordinate types, Cartesian3::coord.
456  * @param[out] lat the latitude of the point.
457  * @param[out] lon the longitude of the point.
458  * @param[out] h the height (in meters).
459  * @exception GeographicErr if \e coordin is not recognized.
460  **********************************************************************/
461  void carttoany(vec3 R,
462  coord coordout, Angle& lat, Angle& lon, real& h) const;
463  /**
464  * Convert a Cartesian position to latitiude, longitude in degrees, and
465  * height.
466  *
467  * @param[in] R the Cartesian position of the point.
468  * @param[in] coordout one of the coordinate types, Cartesian3::coord.
469  * @param[out] lat the latitude of the point (in degrees).
470  * @param[out] lon the longitude of the point (in degrees).
471  * @param[out] h the height (in meters).
472  * @exception GeographicErr if \e coordin is not recognized.
473  **********************************************************************/
474  void carttoany(vec3 R,
475  coord coordout, real& lat, real& lon, real& h) const {
476  Angle lata, lona; carttoany(R, coordout, lata, lona, h);
477  lat = real(lata); lon = real(lona);
478  }
479  ///@}
480 
481  /** \name Transferring an arbitrary point onto the ellipsoid.
482  **********************************************************************/
483  ///@{
484  /**
485  * Convert a point on the ellipsoid and a height to a Cartesian position.
486  *
487  * @param[in] R2 the Cartesian position of the point on the ellipsoid.
488  * @param[in] h the height above the ellipsoid (in meters).
489  * @param[out] R the Cartesian position of the point.
490  **********************************************************************/
491  void cart2tocart(vec3 R2, real h, vec3& R) const;
492  /**
493  * Find the closest point on the ellipsoid
494  *
495  * @param[in] R the Cartesian position of the point.
496  * @param[out] R2 the Cartesian position of the closest point on the
497  * ellipsoid.
498  * @param[out] h the height above the ellipsoid (in meters).
499  **********************************************************************/
500  void carttocart2(vec3 R, vec3& R2, real& h) const;
501  ///@}
502 
503  /** \name Generating random points on the ellipsoid.
504  **********************************************************************/
505  ///@{
506  /**
507  * Generate a random point on the ellipsoid.
508  *
509  * @tparam G the type of the random generator.
510  * @param[in] g the random generator.
511  * @param[out] R a Cartesian position uniformly sampled on the surface of
512  * the ellipsoid.
513  *
514  * See the example listed in the description of this class for an example
515  * of using this function.
516  *
517  * The method of sampling is given by
518  * <a href="https://doi.org/10.1007/s11075-023-01628-4"> Marples and
519  * Williams (2023)</a> Algorithm 1, based on the general method of
520  * <a href="https://doi.org/10.1088/0031-9155/32/10/009"> Williamson
521  * (1987)</a>.
522  **********************************************************************/
523  template <class G> void cart2rand(G& g, vec3& R) const;
524  /**
525  * Generate a random point and direction on the ellipsoid.
526  *
527  * @tparam G the type of the random generator.
528  * @param[in] g the random generator.
529  * @param[out] R a Cartesian position uniformly sampled on the surface of
530  * the ellipsoid.
531  * @param[out] V a Cartesian direction uniformly sampled tangent to the
532  * ellipsoid.
533  **********************************************************************/
534  template <class G> void cart2rand(G& g, vec3& R, vec3& V) const;
535  ///@}
536 
537  /** \name Inspector function
538  **********************************************************************/
539  ///@{
540  /**
541  * @return the Ellipsoid3 object for this projection.
542  **********************************************************************/
543  const Ellipsoid3& t() const { return _t; }
544  ///@}
545  };
546 
547  template<class G> inline void Cartesian3::cart2rand(G& g, vec3& R) const {
548  // This uses the simple rejection technique given by Marples and Williams,
549  // Num. Alg. (2023), Algorithm 1 based on the general method of Williamson,
550  // Phys. Med. Biol. (1987).
551  using std::isfinite;
552  while (true) {
553  while (true) {
554  // guaranteed evaluated left to right
555  R = {real(_norm(g)), real(_norm(g)), real(_norm(g))};
556  Ellipsoid3::normvec(R); // But catch rare cases where |R| = 0
557  if (isfinite(R[0])) break;
558  }
559  R[0] *= _axes[0]; R[1] *= _axes[1]; R[2] *= _axes[2];
560  vec3 up{ R[0] / _axes2[0], R[1] / _axes2[1], R[2] / _axes2[2] };
561  real q = c() * Math::hypot3(up[0], up[1], up[2]);
562  if (real(_uni(g)) < q) break;
563  }
564  }
565  template<class G> inline void Cartesian3::cart2rand(G& g, vec3& R, vec3& V)
566  const {
567  using std::isfinite;
568  cart2rand<G>(g, R);
569  while (true) {
570  // guaranteed evaluated left to right
571  V = {real(_norm(g)), real(_norm(g)), real(_norm(g))};
572  vec3 up{ R[0] / _axes2[0], R[1] / _axes2[1], R[2] / _axes2[2] };
573  real u2 = Math::sq(up[0]) + Math::sq(up[1]) + Math::sq(up[2]), // |up|^2
574  // (up . V) / |up|^2
575  uv = (V[0] * up[0] + V[1] * up[1] + V[2] * up[2])/u2;
576  // V - up * (up . V) / |up|^2
577  V[0] -= uv * up[0]; V[1] -= uv * up[1]; V[2] -= uv * up[2];
578  Ellipsoid3::normvec(V); // But catch rare cases where |V| = 0
579  if (isfinite(V[0])) break;
580  }
581  }
582 
583  } // namespace Triaxial
584 } // namespace GeographicLib
585 
586 #if defined(_MSC_VER)
587 # pragma warning (pop)
588 #endif
589 
590 #endif // GEOGRAPHICLIB_CARTESIAN3_HPP
std::array< Math::real, 3 > vec3
Definition: Ellipsoid3.hpp:88
#define GEOGRAPHICLIB_EXPORT
Definition: Constants.hpp:59
void cart2rand(G &g, vec3 &R) const
Definition: Cartesian3.hpp:547
void anytocart(coord coordin, real lat, real lon, real h, vec3 &R) const
Definition: Cartesian3.hpp:448
double extended
Definition: Math.hpp:95
AngleT< Math::real > Angle
Definition: Angle.hpp:760
void anytoany(coord coordin, real lat1, real lon1, coord coordout, real &lat2, real &lon2) const
Definition: Cartesian3.hpp:349
void anytocart2(coord coordin, real lat, real lon, vec3 &R) const
Definition: Cartesian3.hpp:299
static T sq(T x)
Definition: Math.hpp:209
Namespace for GeographicLib.
Definition: Accumulator.cpp:12
Header for GeographicLib::Triaxial::Ellipsoid3 class.
static T hypot3(T x, T y, T z)
Definition: Math.cpp:285
GeographicLib::Math::real real
Definition: Geod3Solve.cpp:25
const Ellipsoid3 & t() const
Definition: Cartesian3.hpp:543
void swap(GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &a, GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &b)
Transformations between Cartesian and triaxial coordinates.
Definition: Cartesian3.hpp:94
void anytocart2(coord coordin, real lat, real lon, real azi, vec3 &R, vec3 &V) const
Definition: Cartesian3.hpp:386
void cart2toany(vec3 R, vec3 V, coord coordout, real &lat, real &lon, real &azi) const
Definition: Cartesian3.hpp:416
void carttoany(vec3 R, coord coordout, real &lat, real &lon, real &h) const
Definition: Cartesian3.hpp:474
void cart2toany(vec3 R, coord coordout, real &lat, real &lon) const
Definition: Cartesian3.hpp:321