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
Math::real InverseRectifyingLatitude(real mu) const
Math::real IsometricLatitude(real phi) const
static real Dasinh(real x, real y)
Definition: Rhumb.hpp:126
static T pi()
Definition: Math.hpp:202
static real Dgd(real x, real y)
Definition: Rhumb.hpp:133
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 DRectifyingToConformal(real mux, real muy) const
Definition: src/Rhumb.cpp:297
real DRectifyingToIsometric(real mux, real muy) const
Definition: src/Rhumb.cpp:315
real DRectifying(real latx, real laty) const
Definition: src/Rhumb.cpp:205
real DIsometricToRectifying(real psix, real psiy) const
Definition: src/Rhumb.cpp:302
static real Dcosh(real x, real y)
Definition: Rhumb.hpp:121
int n
Scalar Scalar * c
Definition: benchVecAdd.cpp:17
EIGEN_DEVICE_FUNC const CoshReturnType cosh() const
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: Half.h:150
Rhumb(real a, real f, bool exact=true)
Definition: src/Rhumb.cpp:18
void GenPosition(real s12, unsigned outmask, real &lat2, real &lon2, real &S12) const
Definition: src/Rhumb.cpp:347
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 Delta(real sn, real cn) const
static real Dsin(real x, real y)
Definition: Rhumb.hpp:111
real MeanSinXi(real psi1, real psi2) const
Definition: src/Rhumb.cpp:326
Array33i a
real DE(real x, real y) const
Definition: src/Rhumb.cpp:176
RhumbLine(const Rhumb &rh, real lat1, real lon1, real azi12, bool exact)
Definition: src/Rhumb.cpp:331
EIGEN_DEVICE_FUNC const CosReturnType cos() const
friend class RhumbLine
Definition: Rhumb.hpp:69
static const Line3 l(Rot3(), 1, 1)
Math::real RectifyingLatitude(real phi) const
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
RhumbLine Line(real lat1, real lon1, real azi12) const
Definition: src/Rhumb.cpp:168
static real gd(real x)
Definition: Rhumb.hpp:78
Vector2 b2(4,-5)
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
EIGEN_DEVICE_FUNC const AtanReturnType atan() const
static real Datan(real x, real y)
Definition: Rhumb.hpp:104
Point2(* f)(const Point3 &, OptionalJacobian< 2, 3 >)
Namespace for GeographicLib.
RealScalar s
real DConformalToRectifying(real chix, real chiy) const
Definition: src/Rhumb.cpp:292
Math::real QuarterMeridian() const
static T degree()
Definition: Math.hpp:216
real Deatanhe(real x, real y) const
Definition: Rhumb.hpp:142
Math::real InverseIsometricLatitude(real psi) const
Vector2 b1(2,-1)
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
const double cy
Solve of the direct and inverse rhumb problems.
Definition: Rhumb.hpp:66
float * p
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 _R[maxpow_+1]
Definition: Rhumb.hpp:77
real DIsometric(real latx, real laty) const
Definition: src/Rhumb.cpp:213
Math::real CircleRadius(real phi) const
Find a sequence of points on a single rhumb line.
Definition: Rhumb.hpp:437
EIGEN_DEVICE_FUNC const SinReturnType sin() const
const Math::real * RectifyingToConformalCoeffs() const
Definition: Ellipsoid.hpp:53
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
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
const Math::real * ConformalToRectifyingCoeffs() const
Definition: Ellipsoid.hpp:52
Math::real real
Definition: Rhumb.hpp:68
void swap(mpfr::mpreal &x, mpfr::mpreal &y)
Definition: mpreal.h:2986
std::ptrdiff_t j
Point2 t(10, 10)
static T taupf(T tau, T es)
Definition: Math.cpp:25


gtsam
Author(s):
autogenerated on Sat May 8 2021 02:43:53