src/Rhumb.cpp
Go to the documentation of this file.
1 
11 #include <algorithm>
12 #include <GeographicLib/Rhumb.hpp>
13 
14 namespace GeographicLib {
15 
16  using namespace std;
17 
18  Rhumb::Rhumb(real a, real f, bool exact)
19  : _ell(a, f)
20  , _exact(exact)
21  , _c2(_ell.Area() / 720)
22  {
23  // Generated by Maxima on 2015-05-15 08:24:04-04:00
24 #if GEOGRAPHICLIB_RHUMBAREA_ORDER == 4
25  static const real coeff[] = {
26  // R[0]/n^0, polynomial in n of order 4
27  691, 7860, -20160, 18900, 0, 56700,
28  // R[1]/n^1, polynomial in n of order 3
29  1772, -5340, 6930, -4725, 14175,
30  // R[2]/n^2, polynomial in n of order 2
31  -1747, 1590, -630, 4725,
32  // R[3]/n^3, polynomial in n of order 1
33  104, -31, 315,
34  // R[4]/n^4, polynomial in n of order 0
35  -41, 420,
36  }; // count = 20
37 #elif GEOGRAPHICLIB_RHUMBAREA_ORDER == 5
38  static const real coeff[] = {
39  // R[0]/n^0, polynomial in n of order 5
40  -79036, 22803, 259380, -665280, 623700, 0, 1871100,
41  // R[1]/n^1, polynomial in n of order 4
42  41662, 58476, -176220, 228690, -155925, 467775,
43  // R[2]/n^2, polynomial in n of order 3
44  18118, -57651, 52470, -20790, 155925,
45  // R[3]/n^3, polynomial in n of order 2
46  -23011, 17160, -5115, 51975,
47  // R[4]/n^4, polynomial in n of order 1
48  5480, -1353, 13860,
49  // R[5]/n^5, polynomial in n of order 0
50  -668, 5775,
51  }; // count = 27
52 #elif GEOGRAPHICLIB_RHUMBAREA_ORDER == 6
53  static const real coeff[] = {
54  // R[0]/n^0, polynomial in n of order 6
55  128346268, -107884140, 31126095, 354053700, -908107200, 851350500, 0,
56  2554051500LL,
57  // R[1]/n^1, polynomial in n of order 5
58  -114456994, 56868630, 79819740, -240540300, 312161850, -212837625,
59  638512875,
60  // R[2]/n^2, polynomial in n of order 4
61  51304574, 24731070, -78693615, 71621550, -28378350, 212837625,
62  // R[3]/n^3, polynomial in n of order 3
63  1554472, -6282003, 4684680, -1396395, 14189175,
64  // R[4]/n^4, polynomial in n of order 2
65  -4913956, 3205800, -791505, 8108100,
66  // R[5]/n^5, polynomial in n of order 1
67  1092376, -234468, 2027025,
68  // R[6]/n^6, polynomial in n of order 0
69  -313076, 2027025,
70  }; // count = 35
71 #elif GEOGRAPHICLIB_RHUMBAREA_ORDER == 7
72  static const real coeff[] = {
73  // R[0]/n^0, polynomial in n of order 7
74  -317195588, 385038804, -323652420, 93378285, 1062161100, -2724321600LL,
75  2554051500LL, 0, 7662154500LL,
76  // R[1]/n^1, polynomial in n of order 6
77  258618446, -343370982, 170605890, 239459220, -721620900, 936485550,
78  -638512875, 1915538625,
79  // R[2]/n^2, polynomial in n of order 5
80  -248174686, 153913722, 74193210, -236080845, 214864650, -85135050,
81  638512875,
82  // R[3]/n^3, polynomial in n of order 4
83  114450437, 23317080, -94230045, 70270200, -20945925, 212837625,
84  // R[4]/n^4, polynomial in n of order 3
85  15445736, -103193076, 67321800, -16621605, 170270100,
86  // R[5]/n^5, polynomial in n of order 2
87  -27766753, 16385640, -3517020, 30405375,
88  // R[6]/n^6, polynomial in n of order 1
89  4892722, -939228, 6081075,
90  // R[7]/n^7, polynomial in n of order 0
91  -3189007, 14189175,
92  }; // count = 44
93 #elif GEOGRAPHICLIB_RHUMBAREA_ORDER == 8
94  static const real coeff[] = {
95  // R[0]/n^0, polynomial in n of order 8
96  71374704821LL, -161769749880LL, 196369790040LL, -165062734200LL,
97  47622925350LL, 541702161000LL, -1389404016000LL, 1302566265000LL, 0,
98  3907698795000LL,
99  // R[1]/n^1, polynomial in n of order 7
100  -13691187484LL, 65947703730LL, -87559600410LL, 43504501950LL,
101  61062101100LL, -184013329500LL, 238803815250LL, -162820783125LL,
102  488462349375LL,
103  // R[2]/n^2, polynomial in n of order 6
104  30802104839LL, -63284544930LL, 39247999110LL, 18919268550LL,
105  -60200615475LL, 54790485750LL, -21709437750LL, 162820783125LL,
106  // R[3]/n^3, polynomial in n of order 5
107  -8934064508LL, 5836972287LL, 1189171080, -4805732295LL, 3583780200LL,
108  -1068242175, 10854718875LL,
109  // R[4]/n^4, polynomial in n of order 4
110  50072287748LL, 3938662680LL, -26314234380LL, 17167059000LL,
111  -4238509275LL, 43418875500LL,
112  // R[5]/n^5, polynomial in n of order 3
113  359094172, -9912730821LL, 5849673480LL, -1255576140, 10854718875LL,
114  // R[6]/n^6, polynomial in n of order 2
115  -16053944387LL, 8733508770LL, -1676521980, 10854718875LL,
116  // R[7]/n^7, polynomial in n of order 1
117  930092876, -162639357, 723647925,
118  // R[8]/n^8, polynomial in n of order 0
119  -673429061, 1929727800,
120  }; // count = 54
121 #else
122 #error "Bad value for GEOGRAPHICLIB_RHUMBAREA_ORDER"
123 #endif
124  GEOGRAPHICLIB_STATIC_ASSERT(sizeof(coeff) / sizeof(real) ==
125  ((maxpow_ + 1) * (maxpow_ + 4))/2,
126  "Coefficient array size mismatch for Rhumb");
127  real d = 1;
128  int o = 0;
129  for (int l = 0; l <= maxpow_; ++l) {
130  int m = maxpow_ - l;
131  // R[0] is just an integration constant so it cancels when evaluating a
132  // definite integral. So don't bother computing it. It won't be used
133  // when invoking SinCosSeries.
134  if (l)
135  _R[l] = d * Math::polyval(m, coeff + o, _ell._n) / coeff[o + m + 1];
136  o += m + 2;
137  d *= _ell._n;
138  }
139  // Post condition: o == sizeof(alpcoeff) / sizeof(real)
140  }
141 
142  const Rhumb& Rhumb::WGS84() {
143  static const Rhumb
144  wgs84(Constants::WGS84_a(), Constants::WGS84_f(), false);
145  return wgs84;
146  }
147 
148  void Rhumb::GenInverse(real lat1, real lon1, real lat2, real lon2,
149  unsigned outmask,
150  real& s12, real& azi12, real& S12) const {
151  real
152  lon12 = Math::AngDiff(lon1, lon2),
153  psi1 = _ell.IsometricLatitude(lat1),
154  psi2 = _ell.IsometricLatitude(lat2),
155  psi12 = psi2 - psi1,
156  h = Math::hypot(lon12, psi12);
157  if (outmask & AZIMUTH)
158  azi12 = Math::atan2d(lon12, psi12);
159  if (outmask & DISTANCE) {
160  real dmudpsi = DIsometricToRectifying(psi2, psi1);
161  s12 = h * dmudpsi * _ell.QuarterMeridian() / 90;
162  }
163  if (outmask & AREA)
164  S12 = _c2 * lon12 *
165  MeanSinXi(psi2 * Math::degree(), psi1 * Math::degree());
166  }
167 
168  RhumbLine Rhumb::Line(real lat1, real lon1, real azi12) const
169  { return RhumbLine(*this, lat1, lon1, azi12, _exact); }
170 
171  void Rhumb::GenDirect(real lat1, real lon1, real azi12, real s12,
172  unsigned outmask,
173  real& lat2, real& lon2, real& S12) const
174  { Line(lat1, lon1, azi12).GenPosition(s12, outmask, lat2, lon2, S12); }
175 
177  const EllipticFunction& ei = _ell._ell;
178  real d = x - y;
179  if (x * y <= 0)
180  return d != 0 ? (ei.E(x) - ei.E(y)) / d : 1;
181  // See DLMF: Eqs (19.11.2) and (19.11.4) letting
182  // theta -> x, phi -> -y, psi -> z
183  //
184  // (E(x) - E(y)) / d = E(z)/d - k2 * sin(x) * sin(y) * sin(z)/d
185  //
186  // tan(z/2) = (sin(x)*Delta(y) - sin(y)*Delta(x)) / (cos(x) + cos(y))
187  // = d * Dsin(x,y) * (sin(x) + sin(y))/(cos(x) + cos(y)) /
188  // (sin(x)*Delta(y) + sin(y)*Delta(x))
189  // = t = d * Dt
190  // sin(z) = 2*t/(1+t^2); cos(z) = (1-t^2)/(1+t^2)
191  // Alt (this only works for |z| <= pi/2 -- however, this conditions holds
192  // if x*y > 0):
193  // sin(z) = d * Dsin(x,y) * (sin(x) + sin(y))/
194  // (sin(x)*cos(y)*Delta(y) + sin(y)*cos(x)*Delta(x))
195  // cos(z) = sqrt((1-sin(z))*(1+sin(z)))
196  real sx = sin(x), sy = sin(y), cx = cos(x), cy = cos(y);
197  real Dt = Dsin(x, y) * (sx + sy) /
198  ((cx + cy) * (sx * ei.Delta(sy, cy) + sy * ei.Delta(sx, cx))),
199  t = d * Dt, Dsz = 2 * Dt / (1 + t*t),
200  sz = d * Dsz, cz = (1 - t) * (1 + t) / (1 + t*t);
201  return ((sz != 0 ? ei.E(sz, cz, ei.Delta(sz, cz)) / sz : 1)
202  - ei.k2() * sx * sy) * Dsz;
203  }
204 
206  real
207  tbetx = _ell._f1 * Math::tand(latx),
208  tbety = _ell._f1 * Math::tand(laty);
209  return (Math::pi()/2) * _ell._b * _ell._f1 * DE(atan(tbetx), atan(tbety))
210  * Dtan(latx, laty) * Datan(tbetx, tbety) / _ell.QuarterMeridian();
211  }
212 
213  Math::real Rhumb::DIsometric(real latx, real laty) const {
214  real
215  phix = latx * Math::degree(), tx = Math::tand(latx),
216  phiy = laty * Math::degree(), ty = Math::tand(laty);
217  return Dasinh(tx, ty) * Dtan(latx, laty)
218  - Deatanhe(sin(phix), sin(phiy)) * Dsin(phix, phiy);
219  }
220 
222  real x, real y, const real c[], int n) {
223  // N.B. n >= 0 and c[] has n+1 elements 0..n, of which c[0] is ignored.
224  //
225  // Use Clenshaw summation to evaluate
226  // m = (g(x) + g(y)) / 2 -- mean value
227  // s = (g(x) - g(y)) / (x - y) -- average slope
228  // where
229  // g(x) = sum(c[j]*SC(2*j*x), j = 1..n)
230  // SC = sinp ? sin : cos
231  // CS = sinp ? cos : sin
232  //
233  // This function returns only s; m is discarded.
234  //
235  // Write
236  // t = [m; s]
237  // t = sum(c[j] * f[j](x,y), j = 1..n)
238  // where
239  // f[j](x,y) = [ (SC(2*j*x)+SC(2*j*y))/2 ]
240  // [ (SC(2*j*x)-SC(2*j*y))/d ]
241  //
242  // = [ cos(j*d)*SC(j*p) ]
243  // [ +/-(2/d)*sin(j*d)*CS(j*p) ]
244  // (+/- = sinp ? + : -) and
245  // p = x+y, d = x-y
246  //
247  // f[j+1](x,y) = A * f[j](x,y) - f[j-1](x,y)
248  //
249  // A = [ 2*cos(p)*cos(d) -sin(p)*sin(d)*d]
250  // [ -4*sin(p)*sin(d)/d 2*cos(p)*cos(d) ]
251  //
252  // Let b[n+1] = b[n+2] = [0 0; 0 0]
253  // b[j] = A * b[j+1] - b[j+2] + c[j] * I for j = n..1
254  // t = (c[0] * I - b[2]) * f[0](x,y) + b[1] * f[1](x,y)
255  // c[0] is not accessed for s = t[2]
256  real p = x + y, d = x - y,
257  cp = cos(p), cd = cos(d),
258  sp = sin(p), sd = d != 0 ? sin(d)/d : 1,
259  m = 2 * cp * cd, s = sp * sd;
260  // 2x2 matrices stored in row-major order
261  const real a[4] = {m, -s * d * d, -4 * s, m};
262  real ba[4] = {0, 0, 0, 0};
263  real bb[4] = {0, 0, 0, 0};
264  real* b1 = ba;
265  real* b2 = bb;
266  if (n > 0) b1[0] = b1[3] = c[n];
267  for (int j = n - 1; j > 0; --j) { // j = n-1 .. 1
268  std::swap(b1, b2);
269  // b1 = A * b2 - b1 + c[j] * I
270  b1[0] = a[0] * b2[0] + a[1] * b2[2] - b1[0] + c[j];
271  b1[1] = a[0] * b2[1] + a[1] * b2[3] - b1[1];
272  b1[2] = a[2] * b2[0] + a[3] * b2[2] - b1[2];
273  b1[3] = a[2] * b2[1] + a[3] * b2[3] - b1[3] + c[j];
274  }
275  // Here are the full expressions for m and s
276  // m = (c[0] - b2[0]) * f01 - b2[1] * f02 + b1[0] * f11 + b1[1] * f12;
277  // s = - b2[2] * f01 + (c[0] - b2[3]) * f02 + b1[2] * f11 + b1[3] * f12;
278  if (sinp) {
279  // real f01 = 0, f02 = 0;
280  real f11 = cd * sp, f12 = 2 * sd * cp;
281  // m = b1[0] * f11 + b1[1] * f12;
282  s = b1[2] * f11 + b1[3] * f12;
283  } else {
284  // real f01 = 1, f02 = 0;
285  real f11 = cd * cp, f12 = - 2 * sd * sp;
286  // m = c[0] - b2[0] + b1[0] * f11 + b1[1] * f12;
287  s = - b2[2] + b1[2] * f11 + b1[3] * f12;
288  }
289  return s;
290  }
291 
293  return 1 + SinCosSeries(true, chix, chiy,
295  }
296 
298  return 1 - SinCosSeries(true, mux, muy,
300  }
301 
303  if (_exact) {
304  real
305  latx = _ell.InverseIsometricLatitude(psix),
306  laty = _ell.InverseIsometricLatitude(psiy);
307  return DRectifying(latx, laty) / DIsometric(latx, laty);
308  } else {
309  psix *= Math::degree();
310  psiy *= Math::degree();
311  return DConformalToRectifying(gd(psix), gd(psiy)) * Dgd(psix, psiy);
312  }
313  }
314 
316  real
319  return _exact ?
320  DIsometric(latx, laty) / DRectifying(latx, laty) :
322  Math::taupf(Math::tand(laty), _ell._es)) *
323  DRectifyingToConformal(mux, muy);
324  }
325 
326  Math::real Rhumb::MeanSinXi(real psix, real psiy) const {
327  return Dlog(cosh(psix), cosh(psiy)) * Dcosh(psix, psiy)
328  + SinCosSeries(false, gd(psix), gd(psiy), _R, maxpow_) * Dgd(psix, psiy);
329  }
330 
331  RhumbLine::RhumbLine(const Rhumb& rh, real lat1, real lon1, real azi12,
332  bool exact)
333  : _rh(rh)
334  , _exact(exact)
335  , _lat1(Math::LatFix(lat1))
336  , _lon1(lon1)
337  , _azi12(Math::AngNormalize(azi12))
338  {
339  real alp12 = _azi12 * Math::degree();
340  _salp = _azi12 == -180 ? 0 : sin(alp12);
341  _calp = abs(_azi12) == 90 ? 0 : cos(alp12);
344  _r1 = _rh._ell.CircleRadius(lat1);
345  }
346 
347  void RhumbLine::GenPosition(real s12, unsigned outmask,
348  real& lat2, real& lon2, real& S12) const {
349  real
350  mu12 = s12 * _calp * 90 / _rh._ell.QuarterMeridian(),
351  mu2 = _mu1 + mu12;
352  real psi2, lat2x, lon2x;
353  if (abs(mu2) <= 90) {
354  if (_calp != 0) {
355  lat2x = _rh._ell.InverseRectifyingLatitude(mu2);
356  real psi12 = _rh.DRectifyingToIsometric( mu2 * Math::degree(),
357  _mu1 * Math::degree()) * mu12;
358  lon2x = _salp * psi12 / _calp;
359  psi2 = _psi1 + psi12;
360  } else {
361  lat2x = _lat1;
362  lon2x = _salp * s12 / (_r1 * Math::degree());
363  psi2 = _psi1;
364  }
365  if (outmask & AREA)
366  S12 = _rh._c2 * lon2x *
368  lon2x = outmask & LONG_UNROLL ? _lon1 + lon2x :
370  } else {
371  // Reduce to the interval [-180, 180)
372  mu2 = Math::AngNormalize(mu2);
373  // Deal with points on the anti-meridian
374  if (abs(mu2) > 90) mu2 = Math::AngNormalize(180 - mu2);
375  lat2x = _rh._ell.InverseRectifyingLatitude(mu2);
376  lon2x = Math::NaN();
377  if (outmask & AREA)
378  S12 = Math::NaN();
379  }
380  if (outmask & LATITUDE) lat2 = lat2x;
381  if (outmask & LONGITUDE) lon2 = lon2x;
382  }
383 
384 } // namespace GeographicLib
static T AngNormalize(T x)
Definition: Math.hpp:440
Matrix3f m
static T NaN()
Definition: Math.hpp:830
static real Dasinh(real x, real y)
Definition: Rhumb.hpp:126
static T pi()
Definition: Math.hpp:202
real Deatanhe(real x, real y) const
Definition: Rhumb.hpp:142
RhumbLine Line(real lat1, real lon1, real azi12) const
Definition: src/Rhumb.cpp:168
static real Dgd(real x, real y)
Definition: Rhumb.hpp:133
Jet< T, N > cos(const Jet< T, N > &f)
Definition: jet.h:426
static real SinCosSeries(bool sinp, real x, real y, const real c[], int n)
Definition: src/Rhumb.cpp:221
Scalar * y
static real Dtan(real x, real y)
Definition: Rhumb.hpp:97
real DRectifyingToIsometric(real mux, real muy) const
Definition: src/Rhumb.cpp:315
Math::real IsometricLatitude(real phi) const
static real Dcosh(real x, real y)
Definition: Rhumb.hpp:121
const Math::real * RectifyingToConformalCoeffs() const
Definition: Ellipsoid.hpp:53
Math::real InverseRectifyingLatitude(real mu) const
int n
Scalar Scalar * c
Definition: benchVecAdd.cpp:17
Vector2 b2(4, -5)
Math::real CircleRadius(real phi) const
Jet< T, N > sin(const Jet< T, N > &f)
Definition: jet.h:439
const double cx
Mathematical functions needed by GeographicLib.
Definition: Math.hpp:102
Ellipsoid _ell
Definition: Rhumb.hpp:71
static real Dlog(real x, real y)
Definition: Rhumb.hpp:92
Definition: BFloat16.h:88
Rhumb(real a, real f, bool exact=true)
Definition: src/Rhumb.cpp:18
static T AngDiff(T x, T y, T &e)
Definition: Math.hpp:486
Header for GeographicLib::Rhumb and GeographicLib::RhumbLine classes.
Elliptic integrals and functions.
Math::real QuarterMeridian() const
static real Dsin(real x, real y)
Definition: Rhumb.hpp:111
void GenDirect(real lat1, real lon1, real azi12, bool, real s12, unsigned outmask, real &lat2, real &lon2, real &, real &, real &, real &, real &, real &S12) const
Definition: Rhumb.hpp:172
real MeanSinXi(real psi1, real psi2) const
Definition: src/Rhumb.cpp:326
EIGEN_DEVICE_FUNC const AtanReturnType atan() const
RhumbLine(const Rhumb &rh, real lat1, real lon1, real azi12, bool exact)
Definition: src/Rhumb.cpp:331
friend class RhumbLine
Definition: Rhumb.hpp:69
static const Line3 l(Rot3(), 1, 1)
EllipticFunction _ell
Definition: Ellipsoid.hpp:46
static T hypot(T x, T y)
Definition: Math.hpp:243
static const Rhumb & WGS84()
Definition: src/Rhumb.cpp:142
const Rhumb & _rh
Definition: Rhumb.hpp:441
static real gd(real x)
Definition: Rhumb.hpp:78
static T atan2d(T y, T x)
Definition: Math.hpp:691
static T polyval(int N, const T p[], T x)
Definition: Math.hpp:425
static real Datan(real x, real y)
Definition: Rhumb.hpp:104
Definition: main.h:100
Point2(* f)(const Point3 &, OptionalJacobian< 2, 3 >)
Namespace for GeographicLib.
RealScalar s
real DRectifying(real latx, real laty) const
Definition: src/Rhumb.cpp:205
real DConformalToRectifying(real chix, real chiy) const
Definition: src/Rhumb.cpp:292
Math::real InverseIsometricLatitude(real psi) const
static T degree()
Definition: Math.hpp:216
Math::real RectifyingLatitude(real phi) const
void swap(GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &a, GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &b)
static real Dgdinv(real x, real y)
Definition: Rhumb.hpp:138
static T tand(T x)
Definition: Math.hpp:671
const double h
static const int tm_maxord
Definition: Rhumb.hpp:74
static const int maxpow_
Definition: Rhumb.hpp:75
Math::real Delta(real sn, real cn) const
const double cy
Solve of the direct and inverse rhumb problems.
Definition: Rhumb.hpp:66
void GenInverse(real lat1, real lon1, real lat2, real lon2, unsigned outmask, real &s12, real &azi12, real &, real &, real &, real &, real &S12) const
Definition: Rhumb.hpp:178
real DIsometricToRectifying(real psix, real psiy) const
Definition: src/Rhumb.cpp:302
float * p
real _R[maxpow_+1]
Definition: Rhumb.hpp:77
Find a sequence of points on a single rhumb line.
Definition: Rhumb.hpp:437
real DE(real x, real y) const
Definition: src/Rhumb.cpp:176
EIGEN_DEVICE_FUNC const CoshReturnType cosh() const
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy x
#define abs(x)
Definition: datatypes.h:17
real DRectifyingToConformal(real mux, real muy) const
Definition: src/Rhumb.cpp:297
std::ptrdiff_t j
void GenPosition(real s12, unsigned outmask, real &lat2, real &lon2, real &S12) const
Definition: src/Rhumb.cpp:347
const Math::real * ConformalToRectifyingCoeffs() const
Definition: Ellipsoid.hpp:52
Point2 t(10, 10)
real DIsometric(real latx, real laty) const
Definition: src/Rhumb.cpp:213
static T taupf(T tau, T es)
Definition: Math.cpp:25
Vector2 b1(2, -1)


gtsam
Author(s):
autogenerated on Tue Jul 4 2023 02:35:34