geographiclib 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +12 -0
  3. data/LICENSE +24 -0
  4. data/ext/geographiclib/Accumulator.cpp +23 -0
  5. data/ext/geographiclib/AlbersEqualArea.cpp +445 -0
  6. data/ext/geographiclib/AzimuthalEquidistant.cpp +41 -0
  7. data/ext/geographiclib/CassiniSoldner.cpp +89 -0
  8. data/ext/geographiclib/CircularEngine.cpp +96 -0
  9. data/ext/geographiclib/DMS.cpp +381 -0
  10. data/ext/geographiclib/Ellipsoid.cpp +125 -0
  11. data/ext/geographiclib/EllipticFunction.cpp +512 -0
  12. data/ext/geographiclib/GARS.cpp +122 -0
  13. data/ext/geographiclib/GeoCoords.cpp +175 -0
  14. data/ext/geographiclib/Geocentric.cpp +172 -0
  15. data/ext/geographiclib/Geodesic.cpp +1908 -0
  16. data/ext/geographiclib/GeodesicExact.cpp +927 -0
  17. data/ext/geographiclib/GeodesicExactC4.cpp +7879 -0
  18. data/ext/geographiclib/GeodesicLine.cpp +321 -0
  19. data/ext/geographiclib/GeodesicLineExact.cpp +289 -0
  20. data/ext/geographiclib/GeographicLib/Accumulator.hpp +184 -0
  21. data/ext/geographiclib/GeographicLib/AlbersEqualArea.hpp +312 -0
  22. data/ext/geographiclib/GeographicLib/AzimuthalEquidistant.hpp +139 -0
  23. data/ext/geographiclib/GeographicLib/CassiniSoldner.hpp +204 -0
  24. data/ext/geographiclib/GeographicLib/CircularEngine.hpp +195 -0
  25. data/ext/geographiclib/GeographicLib/Config.h +12 -0
  26. data/ext/geographiclib/GeographicLib/Constants.hpp +387 -0
  27. data/ext/geographiclib/GeographicLib/DMS.hpp +370 -0
  28. data/ext/geographiclib/GeographicLib/Ellipsoid.hpp +534 -0
  29. data/ext/geographiclib/GeographicLib/EllipticFunction.hpp +692 -0
  30. data/ext/geographiclib/GeographicLib/GARS.hpp +143 -0
  31. data/ext/geographiclib/GeographicLib/GeoCoords.hpp +544 -0
  32. data/ext/geographiclib/GeographicLib/Geocentric.hpp +267 -0
  33. data/ext/geographiclib/GeographicLib/Geodesic.hpp +970 -0
  34. data/ext/geographiclib/GeographicLib/GeodesicExact.hpp +862 -0
  35. data/ext/geographiclib/GeographicLib/GeodesicLine.hpp +701 -0
  36. data/ext/geographiclib/GeographicLib/GeodesicLineExact.hpp +667 -0
  37. data/ext/geographiclib/GeographicLib/Geohash.hpp +180 -0
  38. data/ext/geographiclib/GeographicLib/Geoid.hpp +472 -0
  39. data/ext/geographiclib/GeographicLib/Georef.hpp +160 -0
  40. data/ext/geographiclib/GeographicLib/Gnomonic.hpp +206 -0
  41. data/ext/geographiclib/GeographicLib/GravityCircle.hpp +301 -0
  42. data/ext/geographiclib/GeographicLib/GravityModel.hpp +520 -0
  43. data/ext/geographiclib/GeographicLib/LambertConformalConic.hpp +313 -0
  44. data/ext/geographiclib/GeographicLib/LocalCartesian.hpp +236 -0
  45. data/ext/geographiclib/GeographicLib/MGRS.hpp +355 -0
  46. data/ext/geographiclib/GeographicLib/MagneticCircle.hpp +178 -0
  47. data/ext/geographiclib/GeographicLib/MagneticModel.hpp +347 -0
  48. data/ext/geographiclib/GeographicLib/Math.hpp +920 -0
  49. data/ext/geographiclib/GeographicLib/NormalGravity.hpp +350 -0
  50. data/ext/geographiclib/GeographicLib/OSGB.hpp +249 -0
  51. data/ext/geographiclib/GeographicLib/PolarStereographic.hpp +150 -0
  52. data/ext/geographiclib/GeographicLib/PolygonArea.hpp +288 -0
  53. data/ext/geographiclib/GeographicLib/Rhumb.hpp +589 -0
  54. data/ext/geographiclib/GeographicLib/SphericalEngine.hpp +376 -0
  55. data/ext/geographiclib/GeographicLib/SphericalHarmonic.hpp +354 -0
  56. data/ext/geographiclib/GeographicLib/SphericalHarmonic1.hpp +281 -0
  57. data/ext/geographiclib/GeographicLib/SphericalHarmonic2.hpp +315 -0
  58. data/ext/geographiclib/GeographicLib/TransverseMercator.hpp +196 -0
  59. data/ext/geographiclib/GeographicLib/TransverseMercatorExact.hpp +254 -0
  60. data/ext/geographiclib/GeographicLib/UTMUPS.hpp +421 -0
  61. data/ext/geographiclib/GeographicLib/Utility.hpp +612 -0
  62. data/ext/geographiclib/Geohash.cpp +102 -0
  63. data/ext/geographiclib/Geoid.cpp +509 -0
  64. data/ext/geographiclib/Georef.cpp +135 -0
  65. data/ext/geographiclib/Gnomonic.cpp +85 -0
  66. data/ext/geographiclib/GravityCircle.cpp +129 -0
  67. data/ext/geographiclib/GravityModel.cpp +360 -0
  68. data/ext/geographiclib/LambertConformalConic.cpp +456 -0
  69. data/ext/geographiclib/LocalCartesian.cpp +62 -0
  70. data/ext/geographiclib/MGRS.cpp +461 -0
  71. data/ext/geographiclib/MagneticCircle.cpp +52 -0
  72. data/ext/geographiclib/MagneticModel.cpp +269 -0
  73. data/ext/geographiclib/Math.cpp +63 -0
  74. data/ext/geographiclib/NormalGravity.cpp +262 -0
  75. data/ext/geographiclib/OSGB.cpp +167 -0
  76. data/ext/geographiclib/PolarStereographic.cpp +108 -0
  77. data/ext/geographiclib/PolygonArea.cpp +204 -0
  78. data/ext/geographiclib/Rhumb.cpp +383 -0
  79. data/ext/geographiclib/SphericalEngine.cpp +477 -0
  80. data/ext/geographiclib/TransverseMercator.cpp +603 -0
  81. data/ext/geographiclib/TransverseMercatorExact.cpp +464 -0
  82. data/ext/geographiclib/UTMUPS.cpp +296 -0
  83. data/ext/geographiclib/Utility.cpp +61 -0
  84. data/ext/geographiclib/extconf.rb +3 -0
  85. data/ext/geographiclib/geographiclib.cpp +62 -0
  86. data/lib/geographiclib.rb +20 -0
  87. metadata +140 -0
@@ -0,0 +1,383 @@
1
+ /**
2
+ * \file Rhumb.cpp
3
+ * \brief Implementation for GeographicLib::Rhumb and GeographicLib::RhumbLine
4
+ * classes
5
+ *
6
+ * Copyright (c) Charles Karney (2014-2015) <charles@karney.com> and licensed
7
+ * under the MIT/X11 License. For more information, see
8
+ * http://geographiclib.sourceforge.net/
9
+ **********************************************************************/
10
+
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 wgs84(Constants::WGS84_a(), Constants::WGS84_f(), false);
144
+ return wgs84;
145
+ }
146
+
147
+ void Rhumb::GenInverse(real lat1, real lon1, real lat2, real lon2,
148
+ unsigned outmask,
149
+ real& s12, real& azi12, real& S12) const {
150
+ real
151
+ lon12 = Math::AngDiff(lon1, lon2),
152
+ psi1 = _ell.IsometricLatitude(lat1),
153
+ psi2 = _ell.IsometricLatitude(lat2),
154
+ psi12 = psi2 - psi1,
155
+ h = Math::hypot(lon12, psi12);
156
+ if (outmask & AZIMUTH)
157
+ azi12 = Math::atan2d(lon12, psi12);
158
+ if (outmask & DISTANCE) {
159
+ real dmudpsi = DIsometricToRectifying(psi2, psi1);
160
+ s12 = h * dmudpsi * _ell.QuarterMeridian() / 90;
161
+ }
162
+ if (outmask & AREA)
163
+ S12 = _c2 * lon12 *
164
+ MeanSinXi(psi2 * Math::degree(), psi1 * Math::degree());
165
+ }
166
+
167
+ RhumbLine Rhumb::Line(real lat1, real lon1, real azi12) const
168
+ { return RhumbLine(*this, lat1, lon1, azi12, _exact); }
169
+
170
+ void Rhumb::GenDirect(real lat1, real lon1, real azi12, real s12,
171
+ unsigned outmask,
172
+ real& lat2, real& lon2, real& S12) const
173
+ { Line(lat1, lon1, azi12).GenPosition(s12, outmask, lat2, lon2, S12); }
174
+
175
+ Math::real Rhumb::DE(real x, real y) const {
176
+ const EllipticFunction& ei = _ell._ell;
177
+ real d = x - y;
178
+ if (x * y <= 0)
179
+ return d ? (ei.E(x) - ei.E(y)) / d : 1;
180
+ // See DLMF: Eqs (19.11.2) and (19.11.4) letting
181
+ // theta -> x, phi -> -y, psi -> z
182
+ //
183
+ // (E(x) - E(y)) / d = E(z)/d - k2 * sin(x) * sin(y) * sin(z)/d
184
+ //
185
+ // tan(z/2) = (sin(x)*Delta(y) - sin(y)*Delta(x)) / (cos(x) + cos(y))
186
+ // = d * Dsin(x,y) * (sin(x) + sin(y))/(cos(x) + cos(y)) /
187
+ // (sin(x)*Delta(y) + sin(y)*Delta(x))
188
+ // = t = d * Dt
189
+ // sin(z) = 2*t/(1+t^2); cos(z) = (1-t^2)/(1+t^2)
190
+ // Alt (this only works for |z| <= pi/2 -- however, this conditions holds
191
+ // if x*y > 0):
192
+ // sin(z) = d * Dsin(x,y) * (sin(x) + sin(y))/
193
+ // (sin(x)*cos(y)*Delta(y) + sin(y)*cos(x)*Delta(x))
194
+ // cos(z) = sqrt((1-sin(z))*(1+sin(z)))
195
+ real sx = sin(x), sy = sin(y), cx = cos(x), cy = cos(y);
196
+ real Dt = Dsin(x, y) * (sx + sy) /
197
+ ((cx + cy) * (sx * ei.Delta(sy, cy) + sy * ei.Delta(sx, cx))),
198
+ t = d * Dt, Dsz = 2 * Dt / (1 + t*t),
199
+ sz = d * Dsz, cz = (1 - t) * (1 + t) / (1 + t*t);
200
+ return ((sz ? ei.E(sz, cz, ei.Delta(sz, cz)) / sz : 1)
201
+ - ei.k2() * sx * sy) * Dsz;
202
+ }
203
+
204
+ Math::real Rhumb::DRectifying(real latx, real laty) const {
205
+ real
206
+ tbetx = _ell._f1 * Math::tand(latx),
207
+ tbety = _ell._f1 * Math::tand(laty);
208
+ return (Math::pi()/2) * _ell._b * _ell._f1 * DE(atan(tbetx), atan(tbety))
209
+ * Dtan(latx, laty) * Datan(tbetx, tbety) / _ell.QuarterMeridian();
210
+ }
211
+
212
+ Math::real Rhumb::DIsometric(real latx, real laty) const {
213
+ real
214
+ phix = latx * Math::degree(), tx = Math::tand(latx),
215
+ phiy = laty * Math::degree(), ty = Math::tand(laty);
216
+ return Dasinh(tx, ty) * Dtan(latx, laty)
217
+ - Deatanhe(sin(phix), sin(phiy)) * Dsin(phix, phiy);
218
+ }
219
+
220
+ Math::real Rhumb::SinCosSeries(bool sinp,
221
+ real x, real y, const real c[], int n) {
222
+ // N.B. n >= 0 and c[] has n+1 elements 0..n, of which c[0] is ignored.
223
+ //
224
+ // Use Clenshaw summation to evaluate
225
+ // m = (g(x) + g(y)) / 2 -- mean value
226
+ // s = (g(x) - g(y)) / (x - y) -- average slope
227
+ // where
228
+ // g(x) = sum(c[j]*SC(2*j*x), j = 1..n)
229
+ // SC = sinp ? sin : cos
230
+ // CS = sinp ? cos : sin
231
+ //
232
+ // This function returns only s; m is discarded.
233
+ //
234
+ // Write
235
+ // t = [m; s]
236
+ // t = sum(c[j] * f[j](x,y), j = 1..n)
237
+ // where
238
+ // f[j](x,y) = [ (SC(2*j*x)+SC(2*j*y))/2 ]
239
+ // [ (SC(2*j*x)-SC(2*j*y))/d ]
240
+ //
241
+ // = [ cos(j*d)*SC(j*p) ]
242
+ // [ +/-(2/d)*sin(j*d)*CS(j*p) ]
243
+ // (+/- = sinp ? + : -) and
244
+ // p = x+y, d = x-y
245
+ //
246
+ // f[j+1](x,y) = A * f[j](x,y) - f[j-1](x,y)
247
+ //
248
+ // A = [ 2*cos(p)*cos(d) -sin(p)*sin(d)*d]
249
+ // [ -4*sin(p)*sin(d)/d 2*cos(p)*cos(d) ]
250
+ //
251
+ // Let b[n+1] = b[n+2] = [0 0; 0 0]
252
+ // b[j] = A * b[j+1] - b[j+2] + c[j] * I for j = n..1
253
+ // t = (c[0] * I - b[2]) * f[0](x,y) + b[1] * f[1](x,y)
254
+ // c[0] is not accessed for s = t[2]
255
+ real p = x + y, d = x - y,
256
+ cp = cos(p), cd = cos(d),
257
+ sp = sin(p), sd = d ? sin(d)/d : 1,
258
+ m = 2 * cp * cd, s = sp * sd;
259
+ // 2x2 matrices stored in row-major order
260
+ const real a[4] = {m, -s * d * d, -4 * s, m};
261
+ real ba[4] = {0, 0, 0, 0};
262
+ real bb[4] = {0, 0, 0, 0};
263
+ real* b1 = ba;
264
+ real* b2 = bb;
265
+ if (n > 0) b1[0] = b1[3] = c[n];
266
+ for (int j = n - 1; j > 0; --j) { // j = n-1 .. 1
267
+ std::swap(b1, b2);
268
+ // b1 = A * b2 - b1 + c[j] * I
269
+ b1[0] = a[0] * b2[0] + a[1] * b2[2] - b1[0] + c[j];
270
+ b1[1] = a[0] * b2[1] + a[1] * b2[3] - b1[1];
271
+ b1[2] = a[2] * b2[0] + a[3] * b2[2] - b1[2];
272
+ b1[3] = a[2] * b2[1] + a[3] * b2[3] - b1[3] + c[j];
273
+ }
274
+ // Here are the full expressions for m and s
275
+ // m = (c[0] - b2[0]) * f01 - b2[1] * f02 + b1[0] * f11 + b1[1] * f12;
276
+ // s = - b2[2] * f01 + (c[0] - b2[3]) * f02 + b1[2] * f11 + b1[3] * f12;
277
+ if (sinp) {
278
+ // real f01 = 0, f02 = 0;
279
+ real f11 = cd * sp, f12 = 2 * sd * cp;
280
+ // m = b1[0] * f11 + b1[1] * f12;
281
+ s = b1[2] * f11 + b1[3] * f12;
282
+ } else {
283
+ // real f01 = 1, f02 = 0;
284
+ real f11 = cd * cp, f12 = - 2 * sd * sp;
285
+ // m = c[0] - b2[0] + b1[0] * f11 + b1[1] * f12;
286
+ s = - b2[2] + b1[2] * f11 + b1[3] * f12;
287
+ }
288
+ return s;
289
+ }
290
+
291
+ Math::real Rhumb::DConformalToRectifying(real chix, real chiy) const {
292
+ return 1 + SinCosSeries(true, chix, chiy,
293
+ _ell.ConformalToRectifyingCoeffs(), tm_maxord);
294
+ }
295
+
296
+ Math::real Rhumb::DRectifyingToConformal(real mux, real muy) const {
297
+ return 1 - SinCosSeries(true, mux, muy,
298
+ _ell.RectifyingToConformalCoeffs(), tm_maxord);
299
+ }
300
+
301
+ Math::real Rhumb::DIsometricToRectifying(real psix, real psiy) const {
302
+ if (_exact) {
303
+ real
304
+ latx = _ell.InverseIsometricLatitude(psix),
305
+ laty = _ell.InverseIsometricLatitude(psiy);
306
+ return DRectifying(latx, laty) / DIsometric(latx, laty);
307
+ } else {
308
+ psix *= Math::degree();
309
+ psiy *= Math::degree();
310
+ return DConformalToRectifying(gd(psix), gd(psiy)) * Dgd(psix, psiy);
311
+ }
312
+ }
313
+
314
+ Math::real Rhumb::DRectifyingToIsometric(real mux, real muy) const {
315
+ real
316
+ latx = _ell.InverseRectifyingLatitude(mux/Math::degree()),
317
+ laty = _ell.InverseRectifyingLatitude(muy/Math::degree());
318
+ return _exact ?
319
+ DIsometric(latx, laty) / DRectifying(latx, laty) :
320
+ Dgdinv(Math::taupf(Math::tand(latx), _ell._es),
321
+ Math::taupf(Math::tand(laty), _ell._es)) *
322
+ DRectifyingToConformal(mux, muy);
323
+ }
324
+
325
+ Math::real Rhumb::MeanSinXi(real psix, real psiy) const {
326
+ return Dlog(cosh(psix), cosh(psiy)) * Dcosh(psix, psiy)
327
+ + SinCosSeries(false, gd(psix), gd(psiy), _R, maxpow_) * Dgd(psix, psiy);
328
+ }
329
+
330
+ RhumbLine::RhumbLine(const Rhumb& rh, real lat1, real lon1, real azi12,
331
+ bool exact)
332
+ : _rh(rh)
333
+ , _exact(exact)
334
+ , _lat1(Math::LatFix(lat1))
335
+ , _lon1(lon1)
336
+ , _azi12(Math::AngNormalize(azi12))
337
+ {
338
+ real alp12 = _azi12 * Math::degree();
339
+ _salp = _azi12 == -180 ? 0 : sin(alp12);
340
+ _calp = abs(_azi12) == 90 ? 0 : cos(alp12);
341
+ _mu1 = _rh._ell.RectifyingLatitude(lat1);
342
+ _psi1 = _rh._ell.IsometricLatitude(lat1);
343
+ _r1 = _rh._ell.CircleRadius(lat1);
344
+ }
345
+
346
+ void RhumbLine::GenPosition(real s12, unsigned outmask,
347
+ real& lat2, real& lon2, real& S12) const {
348
+ real
349
+ mu12 = s12 * _calp * 90 / _rh._ell.QuarterMeridian(),
350
+ mu2 = _mu1 + mu12;
351
+ real psi2, lat2x, lon2x;
352
+ if (abs(mu2) <= 90) {
353
+ if (_calp) {
354
+ lat2x = _rh._ell.InverseRectifyingLatitude(mu2);
355
+ real psi12 = _rh.DRectifyingToIsometric( mu2 * Math::degree(),
356
+ _mu1 * Math::degree()) * mu12;
357
+ lon2x = _salp * psi12 / _calp;
358
+ psi2 = _psi1 + psi12;
359
+ } else {
360
+ lat2x = _lat1;
361
+ lon2x = _salp * s12 / (_r1 * Math::degree());
362
+ psi2 = _psi1;
363
+ }
364
+ if (outmask & AREA)
365
+ S12 = _rh._c2 * lon2x *
366
+ _rh.MeanSinXi(_psi1 * Math::degree(), psi2 * Math::degree());
367
+ lon2x = outmask & LONG_UNROLL ? _lon1 + lon2x :
368
+ Math::AngNormalize(Math::AngNormalize(_lon1) + lon2x);
369
+ } else {
370
+ // Reduce to the interval [-180, 180)
371
+ mu2 = Math::AngNormalize(mu2);
372
+ // Deal with points on the anti-meridian
373
+ if (abs(mu2) > 90) mu2 = Math::AngNormalize(180 - mu2);
374
+ lat2x = _rh._ell.InverseRectifyingLatitude(mu2);
375
+ lon2x = Math::NaN();
376
+ if (outmask & AREA)
377
+ S12 = Math::NaN();
378
+ }
379
+ if (outmask & LATITUDE) lat2 = lat2x;
380
+ if (outmask & LONGITUDE) lon2 = lon2x;
381
+ }
382
+
383
+ } // namespace GeographicLib
@@ -0,0 +1,477 @@
1
+ /**
2
+ * \file SphericalEngine.cpp
3
+ * \brief Implementation for GeographicLib::SphericalEngine class
4
+ *
5
+ * Copyright (c) Charles Karney (2011) <charles@karney.com> and licensed under
6
+ * the MIT/X11 License. For more information, see
7
+ * http://geographiclib.sourceforge.net/
8
+ *
9
+ * The general sum is\verbatim
10
+ V(r, theta, lambda) = sum(n = 0..N) sum(m = 0..n)
11
+ q^(n+1) * (C[n,m] * cos(m*lambda) + S[n,m] * sin(m*lambda)) * P[n,m](t)
12
+ \endverbatim
13
+ * where <tt>t = cos(theta)</tt>, <tt>q = a/r</tt>. In addition write <tt>u =
14
+ * sin(theta)</tt>.
15
+ *
16
+ * <tt>P[n,m]</tt> is a normalized associated Legendre function of degree
17
+ * <tt>n</tt> and order <tt>m</tt>. Here the formulas are given for full
18
+ * normalized functions (usually denoted <tt>Pbar</tt>).
19
+ *
20
+ * Rewrite outer sum\verbatim
21
+ V(r, theta, lambda) = sum(m = 0..N) * P[m,m](t) * q^(m+1) *
22
+ [Sc[m] * cos(m*lambda) + Ss[m] * sin(m*lambda)]
23
+ \endverbatim
24
+ * where the inner sums are\verbatim
25
+ Sc[m] = sum(n = m..N) q^(n-m) * C[n,m] * P[n,m](t)/P[m,m](t)
26
+ Ss[m] = sum(n = m..N) q^(n-m) * S[n,m] * P[n,m](t)/P[m,m](t)
27
+ \endverbatim
28
+ * Evaluate sums via Clenshaw method. The overall framework is similar to
29
+ * Deakin with the following changes:
30
+ * - Clenshaw summation is used to roll the computation of
31
+ * <tt>cos(m*lambda)</tt> and <tt>sin(m*lambda)</tt> into the evaluation of
32
+ * the outer sum (rather than independently computing an array of these
33
+ * trigonometric terms).
34
+ * - Scale the coefficients to guard against overflow when <tt>N</tt> is large.
35
+ * .
36
+ * For the general framework of Clenshaw, see
37
+ * http://mathworld.wolfram.com/ClenshawRecurrenceFormula.html
38
+ *
39
+ * Let\verbatim
40
+ S = sum(k = 0..N) c[k] * F[k](x)
41
+ F[n+1](x) = alpha[n](x) * F[n](x) + beta[n](x) * F[n-1](x)
42
+ \endverbatim
43
+ * Evaluate <tt>S</tt> with\verbatim
44
+ y[N+2] = y[N+1] = 0
45
+ y[k] = alpha[k] * y[k+1] + beta[k+1] * y[k+2] + c[k]
46
+ S = c[0] * F[0] + y[1] * F[1] + beta[1] * F[0] * y[2]
47
+ \endverbatim
48
+ * \e IF <tt>F[0](x) = 1</tt> and <tt>beta(0,x) = 0</tt>, then <tt>F[1](x) =
49
+ * alpha(0,x)</tt> and we can continue the recursion for <tt>y[k]</tt> until
50
+ * <tt>y[0]</tt>, giving\verbatim
51
+ S = y[0]
52
+ \endverbatim
53
+ *
54
+ * Evaluating the inner sum\verbatim
55
+ l = n-m; n = l+m
56
+ Sc[m] = sum(l = 0..N-m) C[l+m,m] * q^l * P[l+m,m](t)/P[m,m](t)
57
+ F[l] = q^l * P[l+m,m](t)/P[m,m](t)
58
+ \endverbatim
59
+ * Holmes + Featherstone, Eq. (11), give\verbatim
60
+ P[n,m] = sqrt((2*n-1)*(2*n+1)/((n-m)*(n+m))) * t * P[n-1,m] -
61
+ sqrt((2*n+1)*(n+m-1)*(n-m-1)/((n-m)*(n+m)*(2*n-3))) * P[n-2,m]
62
+ \endverbatim
63
+ * thus\verbatim
64
+ alpha[l] = t * q * sqrt(((2*n+1)*(2*n+3))/
65
+ ((n-m+1)*(n+m+1)))
66
+ beta[l+1] = - q^2 * sqrt(((n-m+1)*(n+m+1)*(2*n+5))/
67
+ ((n-m+2)*(n+m+2)*(2*n+1)))
68
+ \endverbatim
69
+ * In this case, <tt>F[0] = 1</tt> and <tt>beta[0] = 0</tt>, so the <tt>Sc[m]
70
+ * = y[0]</tt>.
71
+ *
72
+ * Evaluating the outer sum\verbatim
73
+ V = sum(m = 0..N) Sc[m] * q^(m+1) * cos(m*lambda) * P[m,m](t)
74
+ + sum(m = 0..N) Ss[m] * q^(m+1) * cos(m*lambda) * P[m,m](t)
75
+ F[m] = q^(m+1) * cos(m*lambda) * P[m,m](t) [or sin(m*lambda)]
76
+ \endverbatim
77
+ * Holmes + Featherstone, Eq. (13), give\verbatim
78
+ P[m,m] = u * sqrt((2*m+1)/((m>1?2:1)*m)) * P[m-1,m-1]
79
+ \endverbatim
80
+ * also, we have\verbatim
81
+ cos((m+1)*lambda) = 2*cos(lambda)*cos(m*lambda) - cos((m-1)*lambda)
82
+ \endverbatim
83
+ * thus\verbatim
84
+ alpha[m] = 2*cos(lambda) * sqrt((2*m+3)/(2*(m+1))) * u * q
85
+ = cos(lambda) * sqrt( 2*(2*m+3)/(m+1) ) * u * q
86
+ beta[m+1] = -sqrt((2*m+3)*(2*m+5)/(4*(m+1)*(m+2))) * u^2 * q^2
87
+ * (m == 0 ? sqrt(2) : 1)
88
+ \endverbatim
89
+ * Thus\verbatim
90
+ F[0] = q [or 0]
91
+ F[1] = cos(lambda) * sqrt(3) * u * q^2 [or sin(lambda)]
92
+ beta[1] = - sqrt(15/4) * u^2 * q^2
93
+ \endverbatim
94
+ *
95
+ * Here is how the various components of the gradient are computed
96
+ *
97
+ * Differentiate wrt <tt>r</tt>\verbatim
98
+ d q^(n+1) / dr = (-1/r) * (n+1) * q^(n+1)
99
+ \endverbatim
100
+ * so multiply <tt>C[n,m]</tt> by <tt>n+1</tt> in inner sum and multiply the
101
+ * sum by <tt>-1/r</tt>.
102
+ *
103
+ * Differentiate wrt <tt>lambda</tt>\verbatim
104
+ d cos(m*lambda) = -m * sin(m*lambda)
105
+ d sin(m*lambda) = m * cos(m*lambda)
106
+ \endverbatim
107
+ * so multiply terms by <tt>m</tt> in outer sum and swap sine and cosine
108
+ * variables.
109
+ *
110
+ * Differentiate wrt <tt>theta</tt>\verbatim
111
+ dV/dtheta = V' = -u * dV/dt = -u * V'
112
+ \endverbatim
113
+ * here <tt>'</tt> denotes differentiation wrt <tt>theta</tt>.\verbatim
114
+ d/dtheta (Sc[m] * P[m,m](t)) = Sc'[m] * P[m,m](t) + Sc[m] * P'[m,m](t)
115
+ \endverbatim
116
+ * Now <tt>P[m,m](t) = const * u^m</tt>, so <tt>P'[m,m](t) = m * t/u *
117
+ * P[m,m](t)</tt>, thus\verbatim
118
+ d/dtheta (Sc[m] * P[m,m](t)) = (Sc'[m] + m * t/u * Sc[m]) * P[m,m](t)
119
+ \endverbatim
120
+ * Clenshaw recursion for <tt>Sc[m]</tt> reads\verbatim
121
+ y[k] = alpha[k] * y[k+1] + beta[k+1] * y[k+2] + c[k]
122
+ \endverbatim
123
+ * Substituting <tt>alpha[k] = const * t</tt>, <tt>alpha'[k] = -u/t *
124
+ * alpha[k]</tt>, <tt>beta'[k] = c'[k] = 0</tt> gives\verbatim
125
+ y'[k] = alpha[k] * y'[k+1] + beta[k+1] * y'[k+2] - u/t * alpha[k] * y[k+1]
126
+ \endverbatim
127
+ *
128
+ * Finally, given the derivatives of <tt>V</tt>, we can compute the components
129
+ * of the gradient in spherical coordinates and transform the result into
130
+ * cartesian coordinates.
131
+ **********************************************************************/
132
+
133
+ #include <GeographicLib/SphericalEngine.hpp>
134
+ #include <GeographicLib/CircularEngine.hpp>
135
+ #include <GeographicLib/Utility.hpp>
136
+
137
+ #if defined(_MSC_VER)
138
+ // Squelch warnings about constant conditional expressions and potentially
139
+ // uninitialized local variables
140
+ # pragma warning (disable: 4127 4701)
141
+ #endif
142
+
143
+ namespace GeographicLib {
144
+
145
+ using namespace std;
146
+
147
+ const vector<Math::real> SphericalEngine::Z_(0);
148
+ vector<Math::real> SphericalEngine::root_(0);
149
+
150
+ template<bool gradp, SphericalEngine::normalization norm, int L>
151
+ Math::real SphericalEngine::Value(const coeff c[], const real f[],
152
+ real x, real y, real z, real a,
153
+ real& gradx, real& grady, real& gradz)
154
+ {
155
+ GEOGRAPHICLIB_STATIC_ASSERT(L > 0, "L must be positive");
156
+ GEOGRAPHICLIB_STATIC_ASSERT(norm == FULL || norm == SCHMIDT,
157
+ "Unknown normalization");
158
+ int N = c[0].nmx(), M = c[0].mmx();
159
+
160
+ real
161
+ p = Math::hypot(x, y),
162
+ cl = p ? x / p : 1, // cos(lambda); at pole, pick lambda = 0
163
+ sl = p ? y / p : 0, // sin(lambda)
164
+ r = Math::hypot(z, p),
165
+ t = r ? z / r : 0, // cos(theta); at origin, pick theta = pi/2
166
+ u = r ? max(p / r, eps()) : 1, // sin(theta); but avoid the pole
167
+ q = a / r;
168
+ real
169
+ q2 = Math::sq(q),
170
+ uq = u * q,
171
+ uq2 = Math::sq(uq),
172
+ tu = t / u;
173
+ // Initialize outer sum
174
+ real vc = 0, vc2 = 0, vs = 0, vs2 = 0; // v [N + 1], v [N + 2]
175
+ // vr, vt, vl and similar w variable accumulate the sums for the
176
+ // derivatives wrt r, theta, and lambda, respectively.
177
+ real vrc = 0, vrc2 = 0, vrs = 0, vrs2 = 0; // vr[N + 1], vr[N + 2]
178
+ real vtc = 0, vtc2 = 0, vts = 0, vts2 = 0; // vt[N + 1], vt[N + 2]
179
+ real vlc = 0, vlc2 = 0, vls = 0, vls2 = 0; // vl[N + 1], vl[N + 2]
180
+ int k[L];
181
+ for (int m = M; m >= 0; --m) { // m = M .. 0
182
+ // Initialize inner sum
183
+ real wc = 0, wc2 = 0, ws = 0, ws2 = 0; // w [N - m + 1], w [N - m + 2]
184
+ real wrc = 0, wrc2 = 0, wrs = 0, wrs2 = 0; // wr[N - m + 1], wr[N - m + 2]
185
+ real wtc = 0, wtc2 = 0, wts = 0, wts2 = 0; // wt[N - m + 1], wt[N - m + 2]
186
+ for (int l = 0; l < L; ++l)
187
+ k[l] = c[l].index(N, m) + 1;
188
+ for (int n = N; n >= m; --n) { // n = N .. m; l = N - m .. 0
189
+ real w, A, Ax, B, R; // alpha[l], beta[l + 1]
190
+ switch (norm) {
191
+ case FULL:
192
+ w = root_[2 * n + 1] / (root_[n - m + 1] * root_[n + m + 1]);
193
+ Ax = q * w * root_[2 * n + 3];
194
+ A = t * Ax;
195
+ B = - q2 * root_[2 * n + 5] /
196
+ (w * root_[n - m + 2] * root_[n + m + 2]);
197
+ break;
198
+ case SCHMIDT:
199
+ w = root_[n - m + 1] * root_[n + m + 1];
200
+ Ax = q * (2 * n + 1) / w;
201
+ A = t * Ax;
202
+ B = - q2 * w / (root_[n - m + 2] * root_[n + m + 2]);
203
+ break;
204
+ default: break; // To suppress warning message from Visual Studio
205
+ }
206
+ R = c[0].Cv(--k[0]);
207
+ for (int l = 1; l < L; ++l)
208
+ R += c[l].Cv(--k[l], n, m, f[l]);
209
+ R *= scale();
210
+ w = A * wc + B * wc2 + R; wc2 = wc; wc = w;
211
+ if (gradp) {
212
+ w = A * wrc + B * wrc2 + (n + 1) * R; wrc2 = wrc; wrc = w;
213
+ w = A * wtc + B * wtc2 - u*Ax * wc2; wtc2 = wtc; wtc = w;
214
+ }
215
+ if (m) {
216
+ R = c[0].Sv(k[0]);
217
+ for (int l = 1; l < L; ++l)
218
+ R += c[l].Sv(k[l], n, m, f[l]);
219
+ R *= scale();
220
+ w = A * ws + B * ws2 + R; ws2 = ws; ws = w;
221
+ if (gradp) {
222
+ w = A * wrs + B * wrs2 + (n + 1) * R; wrs2 = wrs; wrs = w;
223
+ w = A * wts + B * wts2 - u*Ax * ws2; wts2 = wts; wts = w;
224
+ }
225
+ }
226
+ }
227
+ // Now Sc[m] = wc, Ss[m] = ws
228
+ // Sc'[m] = wtc, Ss'[m] = wtc
229
+ if (m) {
230
+ real v, A, B; // alpha[m], beta[m + 1]
231
+ switch (norm) {
232
+ case FULL:
233
+ v = root_[2] * root_[2 * m + 3] / root_[m + 1];
234
+ A = cl * v * uq;
235
+ B = - v * root_[2 * m + 5] / (root_[8] * root_[m + 2]) * uq2;
236
+ break;
237
+ case SCHMIDT:
238
+ v = root_[2] * root_[2 * m + 1] / root_[m + 1];
239
+ A = cl * v * uq;
240
+ B = - v * root_[2 * m + 3] / (root_[8] * root_[m + 2]) * uq2;
241
+ break;
242
+ default: break; // To suppress warning message from Visual Studio
243
+ }
244
+ v = A * vc + B * vc2 + wc ; vc2 = vc ; vc = v;
245
+ v = A * vs + B * vs2 + ws ; vs2 = vs ; vs = v;
246
+ if (gradp) {
247
+ // Include the terms Sc[m] * P'[m,m](t) and Ss[m] * P'[m,m](t)
248
+ wtc += m * tu * wc; wts += m * tu * ws;
249
+ v = A * vrc + B * vrc2 + wrc; vrc2 = vrc; vrc = v;
250
+ v = A * vrs + B * vrs2 + wrs; vrs2 = vrs; vrs = v;
251
+ v = A * vtc + B * vtc2 + wtc; vtc2 = vtc; vtc = v;
252
+ v = A * vts + B * vts2 + wts; vts2 = vts; vts = v;
253
+ v = A * vlc + B * vlc2 + m*ws; vlc2 = vlc; vlc = v;
254
+ v = A * vls + B * vls2 - m*wc; vls2 = vls; vls = v;
255
+ }
256
+ } else {
257
+ real A, B, qs;
258
+ switch (norm) {
259
+ case FULL:
260
+ A = root_[3] * uq; // F[1]/(q*cl) or F[1]/(q*sl)
261
+ B = - root_[15]/2 * uq2; // beta[1]/q
262
+ break;
263
+ case SCHMIDT:
264
+ A = uq;
265
+ B = - root_[3]/2 * uq2;
266
+ break;
267
+ default: break; // To suppress warning message from Visual Studio
268
+ }
269
+ qs = q / scale();
270
+ vc = qs * (wc + A * (cl * vc + sl * vs ) + B * vc2);
271
+ if (gradp) {
272
+ qs /= r;
273
+ // The components of the gradient in spherical coordinates are
274
+ // r: dV/dr
275
+ // theta: 1/r * dV/dtheta
276
+ // lambda: 1/(r*u) * dV/dlambda
277
+ vrc = - qs * (wrc + A * (cl * vrc + sl * vrs) + B * vrc2);
278
+ vtc = qs * (wtc + A * (cl * vtc + sl * vts) + B * vtc2);
279
+ vlc = qs / u * ( A * (cl * vlc + sl * vls) + B * vlc2);
280
+ }
281
+ }
282
+ }
283
+
284
+ if (gradp) {
285
+ // Rotate into cartesian (geocentric) coordinates
286
+ gradx = cl * (u * vrc + t * vtc) - sl * vlc;
287
+ grady = sl * (u * vrc + t * vtc) + cl * vlc;
288
+ gradz = t * vrc - u * vtc ;
289
+ }
290
+ return vc;
291
+ }
292
+
293
+ template<bool gradp, SphericalEngine::normalization norm, int L>
294
+ CircularEngine SphericalEngine::Circle(const coeff c[], const real f[],
295
+ real p, real z, real a) {
296
+
297
+ GEOGRAPHICLIB_STATIC_ASSERT(L > 0, "L must be positive");
298
+ GEOGRAPHICLIB_STATIC_ASSERT(norm == FULL || norm == SCHMIDT,
299
+ "Unknown normalization");
300
+ int N = c[0].nmx(), M = c[0].mmx();
301
+
302
+ real
303
+ r = Math::hypot(z, p),
304
+ t = r ? z / r : 0, // cos(theta); at origin, pick theta = pi/2
305
+ u = r ? max(p / r, eps()) : 1, // sin(theta); but avoid the pole
306
+ q = a / r;
307
+ real
308
+ q2 = Math::sq(q),
309
+ tu = t / u;
310
+ CircularEngine circ(M, gradp, norm, a, r, u, t);
311
+ int k[L];
312
+ for (int m = M; m >= 0; --m) { // m = M .. 0
313
+ // Initialize inner sum
314
+ real wc = 0, wc2 = 0, ws = 0, ws2 = 0; // w [N - m + 1], w [N - m + 2]
315
+ real wrc = 0, wrc2 = 0, wrs = 0, wrs2 = 0; // wr[N - m + 1], wr[N - m + 2]
316
+ real wtc = 0, wtc2 = 0, wts = 0, wts2 = 0; // wt[N - m + 1], wt[N - m + 2]
317
+ for (int l = 0; l < L; ++l)
318
+ k[l] = c[l].index(N, m) + 1;
319
+ for (int n = N; n >= m; --n) { // n = N .. m; l = N - m .. 0
320
+ real w, A, Ax, B, R; // alpha[l], beta[l + 1]
321
+ switch (norm) {
322
+ case FULL:
323
+ w = root_[2 * n + 1] / (root_[n - m + 1] * root_[n + m + 1]);
324
+ Ax = q * w * root_[2 * n + 3];
325
+ A = t * Ax;
326
+ B = - q2 * root_[2 * n + 5] /
327
+ (w * root_[n - m + 2] * root_[n + m + 2]);
328
+ break;
329
+ case SCHMIDT:
330
+ w = root_[n - m + 1] * root_[n + m + 1];
331
+ Ax = q * (2 * n + 1) / w;
332
+ A = t * Ax;
333
+ B = - q2 * w / (root_[n - m + 2] * root_[n + m + 2]);
334
+ break;
335
+ default: break; // To suppress warning message from Visual Studio
336
+ }
337
+ R = c[0].Cv(--k[0]);
338
+ for (int l = 1; l < L; ++l)
339
+ R += c[l].Cv(--k[l], n, m, f[l]);
340
+ R *= scale();
341
+ w = A * wc + B * wc2 + R; wc2 = wc; wc = w;
342
+ if (gradp) {
343
+ w = A * wrc + B * wrc2 + (n + 1) * R; wrc2 = wrc; wrc = w;
344
+ w = A * wtc + B * wtc2 - u*Ax * wc2; wtc2 = wtc; wtc = w;
345
+ }
346
+ if (m) {
347
+ R = c[0].Sv(k[0]);
348
+ for (int l = 1; l < L; ++l)
349
+ R += c[l].Sv(k[l], n, m, f[l]);
350
+ R *= scale();
351
+ w = A * ws + B * ws2 + R; ws2 = ws; ws = w;
352
+ if (gradp) {
353
+ w = A * wrs + B * wrs2 + (n + 1) * R; wrs2 = wrs; wrs = w;
354
+ w = A * wts + B * wts2 - u*Ax * ws2; wts2 = wts; wts = w;
355
+ }
356
+ }
357
+ }
358
+ if (!gradp)
359
+ circ.SetCoeff(m, wc, ws);
360
+ else {
361
+ // Include the terms Sc[m] * P'[m,m](t) and Ss[m] * P'[m,m](t)
362
+ wtc += m * tu * wc; wts += m * tu * ws;
363
+ circ.SetCoeff(m, wc, ws, wrc, wrs, wtc, wts);
364
+ }
365
+ }
366
+
367
+ return circ;
368
+ }
369
+
370
+ void SphericalEngine::RootTable(int N) {
371
+ // Need square roots up to max(2 * N + 5, 15).
372
+ int L = max(2 * N + 5, 15) + 1, oldL = int(root_.size());
373
+ if (oldL >= L)
374
+ return;
375
+ root_.resize(L);
376
+ for (int l = oldL; l < L; ++l)
377
+ root_[l] = sqrt(real(l));
378
+ }
379
+
380
+ void SphericalEngine::coeff::readcoeffs(std::istream& stream, int& N, int& M,
381
+ std::vector<real>& C,
382
+ std::vector<real>& S) {
383
+ int nm[2];
384
+ Utility::readarray<int, int, false>(stream, nm, 2);
385
+ N = nm[0]; M = nm[1];
386
+ if (!(N >= M && M >= -1 && N * M >= 0))
387
+ // The last condition is that M = -1 implies N = -1 and vice versa.
388
+ throw GeographicErr("Bad degree and order " +
389
+ Utility::str(N) + " " + Utility::str(M));
390
+ C.resize(SphericalEngine::coeff::Csize(N, M));
391
+ Utility::readarray<double, real, false>(stream, C);
392
+ S.resize(SphericalEngine::coeff::Ssize(N, M));
393
+ Utility::readarray<double, real, false>(stream, S);
394
+ return;
395
+ }
396
+
397
+ /// \cond SKIP
398
+ template Math::real GEOGRAPHICLIB_EXPORT
399
+ SphericalEngine::Value<true, SphericalEngine::FULL, 1>
400
+ (const coeff[], const real[], real, real, real, real, real&, real&, real&);
401
+ template Math::real GEOGRAPHICLIB_EXPORT
402
+ SphericalEngine::Value<false, SphericalEngine::FULL, 1>
403
+ (const coeff[], const real[], real, real, real, real, real&, real&, real&);
404
+ template Math::real GEOGRAPHICLIB_EXPORT
405
+ SphericalEngine::Value<true, SphericalEngine::SCHMIDT, 1>
406
+ (const coeff[], const real[], real, real, real, real, real&, real&, real&);
407
+ template Math::real GEOGRAPHICLIB_EXPORT
408
+ SphericalEngine::Value<false, SphericalEngine::SCHMIDT, 1>
409
+ (const coeff[], const real[], real, real, real, real, real&, real&, real&);
410
+
411
+ template Math::real GEOGRAPHICLIB_EXPORT
412
+ SphericalEngine::Value<true, SphericalEngine::FULL, 2>
413
+ (const coeff[], const real[], real, real, real, real, real&, real&, real&);
414
+ template Math::real GEOGRAPHICLIB_EXPORT
415
+ SphericalEngine::Value<false, SphericalEngine::FULL, 2>
416
+ (const coeff[], const real[], real, real, real, real, real&, real&, real&);
417
+ template Math::real GEOGRAPHICLIB_EXPORT
418
+ SphericalEngine::Value<true, SphericalEngine::SCHMIDT, 2>
419
+ (const coeff[], const real[], real, real, real, real, real&, real&, real&);
420
+ template Math::real GEOGRAPHICLIB_EXPORT
421
+ SphericalEngine::Value<false, SphericalEngine::SCHMIDT, 2>
422
+ (const coeff[], const real[], real, real, real, real, real&, real&, real&);
423
+
424
+ template Math::real GEOGRAPHICLIB_EXPORT
425
+ SphericalEngine::Value<true, SphericalEngine::FULL, 3>
426
+ (const coeff[], const real[], real, real, real, real, real&, real&, real&);
427
+ template Math::real GEOGRAPHICLIB_EXPORT
428
+ SphericalEngine::Value<false, SphericalEngine::FULL, 3>
429
+ (const coeff[], const real[], real, real, real, real, real&, real&, real&);
430
+ template Math::real GEOGRAPHICLIB_EXPORT
431
+ SphericalEngine::Value<true, SphericalEngine::SCHMIDT, 3>
432
+ (const coeff[], const real[], real, real, real, real, real&, real&, real&);
433
+ template Math::real GEOGRAPHICLIB_EXPORT
434
+ SphericalEngine::Value<false, SphericalEngine::SCHMIDT, 3>
435
+ (const coeff[], const real[], real, real, real, real, real&, real&, real&);
436
+
437
+ template CircularEngine GEOGRAPHICLIB_EXPORT
438
+ SphericalEngine::Circle<true, SphericalEngine::FULL, 1>
439
+ (const coeff[], const real[], real, real, real);
440
+ template CircularEngine GEOGRAPHICLIB_EXPORT
441
+ SphericalEngine::Circle<false, SphericalEngine::FULL, 1>
442
+ (const coeff[], const real[], real, real, real);
443
+ template CircularEngine GEOGRAPHICLIB_EXPORT
444
+ SphericalEngine::Circle<true, SphericalEngine::SCHMIDT, 1>
445
+ (const coeff[], const real[], real, real, real);
446
+ template CircularEngine GEOGRAPHICLIB_EXPORT
447
+ SphericalEngine::Circle<false, SphericalEngine::SCHMIDT, 1>
448
+ (const coeff[], const real[], real, real, real);
449
+
450
+ template CircularEngine GEOGRAPHICLIB_EXPORT
451
+ SphericalEngine::Circle<true, SphericalEngine::FULL, 2>
452
+ (const coeff[], const real[], real, real, real);
453
+ template CircularEngine GEOGRAPHICLIB_EXPORT
454
+ SphericalEngine::Circle<false, SphericalEngine::FULL, 2>
455
+ (const coeff[], const real[], real, real, real);
456
+ template CircularEngine GEOGRAPHICLIB_EXPORT
457
+ SphericalEngine::Circle<true, SphericalEngine::SCHMIDT, 2>
458
+ (const coeff[], const real[], real, real, real);
459
+ template CircularEngine GEOGRAPHICLIB_EXPORT
460
+ SphericalEngine::Circle<false, SphericalEngine::SCHMIDT, 2>
461
+ (const coeff[], const real[], real, real, real);
462
+
463
+ template CircularEngine GEOGRAPHICLIB_EXPORT
464
+ SphericalEngine::Circle<true, SphericalEngine::FULL, 3>
465
+ (const coeff[], const real[], real, real, real);
466
+ template CircularEngine GEOGRAPHICLIB_EXPORT
467
+ SphericalEngine::Circle<false, SphericalEngine::FULL, 3>
468
+ (const coeff[], const real[], real, real, real);
469
+ template CircularEngine GEOGRAPHICLIB_EXPORT
470
+ SphericalEngine::Circle<true, SphericalEngine::SCHMIDT, 3>
471
+ (const coeff[], const real[], real, real, real);
472
+ template CircularEngine GEOGRAPHICLIB_EXPORT
473
+ SphericalEngine::Circle<false, SphericalEngine::SCHMIDT, 3>
474
+ (const coeff[], const real[], real, real, real);
475
+ /// \endcond
476
+
477
+ } // namespace GeographicLib