GeographicLib
2.7
Toggle main menu visibility
Loading...
Searching...
No Matches
Geodesic3.hpp
Go to the documentation of this file.
1
/**
2
* \file Geodesic3.hpp
3
* \brief Header for GeographicLib::Triaxial::Geodesic3 class
4
*
5
* Copyright (c) Charles Karney (2024-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_GEODESIC3_HPP)
11
#define GEOGRAPHICLIB_GEODESIC3_HPP 1
12
13
#include <functional>
14
#include <memory>
15
#include <
GeographicLib/Triaxial/Ellipsoid3.hpp
>
16
17
#if defined(_MSC_VER)
18
// Squelch warnings about dll vs shared_ptr
19
# pragma warning (push)
20
# pragma warning (disable: 4251)
21
#endif
22
23
namespace
GeographicLib
{
24
namespace
Triaxial
{
25
class
GeodesicLine3
;
26
27
/**
28
* \brief The solution of the geodesic problem for a triaxial ellipsoid
29
*
30
* This is an implementation of
31
* <a href="https://books.google.com/books?id=RbwGAAAAYAAJ&pg=PA309">
32
* Jacobi's method for finding geodesics on a triaxial ellipsoid</a>
33
* (1839). This class offers an interface to the solutions to the direct
34
* geodesic problem via the GeodesicLine3 class which contains the meat of
35
* Jacobi's direct solution. In addition it provides a solution to the
36
* inverse problem which closely parallels the solution for the biaxial
37
* problem given by GeodesicExact. For more details see \ref triaxial
38
* and
39
* - C. F. F. Karney,<br>
40
* <a href="https://arxiv.org/abs/2511.01621">
41
* Jacobi's solution for geodesics on a triaxial ellipsoid</a>,<br>
42
* Technical Report, SRI International, Nov. 2025.<br>
43
* <a href="https://arxiv.org/abs/2511.01621">arxiv:2511.01621</a>
44
*
45
* Data for testing the geodesic routines is available at
46
* <a href="https://doi.org/10.5281/zenodo.12510796"> Test set of geodesics
47
* on a triaxial ellipsoid (2024)</a>.
48
*
49
* \note There's a lot of new code here and testing is two orders of
50
* magnitude more difficult compared with the biaxial case (an extra
51
* parameter to fix the shape of the ellipsoid and geodesics now depend on
52
* the longitude of the two end points separately). I've limited by testing
53
* to ellipsoids with \e a/\e c ≤ 2. I don't expect any problems if \e
54
* a/\e c ≤ 10; but you might run into problems with more eccentric
55
* ellipsoids. The code treats oblate and prolate (biaxial) ellipsoids
56
* correctly; but, again, there may be problems with triaxial ellipsoids
57
* which are \e extremely close to oblate or prolate i.e., with either \e k
58
* or \e k' very small. (However the triaxial model of the Earth where the
59
* difference in the equatorial semiaxes is 70 m, \f$k' = 0.057\f$, is
60
* treated just fine.) While I have made every effort to ensure that the
61
* code is error free, it's likely that some bugs remain. Please use caution
62
* with the results and report any problems (via email or with a Github
63
* issue).
64
*
65
* Example of use:
66
* \include example-Geodesic3.cpp
67
*
68
* <a href="Geod3Solve.1.html">Geod3Solve</a> is a command-line utility
69
* providing access to the functionality of Geodesic3 and GeodesicLine3.
70
**********************************************************************/
71
class
GEOGRAPHICLIB_EXPORT
Geodesic3
{
72
private
:
73
/// \cond SKIP
74
// For access to BigValue, _ellipthresh, _biaxp
75
friend
class
GeodesicLine3
;
76
/// \endcond
77
using
real =
Math::real
;
78
using
ang =
Angle
;
79
static
constexpr
bool
debug_ =
false
;
// print out diagnostics
80
static
constexpr
bool
throw_ =
true
;
// exception on convergence failure
81
// special treatment for biaxial non-meridional
82
static
constexpr
bool
biaxp_ =
true
;
83
// favor hybrid solution in terms of omg
84
static
constexpr
bool
hybridalt_ =
true
;
85
// allow swapping of omega{1,2}
86
static
constexpr
bool
swapomg_ =
false
;
87
static
constexpr
int
maxit_ = 200;
88
Ellipsoid3
_t;
89
90
// Run geodesic from bet1, omg1, alp1, find its first intersection with bet
91
// = bet2a and return omg2a - omg2b
92
real HybridA(ang bet1, ang omg1, ang alp1,
93
ang bet2a, ang omg2b,
bool
betp)
const
;
94
static
ang findroot(
const
std::function<
real
(
const
ang&)>& f,
95
ang xa, ang xb,
96
real fa, real fb,
97
int
* countn =
nullptr
,
int
* countb =
nullptr
);
98
bool
_umbalt;
// how coordinates wrap with umbilical lines
99
// If k'^2 < ellipthresh transform phi -> F(phi, k^2)
100
real _ellipthresh;
101
mutable
std::shared_ptr<GeodesicLine3> _umbline;
102
static
real BigValue() {
103
using
std::log;
104
static
real bigval = -3*log(std::numeric_limits<real>::epsilon());
105
return
bigval;
106
}
107
class
gamblk {
108
public
:
109
bool
transpolar;
110
// gamma = (k * cbet * salp)^2 - (kp * somg * calp)^2
111
// = k2*cb2*sa2 - kp2*so2*ca2
112
// Need accurate expressions for
113
// k2 - gamma = k2*(sb2+ca2*cb2) + kp2*so2*ca2
114
// kp2 + gamma = k2*cb2*sa2 + kp2*(co2+sa2*so2)
115
// If gamma is given, eval new alp given new bet and new omg
116
// gamma < 0
117
// ca2 = (k2*cb2-gamma) / (k2*cb2+kp2*so2)
118
// sa2 = (kp2+gamma - kp2*co2) / (k2*cb2+kp2*so2)
119
// gamma > 0
120
// ca2 = (k2-gamma - k2*sb2) / (k2*cb2+kp2*so2)
121
// sa2 = (kp2*so2+gamma) / (k2*cb2+kp2*so2)
122
// gamma > 0
123
// k2*sb2 = spsi2 * (k2-gamma)
124
// (k2-gamma - k2*sb2) = (k2-gamma)*(1-spsi2) = (k2-gamma)*cpsi2
125
// spsi2 = k2*sb2/(k2-gamma)
126
// cpsi2 = (k2*cb2-gamma)/(k2-gamma)
127
real gamma,
128
// [nu, nup]
129
// = [sqrt(gam)/k, sqrt(1 - gam/k2)] for !signbit(gam)
130
// = [sqrt(-gam)/kp, sqrt(1 + gam/kp2)] for signbit(gam)
131
// unused for umbilics
132
nu, nup,
133
gammax, kx2, kxp2, kx, kxp;
134
// Default values for gamma = +/-0
135
gamblk() {}
136
gamblk(
const
Geodesic3
& tg,
bool
neg =
false
);
137
gamblk(
const
Geodesic3
& tg, ang bet, ang omg, ang alp);
138
// gamblk(real gammax, real nux, real nupx)
139
// : gamma(gammax), nu(nux), nup(nupx) {}
140
};
141
gamblk gamma(ang bet, ang omg, ang alp)
142
const
;
143
// real a() const { return t().a(); } // not needed
144
real b()
const
{
return
t
().b(); }
145
// real c() const { return t().c(); } // not needed
146
real e2()
const
{
return
t
().e2(); }
147
real k2()
const
{
return
t
().k2(); }
148
real kp2()
const
{
return
t
().kp2(); }
149
real k()
const
{
return
t
().k(); }
150
real kp()
const
{
return
t
().kp(); }
151
bool
oblate()
const
{
return
t
().oblate(); }
152
bool
prolate()
const
{
return
t
().prolate(); }
153
bool
biaxial()
const
{
return
t
().biaxial(); }
154
public
:
155
/**
156
* Constructor for a triaxial ellipsoid defined by Ellipsoid3 object.
157
*
158
* @param[in] t the Ellipsoid3 object.
159
**********************************************************************/
160
Geodesic3
(
const
Ellipsoid3
&
t
=
Ellipsoid3
{});
161
/**
162
* Constructor for a triaxial ellipsoid with semiaxes.
163
*
164
* @param[in] a the largest semiaxis.
165
* @param[in] b the middle semiaxis.
166
* @param[in] c the smallest semiaxis.
167
* @exception GeographicErr if the required ordering is semiaxes is
168
* violated.
169
*
170
* The semiaxes must satisfy \e a ≥ \e b ≥ \e c > 0.
171
* If \e a = \e c (a sphere), then the oblate limit is taken.
172
**********************************************************************/
173
Geodesic3
(real a, real b, real c);
174
/**
175
* Alternate constructor for a triaxial ellipsoid.
176
*
177
* @param[in] b the middle semiaxis.
178
* @param[in] e2 the eccentricity squared \f$e^2 = (a^2 - c^2)/b^2\f$.
179
* @param[in] k2 the oblateness parameter squared \f$k^2 = (b^2 - c^2) /
180
* (a^2 - c^2)\f$.
181
* @param[in] kp2 the prolateness parameter squared \f$k'^2= (a^2 - b^2) /
182
* (a^2 - c^2)\f$.
183
* @exception GeographicErr if the required ordering is semiaxes is
184
* violated.
185
*
186
* \note The constructor normalizes \e k2 and \e kp2 to ensure then \e k2 +
187
* \e kp2 = 1.
188
**********************************************************************/
189
Geodesic3
(real b, real e2, real k2, real kp2);
190
/**
191
* @return the Ellipsoid3 object for this projection.
192
**********************************************************************/
193
const
Ellipsoid3
&
t
()
const
{
return
_t; }
194
/**
195
* Solve the inverse problem
196
*
197
* @param[in] bet1 the ellipsoidal latitude of point 1.
198
* @param[in] omg1 the ellipsoidal longitude of point 1.
199
* @param[in] bet2 the ellipsoidal latitude of point 2.
200
* @param[in] omg2 the ellipsoidal longitude of point 2.
201
* @param[out] s12 the shortest distance between the points.
202
* @param[out] alp1 the forward azimuth of the geodesic at point 1.
203
* @param[out] alp2 the forward azimuth of the geodesic at point 2.
204
* @return a GeodesicLine3 object defining the geodesic.
205
**********************************************************************/
206
GeodesicLine3
Inverse(
Angle
bet1,
Angle
omg1,
Angle
bet2,
Angle
omg2,
207
real
& s12,
Angle
& alp1,
Angle
& alp2)
const
;
208
/**
209
* Solve the inverse problem in degrees
210
*
211
* @param[in] bet1 the ellipsoidal latitude of point 1 (in degrees).
212
* @param[in] omg1 the ellipsoidal longitude of point 1 (in degrees).
213
* @param[in] bet2 the ellipsoidal latitude of point 2 (in degrees).
214
* @param[in] omg2 the ellipsoidal longitude of point 2 (in degrees).
215
* @param[out] s12 the shortest distance between the points.
216
* @param[out] alp1 the forward azimuth of the geodesic at point 1 (in
217
* degrees).
218
* @param[out] alp2 the forward azimuth of the geodesic at point 2 (in
219
* degrees).
220
* @return a GeodesicLine3 object defining the geodesic.
221
**********************************************************************/
222
GeodesicLine3
Inverse(
real
bet1,
real
omg1,
real
bet2,
real
omg2,
223
real
& s12,
real
& alp1,
real
& alp2)
const
;
224
/**
225
* Solve the direct problem
226
*
227
* @param[in] bet1 the ellipsoidal latitude of point 1.
228
* @param[in] omg1 the ellipsoidal longitude of point 1.
229
* @param[in] alp1 the forward azimuth of the geodesic at point 1.
230
* @param[in] s12 the distance from point 1 to point 2.
231
* @param[out] bet2 the ellipsoidal latitude of point 2.
232
* @param[out] omg2 the ellipsoidal longitude of point 2.
233
* @param[out] alp2 the forward azimuth of the geodesic at point 2.
234
* @return a GeodesicLine3 object defining the geodesic.
235
**********************************************************************/
236
GeodesicLine3
Direct(
Angle
bet1,
Angle
omg1,
Angle
alp1,
real
s12,
237
Angle
& bet2,
Angle
& omg2,
Angle
& alp2)
const
;
238
/**
239
* Solve the direct problem in degrees
240
*
241
* @param[in] bet1 the ellipsoidal latitude of point 1 (in degrees).
242
* @param[in] omg1 the ellipsoidal longitude of point 1 (in degrees).
243
* @param[in] alp1 the forward azimuth of the geodesic at point 1 (in
244
* degrees).
245
* @param[in] s12 the distance from point 1 to point 2.
246
* @param[out] bet2 the ellipsoidal latitude of point 2 (in degrees).
247
* @param[out] omg2 the ellipsoidal longitude of point 2 (in degrees).
248
* @param[out] alp2 the forward azimuth of the geodesic at point 2 (in
249
* degrees).
250
* @return a GeodesicLine3 object defining the geodesic.
251
**********************************************************************/
252
GeodesicLine3
Direct(
real
bet1,
real
omg1,
real
alp1,
real
s12,
253
real
& bet2,
real
& omg2,
real
& alp2)
const
;
254
/**
255
* A geodesic line defined at a starting point
256
*
257
* @param[in] bet1 the ellipsoidal latitude of point 1.
258
* @param[in] omg1 the ellipsoidal longitude of point 1.
259
* @param[in] alp1 the forward azimuth of the geodesic at point 1.
260
* @return a GeodesicLine3 object defining the geodesic.
261
**********************************************************************/
262
GeodesicLine3
Line(
Angle
bet1,
Angle
omg1,
Angle
alp1)
const
;
263
/**
264
* A geodesic line defined at a starting point specified in degrees
265
*
266
* @param[in] bet1 the ellipsoidal latitude of point 1 (in degrees).
267
* @param[in] omg1 the ellipsoidal longitude of point 1 (in degrees).
268
* @param[in] alp1 the forward azimuth of the geodesic at point 1 (in
269
* degrees).
270
* @return a GeodesicLine3 object defining the geodesic.
271
**********************************************************************/
272
GeodesicLine3
Line(
real
bet1,
real
omg1,
real
alp1)
const
;
273
/**
274
* Specify the behavior of umbilical geodesics
275
*
276
* @param[in] numbalt the new value of the \e umbalt flag.
277
*
278
* If \e umbalt is true (resp. false) then the latitude (resp. longitude)
279
* of an umbilical geodesic is the librating coordinate and the longitude
280
* (resp. latitude) is the rotating coordinate. This has no effect for
281
* biaxial ellipsoids. In this case the latitude (resp. longitude) is
282
* always the librating coordinate for oblate (resp. prolate) ellipsoids.
283
**********************************************************************/
284
void
umbalt
(
bool
numbalt) {
285
if
(_t.k2() > 0 && _t.kp2() > 0) _umbalt = numbalt;
286
}
287
/**
288
* @return the value of the \e umbalt flag; see umbalt(bool)).
289
**********************************************************************/
290
bool
umbalt
()
const
{
return
_umbalt; }
291
};
292
293
}
// namespace Triaxial
294
}
// namespace GeographicLib
295
296
#if defined(_MSC_VER)
297
# pragma warning (pop)
298
#endif
299
300
// Include this because all the Geodesic3 methods return a GeodesicLine3.
301
#include <
GeographicLib/Triaxial/GeodesicLine3.hpp
>
302
303
#endif
// GEOGRAPHICLIB_GEODESIC3_HPP
GEOGRAPHICLIB_EXPORT
#define GEOGRAPHICLIB_EXPORT
Definition
Constants.hpp:59
Ellipsoid3.hpp
Header for GeographicLib::Triaxial::Ellipsoid3 class.
real
GeographicLib::Math::real real
Definition
Geod3Solve.cpp:25
GeodesicLine3.hpp
Header for GeographicLib::Triaxial::GeodesicLine3 class.
GeographicLib::Math::real
double real
Definition
Math.hpp:115
GeographicLib::Triaxial::Ellipsoid3
A triaxial ellipsoid.
Definition
Ellipsoid3.hpp:89
GeographicLib::Triaxial::Geodesic3::Geodesic3
Geodesic3(const Ellipsoid3 &t=Ellipsoid3{})
Definition
Geodesic3.cpp:19
GeographicLib::Triaxial::Geodesic3::umbalt
void umbalt(bool numbalt)
Definition
Geodesic3.hpp:284
GeographicLib::Triaxial::Geodesic3::t
const Ellipsoid3 & t() const
Definition
Geodesic3.hpp:193
GeographicLib::Triaxial::Geodesic3::umbalt
bool umbalt() const
Definition
Geodesic3.hpp:290
GeographicLib::Triaxial::GeodesicLine3
The direct geodesic problem for a triaxial ellipsoid.
Definition
GeodesicLine3.hpp:54
GeographicLib::Triaxial
Namespace for operations on triaxial ellipsoids.
Definition
Cartesian3.cpp:13
GeographicLib
Namespace for GeographicLib.
Definition
Accumulator.cpp:12
GeographicLib::Angle
AngleT< Math::real > Angle
Definition
Angle.hpp:760
include
GeographicLib
Triaxial
Geodesic3.hpp
Generated by
1.17.0