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.
- checksums.yaml +7 -0
- data/AUTHORS +12 -0
- data/LICENSE +24 -0
- data/ext/geographiclib/Accumulator.cpp +23 -0
- data/ext/geographiclib/AlbersEqualArea.cpp +445 -0
- data/ext/geographiclib/AzimuthalEquidistant.cpp +41 -0
- data/ext/geographiclib/CassiniSoldner.cpp +89 -0
- data/ext/geographiclib/CircularEngine.cpp +96 -0
- data/ext/geographiclib/DMS.cpp +381 -0
- data/ext/geographiclib/Ellipsoid.cpp +125 -0
- data/ext/geographiclib/EllipticFunction.cpp +512 -0
- data/ext/geographiclib/GARS.cpp +122 -0
- data/ext/geographiclib/GeoCoords.cpp +175 -0
- data/ext/geographiclib/Geocentric.cpp +172 -0
- data/ext/geographiclib/Geodesic.cpp +1908 -0
- data/ext/geographiclib/GeodesicExact.cpp +927 -0
- data/ext/geographiclib/GeodesicExactC4.cpp +7879 -0
- data/ext/geographiclib/GeodesicLine.cpp +321 -0
- data/ext/geographiclib/GeodesicLineExact.cpp +289 -0
- data/ext/geographiclib/GeographicLib/Accumulator.hpp +184 -0
- data/ext/geographiclib/GeographicLib/AlbersEqualArea.hpp +312 -0
- data/ext/geographiclib/GeographicLib/AzimuthalEquidistant.hpp +139 -0
- data/ext/geographiclib/GeographicLib/CassiniSoldner.hpp +204 -0
- data/ext/geographiclib/GeographicLib/CircularEngine.hpp +195 -0
- data/ext/geographiclib/GeographicLib/Config.h +12 -0
- data/ext/geographiclib/GeographicLib/Constants.hpp +387 -0
- data/ext/geographiclib/GeographicLib/DMS.hpp +370 -0
- data/ext/geographiclib/GeographicLib/Ellipsoid.hpp +534 -0
- data/ext/geographiclib/GeographicLib/EllipticFunction.hpp +692 -0
- data/ext/geographiclib/GeographicLib/GARS.hpp +143 -0
- data/ext/geographiclib/GeographicLib/GeoCoords.hpp +544 -0
- data/ext/geographiclib/GeographicLib/Geocentric.hpp +267 -0
- data/ext/geographiclib/GeographicLib/Geodesic.hpp +970 -0
- data/ext/geographiclib/GeographicLib/GeodesicExact.hpp +862 -0
- data/ext/geographiclib/GeographicLib/GeodesicLine.hpp +701 -0
- data/ext/geographiclib/GeographicLib/GeodesicLineExact.hpp +667 -0
- data/ext/geographiclib/GeographicLib/Geohash.hpp +180 -0
- data/ext/geographiclib/GeographicLib/Geoid.hpp +472 -0
- data/ext/geographiclib/GeographicLib/Georef.hpp +160 -0
- data/ext/geographiclib/GeographicLib/Gnomonic.hpp +206 -0
- data/ext/geographiclib/GeographicLib/GravityCircle.hpp +301 -0
- data/ext/geographiclib/GeographicLib/GravityModel.hpp +520 -0
- data/ext/geographiclib/GeographicLib/LambertConformalConic.hpp +313 -0
- data/ext/geographiclib/GeographicLib/LocalCartesian.hpp +236 -0
- data/ext/geographiclib/GeographicLib/MGRS.hpp +355 -0
- data/ext/geographiclib/GeographicLib/MagneticCircle.hpp +178 -0
- data/ext/geographiclib/GeographicLib/MagneticModel.hpp +347 -0
- data/ext/geographiclib/GeographicLib/Math.hpp +920 -0
- data/ext/geographiclib/GeographicLib/NormalGravity.hpp +350 -0
- data/ext/geographiclib/GeographicLib/OSGB.hpp +249 -0
- data/ext/geographiclib/GeographicLib/PolarStereographic.hpp +150 -0
- data/ext/geographiclib/GeographicLib/PolygonArea.hpp +288 -0
- data/ext/geographiclib/GeographicLib/Rhumb.hpp +589 -0
- data/ext/geographiclib/GeographicLib/SphericalEngine.hpp +376 -0
- data/ext/geographiclib/GeographicLib/SphericalHarmonic.hpp +354 -0
- data/ext/geographiclib/GeographicLib/SphericalHarmonic1.hpp +281 -0
- data/ext/geographiclib/GeographicLib/SphericalHarmonic2.hpp +315 -0
- data/ext/geographiclib/GeographicLib/TransverseMercator.hpp +196 -0
- data/ext/geographiclib/GeographicLib/TransverseMercatorExact.hpp +254 -0
- data/ext/geographiclib/GeographicLib/UTMUPS.hpp +421 -0
- data/ext/geographiclib/GeographicLib/Utility.hpp +612 -0
- data/ext/geographiclib/Geohash.cpp +102 -0
- data/ext/geographiclib/Geoid.cpp +509 -0
- data/ext/geographiclib/Georef.cpp +135 -0
- data/ext/geographiclib/Gnomonic.cpp +85 -0
- data/ext/geographiclib/GravityCircle.cpp +129 -0
- data/ext/geographiclib/GravityModel.cpp +360 -0
- data/ext/geographiclib/LambertConformalConic.cpp +456 -0
- data/ext/geographiclib/LocalCartesian.cpp +62 -0
- data/ext/geographiclib/MGRS.cpp +461 -0
- data/ext/geographiclib/MagneticCircle.cpp +52 -0
- data/ext/geographiclib/MagneticModel.cpp +269 -0
- data/ext/geographiclib/Math.cpp +63 -0
- data/ext/geographiclib/NormalGravity.cpp +262 -0
- data/ext/geographiclib/OSGB.cpp +167 -0
- data/ext/geographiclib/PolarStereographic.cpp +108 -0
- data/ext/geographiclib/PolygonArea.cpp +204 -0
- data/ext/geographiclib/Rhumb.cpp +383 -0
- data/ext/geographiclib/SphericalEngine.cpp +477 -0
- data/ext/geographiclib/TransverseMercator.cpp +603 -0
- data/ext/geographiclib/TransverseMercatorExact.cpp +464 -0
- data/ext/geographiclib/UTMUPS.cpp +296 -0
- data/ext/geographiclib/Utility.cpp +61 -0
- data/ext/geographiclib/extconf.rb +3 -0
- data/ext/geographiclib/geographiclib.cpp +62 -0
- data/lib/geographiclib.rb +20 -0
- 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
|