geographiclib 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,52 @@
1
+ /**
2
+ * \file MagneticCircle.cpp
3
+ * \brief Implementation for GeographicLib::MagneticCircle class
4
+ *
5
+ * Copyright (c) Charles Karney (2011-2015) <charles@karney.com> and licensed
6
+ * under the MIT/X11 License. For more information, see
7
+ * http://geographiclib.sourceforge.net/
8
+ **********************************************************************/
9
+
10
+ #include <GeographicLib/MagneticCircle.hpp>
11
+ #include <fstream>
12
+ #include <sstream>
13
+ #include <GeographicLib/Geocentric.hpp>
14
+
15
+ namespace GeographicLib {
16
+
17
+ using namespace std;
18
+
19
+ void MagneticCircle::Field(real lon, bool diffp,
20
+ real& Bx, real& By, real& Bz,
21
+ real& Bxt, real& Byt, real& Bzt) const {
22
+ real slam, clam;
23
+ Math::sincosd(lon, slam, clam);
24
+ real M[Geocentric::dim2_];
25
+ Geocentric::Rotation(_sphi, _cphi, slam, clam, M);
26
+ real BX0, BY0, BZ0, BX1, BY1, BZ1; // Components in geocentric basis
27
+ real BXc = 0, BYc = 0, BZc = 0;
28
+ _circ0(slam, clam, BX0, BY0, BZ0);
29
+ _circ1(slam, clam, BX1, BY1, BZ1);
30
+ if (_constterm)
31
+ _circ2(slam, clam, BXc, BYc, BZc);
32
+ if (_interpolate) {
33
+ BX1 = (BX1 - BX0) / _dt0;
34
+ BY1 = (BY1 - BY0) / _dt0;
35
+ BZ1 = (BZ1 - BZ0) / _dt0;
36
+ }
37
+ BX0 += _t1 * BX1 + BXc;
38
+ BY0 += _t1 * BY1 + BYc;
39
+ BZ0 += _t1 * BZ1 + BZc;
40
+ if (diffp) {
41
+ Geocentric::Unrotate(M, BX1, BY1, BZ1, Bxt, Byt, Bzt);
42
+ Bxt *= - _a;
43
+ Byt *= - _a;
44
+ Bzt *= - _a;
45
+ }
46
+ Geocentric::Unrotate(M, BX0, BY0, BZ0, Bx, By, Bz);
47
+ Bx *= - _a;
48
+ By *= - _a;
49
+ Bz *= - _a;
50
+ }
51
+
52
+ } // namespace GeographicLib
@@ -0,0 +1,269 @@
1
+ /**
2
+ * \file MagneticModel.cpp
3
+ * \brief Implementation for GeographicLib::MagneticModel class
4
+ *
5
+ * Copyright (c) Charles Karney (2011-2015) <charles@karney.com> and licensed
6
+ * under the MIT/X11 License. For more information, see
7
+ * http://geographiclib.sourceforge.net/
8
+ **********************************************************************/
9
+
10
+ #include <GeographicLib/MagneticModel.hpp>
11
+ #include <fstream>
12
+ #include <GeographicLib/SphericalEngine.hpp>
13
+ #include <GeographicLib/MagneticCircle.hpp>
14
+ #include <GeographicLib/Utility.hpp>
15
+
16
+ #if !defined(GEOGRAPHICLIB_DATA)
17
+ # if defined(_WIN32)
18
+ # define GEOGRAPHICLIB_DATA "C:/ProgramData/GeographicLib"
19
+ # else
20
+ # define GEOGRAPHICLIB_DATA "/usr/local/share/GeographicLib"
21
+ # endif
22
+ #endif
23
+
24
+ #if !defined(GEOGRAPHICLIB_MAGNETIC_DEFAULT_NAME)
25
+ # define GEOGRAPHICLIB_MAGNETIC_DEFAULT_NAME "wmm2015"
26
+ #endif
27
+
28
+ #if defined(_MSC_VER)
29
+ // Squelch warnings about unsafe use of getenv
30
+ # pragma warning (disable: 4996)
31
+ #endif
32
+
33
+ namespace GeographicLib {
34
+
35
+ using namespace std;
36
+
37
+ MagneticModel::MagneticModel(const std::string& name,const std::string& path,
38
+ const Geocentric& earth)
39
+ : _name(name)
40
+ , _dir(path)
41
+ , _description("NONE")
42
+ , _date("UNKNOWN")
43
+ , _t0(Math::NaN())
44
+ , _dt0(1)
45
+ , _tmin(Math::NaN())
46
+ , _tmax(Math::NaN())
47
+ , _a(Math::NaN())
48
+ , _hmin(Math::NaN())
49
+ , _hmax(Math::NaN())
50
+ , _Nmodels(1)
51
+ , _Nconstants(0)
52
+ , _norm(SphericalHarmonic::SCHMIDT)
53
+ , _earth(earth)
54
+ {
55
+ if (_dir.empty())
56
+ _dir = DefaultMagneticPath();
57
+ ReadMetadata(_name);
58
+ _G.resize(_Nmodels + 1 + _Nconstants);
59
+ _H.resize(_Nmodels + 1 + _Nconstants);
60
+ {
61
+ string coeff = _filename + ".cof";
62
+ ifstream coeffstr(coeff.c_str(), ios::binary);
63
+ if (!coeffstr.good())
64
+ throw GeographicErr("Error opening " + coeff);
65
+ char id[idlength_ + 1];
66
+ coeffstr.read(id, idlength_);
67
+ if (!coeffstr.good())
68
+ throw GeographicErr("No header in " + coeff);
69
+ id[idlength_] = '\0';
70
+ if (_id != string(id))
71
+ throw GeographicErr("ID mismatch: " + _id + " vs " + id);
72
+ for (int i = 0; i < _Nmodels + 1 + _Nconstants; ++i) {
73
+ int N, M;
74
+ SphericalEngine::coeff::readcoeffs(coeffstr, N, M, _G[i], _H[i]);
75
+ if (!(M < 0 || _G[i][0] == 0))
76
+ throw GeographicErr("A degree 0 term is not permitted");
77
+ _harm.push_back(SphericalHarmonic(_G[i], _H[i], N, N, M, _a, _norm));
78
+ }
79
+ int pos = int(coeffstr.tellg());
80
+ coeffstr.seekg(0, ios::end);
81
+ if (pos != coeffstr.tellg())
82
+ throw GeographicErr("Extra data in " + coeff);
83
+ }
84
+ }
85
+
86
+ void MagneticModel::ReadMetadata(const std::string& name) {
87
+ const char* spaces = " \t\n\v\f\r";
88
+ _filename = _dir + "/" + name + ".wmm";
89
+ ifstream metastr(_filename.c_str());
90
+ if (!metastr.good())
91
+ throw GeographicErr("Cannot open " + _filename);
92
+ string line;
93
+ getline(metastr, line);
94
+ if (!(line.size() >= 6 && line.substr(0,5) == "WMMF-"))
95
+ throw GeographicErr(_filename + " does not contain WMMF-n signature");
96
+ string::size_type n = line.find_first_of(spaces, 5);
97
+ if (n != string::npos)
98
+ n -= 5;
99
+ string version = line.substr(5, n);
100
+ if (!(version == "1" || version == "2"))
101
+ throw GeographicErr("Unknown version in " + _filename + ": " + version);
102
+ string key, val;
103
+ while (getline(metastr, line)) {
104
+ if (!Utility::ParseLine(line, key, val))
105
+ continue;
106
+ // Process key words
107
+ if (key == "Name")
108
+ _name = val;
109
+ else if (key == "Description")
110
+ _description = val;
111
+ else if (key == "ReleaseDate")
112
+ _date = val;
113
+ else if (key == "Radius")
114
+ _a = Utility::num<real>(val);
115
+ else if (key == "Type") {
116
+ if (!(val == "Linear" || val == "linear"))
117
+ throw GeographicErr("Only linear models are supported");
118
+ } else if (key == "Epoch")
119
+ _t0 = Utility::num<real>(val);
120
+ else if (key == "DeltaEpoch")
121
+ _dt0 = Utility::num<real>(val);
122
+ else if (key == "NumModels")
123
+ _Nmodels = Utility::num<int>(val);
124
+ else if (key == "NumConstants")
125
+ _Nconstants = Utility::num<int>(val);
126
+ else if (key == "MinTime")
127
+ _tmin = Utility::num<real>(val);
128
+ else if (key == "MaxTime")
129
+ _tmax = Utility::num<real>(val);
130
+ else if (key == "MinHeight")
131
+ _hmin = Utility::num<real>(val);
132
+ else if (key == "MaxHeight")
133
+ _hmax = Utility::num<real>(val);
134
+ else if (key == "Normalization") {
135
+ if (val == "FULL" || val == "Full" || val == "full")
136
+ _norm = SphericalHarmonic::FULL;
137
+ else if (val == "SCHMIDT" || val == "Schmidt" || val == "schmidt")
138
+ _norm = SphericalHarmonic::SCHMIDT;
139
+ else
140
+ throw GeographicErr("Unknown normalization " + val);
141
+ } else if (key == "ByteOrder") {
142
+ if (val == "Big" || val == "big")
143
+ throw GeographicErr("Only little-endian ordering is supported");
144
+ else if (!(val == "Little" || val == "little"))
145
+ throw GeographicErr("Unknown byte ordering " + val);
146
+ } else if (key == "ID")
147
+ _id = val;
148
+ // else unrecognized keywords are skipped
149
+ }
150
+ // Check values
151
+ if (!(Math::isfinite(_a) && _a > 0))
152
+ throw GeographicErr("Reference radius must be positive");
153
+ if (!(_t0 > 0))
154
+ throw GeographicErr("Epoch time not defined");
155
+ if (_tmin >= _tmax)
156
+ throw GeographicErr("Min time exceeds max time");
157
+ if (_hmin >= _hmax)
158
+ throw GeographicErr("Min height exceeds max height");
159
+ if (int(_id.size()) != idlength_)
160
+ throw GeographicErr("Invalid ID");
161
+ if (_Nmodels < 1)
162
+ throw GeographicErr("NumModels must be positive");
163
+ if (!(_Nconstants == 0 || _Nconstants == 1))
164
+ throw GeographicErr("NumConstants must be 0 or 1");
165
+ if (!(_dt0 > 0)) {
166
+ if (_Nmodels > 1)
167
+ throw GeographicErr("DeltaEpoch must be positive");
168
+ else
169
+ _dt0 = 1;
170
+ }
171
+ }
172
+
173
+ void MagneticModel::Field(real t, real lat, real lon, real h, bool diffp,
174
+ real& Bx, real& By, real& Bz,
175
+ real& Bxt, real& Byt, real& Bzt) const {
176
+ t -= _t0;
177
+ int n = max(min(int(floor(t / _dt0)), _Nmodels - 1), 0);
178
+ bool interpolate = n + 1 < _Nmodels;
179
+ t -= n * _dt0;
180
+ real X, Y, Z;
181
+ real M[Geocentric::dim2_];
182
+ _earth.IntForward(lat, lon, h, X, Y, Z, M);
183
+ // Components in geocentric basis
184
+ // initial values to suppress warning
185
+ real BX0 = 0, BY0 = 0, BZ0 = 0, BX1 = 0, BY1 = 0, BZ1 = 0;
186
+ real BXc = 0, BYc = 0, BZc = 0;
187
+ _harm[n](X, Y, Z, BX0, BY0, BZ0);
188
+ _harm[n + 1](X, Y, Z, BX1, BY1, BZ1);
189
+ if (_Nconstants)
190
+ _harm[_Nmodels + 1](X, Y, Z, BXc, BYc, BZc);
191
+ if (interpolate) {
192
+ // Convert to a time derivative
193
+ BX1 = (BX1 - BX0) / _dt0;
194
+ BY1 = (BY1 - BY0) / _dt0;
195
+ BZ1 = (BZ1 - BZ0) / _dt0;
196
+ }
197
+ BX0 += t * BX1 + BXc;
198
+ BY0 += t * BY1 + BYc;
199
+ BZ0 += t * BZ1 + BZc;
200
+ if (diffp) {
201
+ Geocentric::Unrotate(M, BX1, BY1, BZ1, Bxt, Byt, Bzt);
202
+ Bxt *= - _a;
203
+ Byt *= - _a;
204
+ Bzt *= - _a;
205
+ }
206
+ Geocentric::Unrotate(M, BX0, BY0, BZ0, Bx, By, Bz);
207
+ Bx *= - _a;
208
+ By *= - _a;
209
+ Bz *= - _a;
210
+ }
211
+
212
+ MagneticCircle MagneticModel::Circle(real t, real lat, real h) const {
213
+ real t1 = t - _t0;
214
+ int n = max(min(int(floor(t1 / _dt0)), _Nmodels - 1), 0);
215
+ bool interpolate = n + 1 < _Nmodels;
216
+ t1 -= n * _dt0;
217
+ real X, Y, Z, M[Geocentric::dim2_];
218
+ _earth.IntForward(lat, 0, h, X, Y, Z, M);
219
+ // Y = 0, cphi = M[7], sphi = M[8];
220
+
221
+ return (_Nconstants == 0 ?
222
+ MagneticCircle(_a, _earth._f, lat, h, t,
223
+ M[7], M[8], t1, _dt0, interpolate,
224
+ _harm[n].Circle(X, Z, true),
225
+ _harm[n + 1].Circle(X, Z, true)) :
226
+ MagneticCircle(_a, _earth._f, lat, h, t,
227
+ M[7], M[8], t1, _dt0, interpolate,
228
+ _harm[n].Circle(X, Z, true),
229
+ _harm[n + 1].Circle(X, Z, true),
230
+ _harm[_Nmodels + 1].Circle(X, Z, true)));
231
+ }
232
+
233
+ void MagneticModel::FieldComponents(real Bx, real By, real Bz,
234
+ real Bxt, real Byt, real Bzt,
235
+ real& H, real& F, real& D, real& I,
236
+ real& Ht, real& Ft,
237
+ real& Dt, real& It) {
238
+ H = Math::hypot(Bx, By);
239
+ Ht = H ? (Bx * Bxt + By * Byt) / H : Math::hypot(Bxt, Byt);
240
+ D = H ? Math::atan2d(Bx, By) : Math::atan2d(Bxt, Byt);
241
+ Dt = (H ? (By * Bxt - Bx * Byt) / Math::sq(H) : 0) / Math::degree();
242
+ F = Math::hypot(H, Bz);
243
+ Ft = F ? (H * Ht + Bz * Bzt) / F : Math::hypot(Ht, Bzt);
244
+ I = F ? Math::atan2d(-Bz, H) : Math::atan2d(-Bzt, Ht);
245
+ It = (F ? (Bz * Ht - H * Bzt) / Math::sq(F) : 0) / Math::degree();
246
+ }
247
+
248
+ std::string MagneticModel::DefaultMagneticPath() {
249
+ string path;
250
+ char* magneticpath = getenv("GEOGRAPHICLIB_MAGNETIC_PATH");
251
+ if (magneticpath)
252
+ path = string(magneticpath);
253
+ if (!path.empty())
254
+ return path;
255
+ char* datapath = getenv("GEOGRAPHICLIB_DATA");
256
+ if (datapath)
257
+ path = string(datapath);
258
+ return (!path.empty() ? path : string(GEOGRAPHICLIB_DATA)) + "/magnetic";
259
+ }
260
+
261
+ std::string MagneticModel::DefaultMagneticName() {
262
+ string name;
263
+ char* magneticname = getenv("GEOGRAPHICLIB_MAGNETIC_NAME");
264
+ if (magneticname)
265
+ name = string(magneticname);
266
+ return !name.empty() ? name : string(GEOGRAPHICLIB_MAGNETIC_DEFAULT_NAME);
267
+ }
268
+
269
+ } // namespace GeographicLib
@@ -0,0 +1,63 @@
1
+ /**
2
+ * \file Math.cpp
3
+ * \brief Implementation for GeographicLib::Math class
4
+ *
5
+ * Copyright (c) Charles Karney (2015) <charles@karney.com> and licensed
6
+ * under the MIT/X11 License. For more information, see
7
+ * http://geographiclib.sourceforge.net/
8
+ **********************************************************************/
9
+
10
+ #include <GeographicLib/Math.hpp>
11
+
12
+ #if defined(_MSC_VER)
13
+ // Squelch warnings about constant conditional expressions
14
+ # pragma warning (disable: 4127)
15
+ #endif
16
+
17
+ namespace GeographicLib {
18
+
19
+ using namespace std;
20
+
21
+ template<typename T> T Math::eatanhe(T x, T es) {
22
+ return es > T(0) ? es * atanh(es * x) : -es * atan(es * x);
23
+ }
24
+
25
+ template<typename T> T Math::taupf(T tau, T es) {
26
+ T tau1 = hypot(T(1), tau),
27
+ sig = sinh( eatanhe(tau / tau1, es ) );
28
+ return hypot(T(1), sig) * tau - sig * tau1;
29
+ }
30
+
31
+ template<typename T> T Math::tauf(T taup, T es) {
32
+ static const int numit = 5;
33
+ static const T tol = sqrt(numeric_limits<T>::epsilon()) / T(10);
34
+ T e2m = T(1) - sq(es),
35
+ // To lowest order in e^2, taup = (1 - e^2) * tau = _e2m * tau; so use
36
+ // tau = taup/_e2m as a starting guess. (This starting guess is the
37
+ // geocentric latitude which, to first order in the flattening, is equal
38
+ // to the conformal latitude.) Only 1 iteration is needed for |lat| <
39
+ // 3.35 deg, otherwise 2 iterations are needed. If, instead, tau = taup
40
+ // is used the mean number of iterations increases to 1.99 (2 iterations
41
+ // are needed except near tau = 0).
42
+ tau = taup/e2m,
43
+ stol = tol * max(T(1), abs(taup));
44
+ // min iterations = 1, max iterations = 2; mean = 1.94
45
+ for (int i = 0; i < numit || GEOGRAPHICLIB_PANIC; ++i) {
46
+ T taupa = taupf(tau, es),
47
+ dtau = (taup - taupa) * (1 + e2m * sq(tau)) /
48
+ ( e2m * hypot(T(1), tau) * hypot(T(1), taupa) );
49
+ tau += dtau;
50
+ if (!(abs(dtau) >= stol))
51
+ break;
52
+ }
53
+ return tau;
54
+ }
55
+
56
+ /// \cond SKIP
57
+ // Instantiate
58
+ template Math::real Math::eatanhe<Math::real>(Math::real, Math::real);
59
+ template Math::real Math::taupf<Math::real>(Math::real, Math::real);
60
+ template Math::real Math::tauf<Math::real>(Math::real, Math::real);
61
+ /// \endcond
62
+
63
+ } // namespace GeographicLib
@@ -0,0 +1,262 @@
1
+ /**
2
+ * \file NormalGravity.cpp
3
+ * \brief Implementation for GeographicLib::NormalGravity class
4
+ *
5
+ * Copyright (c) Charles Karney (2011-2015) <charles@karney.com> and licensed
6
+ * under the MIT/X11 License. For more information, see
7
+ * http://geographiclib.sourceforge.net/
8
+ **********************************************************************/
9
+
10
+ #include <GeographicLib/NormalGravity.hpp>
11
+
12
+ #if defined(_MSC_VER)
13
+ // Squelch warnings about constant conditional expressions
14
+ # pragma warning (disable: 4127)
15
+ #endif
16
+
17
+ namespace GeographicLib {
18
+
19
+ using namespace std;
20
+
21
+ NormalGravity::NormalGravity(real a, real GM, real omega, real f, real J2)
22
+ : _a(a)
23
+ , _GM(GM)
24
+ , _omega(omega)
25
+ , _f(f)
26
+ , _J2(J2)
27
+ , _omega2(Math::sq(_omega))
28
+ , _aomega2(Math::sq(_omega * _a))
29
+ {
30
+ if (!(Math::isfinite(_a) && _a > 0))
31
+ throw GeographicErr("Major radius is not positive");
32
+ if (!(Math::isfinite(_GM) && _GM > 0))
33
+ throw GeographicErr("Gravitational constant is not positive");
34
+ if (!(_omega == 0 && _f == 0 && _J2 == 0)) {
35
+ bool flatp = _f > 0 && Math::isfinite(_f);
36
+ if (_J2 > 0 && Math::isfinite(_J2) && flatp)
37
+ throw GeographicErr("Cannot specify both f and J2");
38
+ if (!(_J2 > 0 && Math::isfinite(_J2)) && !flatp)
39
+ throw GeographicErr("Must specify one of f and J2");
40
+ if (!(Math::isfinite(_omega) && _omega != 0))
41
+ throw GeographicErr("Angular velocity is not non-zero");
42
+ if (flatp)
43
+ _J2 = FlatteningToJ2(_a, _GM, _omega, _f);
44
+ else
45
+ _f = J2ToFlattening(_a, _GM, _omega, _J2);
46
+ } // else we have a sphere: omega = f = J2 = 0
47
+ _e2 = _f * (2 - _f);
48
+ _ep2 = _e2 / (1 - _e2);
49
+ _q0 = qf(_ep2);
50
+ _earth = Geocentric(_a, _f);
51
+ _b = _a * (1 - _f);
52
+ _E = _a * sqrt(_e2); // H+M, Eq 2-54
53
+ // H+M, Eq 2-61
54
+ _U0 = _GM / (_E ? _E / atan(sqrt(_ep2)) : _b) + _aomega2 / 3;
55
+ // The approximate ratio of the centrifugal acceleration (at the equator)
56
+ // to gravity.
57
+ _m = _aomega2 * _b / _GM; // H+M, Eq 2-70
58
+ real
59
+ Q = _m * (_q0 ? sqrt(_ep2) * qpf(_ep2) / (3 * _q0) : 1),
60
+ G = (1 - _m - Q / 2);
61
+ _gammae = _GM / (_a * _b) * G; // H+M, Eq 2-73
62
+ _gammap = _GM / (_a * _a) * (1 + Q); // H+M, Eq 2-74
63
+ // k = b * gammap / (a * gammae) - 1
64
+ _k = (_m + 3 * Q / 2 - _e2 * (1 + Q)) / G;
65
+ // f* = (gammap - gammae) / gammae
66
+ _fstar = (_m + 3 * Q / 2 - _f * (1 + Q)) / G;
67
+ }
68
+
69
+ const NormalGravity& NormalGravity::WGS84() {
70
+ static const NormalGravity wgs84(Constants::WGS84_a(),
71
+ Constants::WGS84_GM(),
72
+ Constants::WGS84_omega(),
73
+ Constants::WGS84_f(), 0);
74
+ return wgs84;
75
+ }
76
+
77
+ const NormalGravity& NormalGravity::GRS80() {
78
+ static const NormalGravity grs80(Constants::GRS80_a(),
79
+ Constants::GRS80_GM(),
80
+ Constants::GRS80_omega(),
81
+ 0, Constants::GRS80_J2());
82
+ return grs80;
83
+ }
84
+
85
+ // (atan(y)-(y-y^3/3+y^5/5))/y^7 (y = sqrt(x)) = -1/7+x/9-x^2/11+x^3/13...
86
+ Math::real NormalGravity::atan7(real x) {
87
+ if (abs(x) >= real(0.5)) {
88
+ real y = sqrt(abs(x)), x2 = Math::sq(x);
89
+ return ((x > 0 ? atan(y) : Math::atanh(y))- y * (1 - x / 3 + x2 / 5)) /
90
+ (x * x2 * y);
91
+ } else {
92
+ real xn = -1, q = 0;
93
+ for (int n = 7; ; n += 2) {
94
+ real qn = q + xn / n;
95
+ if (qn == q)
96
+ break;
97
+ q = qn;
98
+ xn *= -x;
99
+ }
100
+ return q;
101
+ }
102
+ }
103
+
104
+ // (atan(y)-(y-y^3/3))/y^5 (y = sqrt(x)) = 1/5-x/7+x^2/9-x^3/11...
105
+ Math::real NormalGravity::atan5(real x)
106
+ { return 1/real(5) + x * atan7(x); }
107
+
108
+ Math::real NormalGravity::qf(real ep2) {
109
+ // Compute
110
+ //
111
+ // ((1 + 3/e'^2) * atan(e') - 3/e')/2
112
+ //
113
+ // See H+M, Eq 2-57, with E/u = e'. This suffers from two levels of
114
+ // cancelation. The e'^-1 and e'^1 terms drop out, so that the leading
115
+ // term is O(e'^3). Substitute atan(e') = e' - e'^3/3 + e'^5*atan5(e'^2)
116
+ return sqrt(ep2) * ep2 * (3 * (3 + ep2) * atan5(ep2) - 1) / 6;
117
+ }
118
+
119
+ Math::real NormalGravity::dq(real ep2) {
120
+ // Compute d qf(ep2) / d ep2 and substitute
121
+ // atan(e') = e' - e'^3/3 + e'^5/5 + e'^7*atan7(e'^2)
122
+ return sqrt(ep2) * (5 - 3 * (1 + ep2) * (1 + 5 * ep2 * atan7(ep2))) /
123
+ (10 * (1 + ep2));
124
+ }
125
+
126
+ Math::real NormalGravity::qpf(real ep2) {
127
+ // Compute
128
+ //
129
+ // 3*(1 + 1/e'^2) * (1 - atan(e')/e') - 1
130
+ //
131
+ // See H+M, Eq 2-67, with E/u = e'. This suffers from two levels of
132
+ // cancelation. The e'^-2 and e'^0 terms drop out, so that the leading
133
+ // term is O(e'^2).
134
+ return ep2 * (1 - 3 * (1 + ep2) * atan5(ep2));
135
+ }
136
+
137
+ Math::real NormalGravity::Jn(int n) const {
138
+ // Note Jn(0) = -1; Jn(2) = _J2; Jn(odd) = 0
139
+ if (n & 1 || n < 0)
140
+ return 0;
141
+ n /= 2;
142
+ real e2n = 1; // Perhaps this should just be e2n = pow(-_e2, n);
143
+ for (int j = n; j--;)
144
+ e2n *= -_e2;
145
+ return // H+M, Eq 2-92
146
+ -3 * e2n * ((1 - n) + 5 * n * _J2 / _e2) / ((2 * n + 1) * (2 * n + 3));
147
+ }
148
+
149
+ Math::real NormalGravity::SurfaceGravity(real lat) const {
150
+ real sphi = Math::sind(Math::LatFix(lat));
151
+ // H+M, Eq 2-78
152
+ return _gammae * (1 + _k * Math::sq(sphi)) / sqrt(1 - _e2 * Math::sq(sphi));
153
+ }
154
+
155
+ Math::real NormalGravity::V0(real X, real Y, real Z,
156
+ real& GammaX, real& GammaY, real& GammaZ)
157
+ const {
158
+ // See H+M, Sec 6-2
159
+ real
160
+ p = Math::hypot(X, Y),
161
+ clam = p ? X/p : 1,
162
+ slam = p ? Y/p : 0,
163
+ r = Math::hypot(p, Z),
164
+ Q = Math::sq(r) - Math::sq(_E),
165
+ t2 = Math::sq(2 * _E * Z),
166
+ disc = sqrt(Math::sq(Q) + t2),
167
+ // This is H+M, Eq 6-8a, but generalized to deal with Q negative
168
+ // accurately.
169
+ u = sqrt((Q >= 0 ? (Q + disc) : t2 / (disc - Q)) / 2),
170
+ uE = Math::hypot(u, _E),
171
+ // H+M, Eq 6-8b
172
+ sbet = Z * uE,
173
+ cbet = p * u,
174
+ s = Math::hypot(cbet, sbet);
175
+ cbet = s ? cbet/s : 0;
176
+ sbet = s ? sbet/s : 1;
177
+ real
178
+ invw = uE / Math::hypot(u, _E * sbet), // H+M, Eq 2-63
179
+ ep = _E/u,
180
+ ep2 = Math::sq(ep),
181
+ q = _q0 ? qf(ep2) / _q0 : pow(_a / u, 3),
182
+ qp = qpf(ep2) / _q0,
183
+ // H+M, Eqs 2-62 + 6-9, but omitting last (rotational) term .
184
+ Vres = (_GM / (_E ? _E / atan(_E / u) : u)
185
+ + _aomega2 * q * (Math::sq(sbet) - 1/real(3)) / 2),
186
+ // H+M, Eq 6-10
187
+ gamu = - invw * (_GM
188
+ + (_aomega2 * (_q0 ? _E * qp : 3 * q * u)
189
+ * (Math::sq(sbet) - 1/real(3)) / 2)) / Math::sq(uE),
190
+ gamb = _aomega2 * q * sbet * cbet * invw / uE,
191
+ t = u * invw / uE;
192
+ // H+M, Eq 6-12
193
+ GammaX = t * cbet * gamu - invw * sbet * gamb;
194
+ GammaY = GammaX * slam;
195
+ GammaX *= clam;
196
+ GammaZ = invw * sbet * gamu + t * cbet * gamb;
197
+ return Vres;
198
+ }
199
+
200
+ Math::real NormalGravity::Phi(real X, real Y, real& fX, real& fY)
201
+ const {
202
+ fX = _omega2 * X;
203
+ fY = _omega2 * Y;
204
+ // N.B. fZ = 0;
205
+ return _omega2 * (Math::sq(X) + Math::sq(Y)) / 2;
206
+ }
207
+
208
+ Math::real NormalGravity::U(real X, real Y, real Z,
209
+ real& gammaX, real& gammaY, real& gammaZ)
210
+ const {
211
+ real fX, fY;
212
+ real Ures = V0(X, Y, Z, gammaX, gammaY, gammaZ) + Phi(X, Y, fX, fY);
213
+ gammaX += fX;
214
+ gammaY += fY;
215
+ return Ures;
216
+ }
217
+
218
+ Math::real NormalGravity::Gravity(real lat, real h,
219
+ real& gammay, real& gammaz)
220
+ const {
221
+ real X, Y, Z;
222
+ real M[Geocentric::dim2_];
223
+ _earth.IntForward(lat, 0, h, X, Y, Z, M);
224
+ real gammaX, gammaY, gammaZ,
225
+ Ures = U(X, Y, Z, gammaX, gammaY, gammaZ);
226
+ // gammax = M[0] * gammaX + M[3] * gammaY + M[6] * gammaZ;
227
+ gammay = M[1] * gammaX + M[4] * gammaY + M[7] * gammaZ;
228
+ gammaz = M[2] * gammaX + M[5] * gammaY + M[8] * gammaZ;
229
+ return Ures;
230
+ }
231
+
232
+ Math::real NormalGravity::J2ToFlattening(real a, real GM,
233
+ real omega, real J2) {
234
+ real
235
+ K = 2 * Math::sq(a * omega) * a / (15 * GM),
236
+ e2 = 3 * J2; // See Moritz (1980), p 398.
237
+ // Solve using Newton's method
238
+ for (int j = 0; j < maxit_ || GEOGRAPHICLIB_PANIC; ++j) {
239
+ real e2a = e2,
240
+ ep2 = e2 / (1 - e2),
241
+ q0 = qf(ep2),
242
+ dq0 = dq(ep2) / Math::sq(1 - e2),
243
+ h = e2 * (1 - sqrt(e2) * K / q0) - 3 * J2,
244
+ dh = 1 - sqrt(e2) * K * (3 * q0 - 2 * e2 * dq0) / (2 * Math::sq(q0)),
245
+ de2 = - h / dh;
246
+ e2 = e2a + de2;
247
+ if (e2 == e2a)
248
+ break;
249
+ }
250
+ return e2 / (1 + sqrt(1 - e2));
251
+ }
252
+
253
+ Math::real NormalGravity::FlatteningToJ2(real a, real GM,
254
+ real omega, real f) {
255
+ real
256
+ K = 2 * Math::sq(a * omega) * a / (15 * GM),
257
+ e2 = f * (2 - f),
258
+ q0 = qf(e2 / (1 - e2));
259
+ return e2 * (1 - K * sqrt(e2) / q0) / 3; // H+M, Eq 2-90
260
+ }
261
+
262
+ } // namespace GeographicLib