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,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* \file Georef.cpp
|
|
3
|
+
* \brief Implementation for GeographicLib::Georef class
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) Charles Karney (2015) <charles@karney.com> and licensed under
|
|
6
|
+
* the MIT/X11 License. For more information, see
|
|
7
|
+
* http://geographiclib.sourceforge.net/
|
|
8
|
+
**********************************************************************/
|
|
9
|
+
|
|
10
|
+
#include <GeographicLib/Georef.hpp>
|
|
11
|
+
#include <GeographicLib/Utility.hpp>
|
|
12
|
+
|
|
13
|
+
namespace GeographicLib {
|
|
14
|
+
|
|
15
|
+
using namespace std;
|
|
16
|
+
|
|
17
|
+
const string Georef::digits_ = "0123456789";
|
|
18
|
+
const string Georef::lontile_ = "ABCDEFGHJKLMNPQRSTUVWXYZ";
|
|
19
|
+
const string Georef::lattile_ = "ABCDEFGHJKLM";
|
|
20
|
+
const string Georef::degrees_ = "ABCDEFGHJKLMNPQ";
|
|
21
|
+
|
|
22
|
+
void Georef::Forward(real lat, real lon, int prec, std::string& georef) {
|
|
23
|
+
if (abs(lat) > 90)
|
|
24
|
+
throw GeographicErr("Latitude " + Utility::str(lat)
|
|
25
|
+
+ "d not in [-90d, 90d]");
|
|
26
|
+
if (Math::isnan(lat) || Math::isnan(lon)) {
|
|
27
|
+
georef = "INVALID";
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
lon = Math::AngNormalize(lon); // lon in [-180,180)
|
|
31
|
+
if (lat == 90) lat *= (1 - numeric_limits<real>::epsilon() / 2);
|
|
32
|
+
prec = max(-1, min(int(maxprec_), prec));
|
|
33
|
+
if (prec == 1) ++prec; // Disallow prec = 1
|
|
34
|
+
// The C++ standard mandates 64 bits for long long. But
|
|
35
|
+
// check, to make sure.
|
|
36
|
+
GEOGRAPHICLIB_STATIC_ASSERT(numeric_limits<long long>::digits >= 45,
|
|
37
|
+
"long long not wide enough to store 21600e9");
|
|
38
|
+
const long long m = 60000000000LL;
|
|
39
|
+
long long
|
|
40
|
+
x = (long long)(floor(lon * m)) - lonorig_ * m,
|
|
41
|
+
y = (long long)(floor(lat * m)) - latorig_ * m;
|
|
42
|
+
int ilon = int(x / m); int ilat = int(y / m);
|
|
43
|
+
char georef1[maxlen_];
|
|
44
|
+
georef1[0] = lontile_[ilon / tile_];
|
|
45
|
+
georef1[1] = lattile_[ilat / tile_];
|
|
46
|
+
if (prec >= 0) {
|
|
47
|
+
georef1[2] = degrees_[ilon % tile_];
|
|
48
|
+
georef1[3] = degrees_[ilat % tile_];
|
|
49
|
+
if (prec > 0) {
|
|
50
|
+
x -= m * ilon; y -= m * ilat;
|
|
51
|
+
long long d = (long long)pow(real(base_), maxprec_ - prec);
|
|
52
|
+
x /= d; y /= d;
|
|
53
|
+
for (int c = prec; c--;) {
|
|
54
|
+
georef1[baselen_ + c ] = digits_[x % base_]; x /= base_;
|
|
55
|
+
georef1[baselen_ + c + prec] = digits_[y % base_]; y /= base_;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
georef.resize(baselen_ + 2 * prec);
|
|
60
|
+
copy(georef1, georef1 + baselen_ + 2 * prec, georef.begin());
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
void Georef::Reverse(const std::string& georef, real& lat, real& lon,
|
|
64
|
+
int& prec, bool centerp) {
|
|
65
|
+
int len = int(georef.length());
|
|
66
|
+
if (len >= 3 &&
|
|
67
|
+
toupper(georef[0]) == 'I' &&
|
|
68
|
+
toupper(georef[1]) == 'N' &&
|
|
69
|
+
toupper(georef[2]) == 'V') {
|
|
70
|
+
lat = lon = Math::NaN();
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (len < baselen_ - 2)
|
|
74
|
+
throw GeographicErr("Georef must start with at least 2 letters "
|
|
75
|
+
+ georef);
|
|
76
|
+
int prec1 = (2 + len - baselen_) / 2 - 1;
|
|
77
|
+
int k;
|
|
78
|
+
k = Utility::lookup(lontile_, georef[0]);
|
|
79
|
+
if (k < 0)
|
|
80
|
+
throw GeographicErr("Bad longitude tile letter in georef " + georef);
|
|
81
|
+
real lon1 = k + lonorig_ / tile_;
|
|
82
|
+
k = Utility::lookup(lattile_, georef[1]);
|
|
83
|
+
if (k < 0)
|
|
84
|
+
throw GeographicErr("Bad latitude tile letter in georef " + georef);
|
|
85
|
+
real lat1 = k + latorig_ / tile_;
|
|
86
|
+
real unit = 1;
|
|
87
|
+
if (len > 2) {
|
|
88
|
+
unit *= tile_;
|
|
89
|
+
k = Utility::lookup(degrees_, georef[2]);
|
|
90
|
+
if (k < 0)
|
|
91
|
+
throw GeographicErr("Bad longitude degree letter in georef " + georef);
|
|
92
|
+
lon1 = lon1 * tile_ + k;
|
|
93
|
+
if (len < 4)
|
|
94
|
+
throw GeographicErr("Missing latitude degree letter in georef "
|
|
95
|
+
+ georef);
|
|
96
|
+
k = Utility::lookup(degrees_, georef[3]);
|
|
97
|
+
if (k < 0)
|
|
98
|
+
throw GeographicErr("Bad latitude degree letter in georef " + georef);
|
|
99
|
+
lat1 = lat1 * tile_ + k;
|
|
100
|
+
if (prec1 > 0) {
|
|
101
|
+
if (georef.find_first_not_of(digits_, baselen_) != string::npos)
|
|
102
|
+
throw GeographicErr("Non digits in trailing portion of georef "
|
|
103
|
+
+ georef.substr(baselen_));
|
|
104
|
+
if (len % 2)
|
|
105
|
+
throw GeographicErr("Georef must end with an even number of digits "
|
|
106
|
+
+ georef.substr(baselen_));
|
|
107
|
+
if (prec1 == 1)
|
|
108
|
+
throw GeographicErr("Georef needs at least 4 digits for minutes "
|
|
109
|
+
+ georef.substr(baselen_));
|
|
110
|
+
if (prec1 > maxprec_)
|
|
111
|
+
throw GeographicErr("More than " + Utility::str(2*maxprec_)
|
|
112
|
+
+ " digits in georef " + georef.substr(baselen_));
|
|
113
|
+
for (int i = 0; i < prec1; ++i) {
|
|
114
|
+
int m = i ? base_ : 6;
|
|
115
|
+
unit *= m;
|
|
116
|
+
int
|
|
117
|
+
x = Utility::lookup(digits_, georef[baselen_ + i]),
|
|
118
|
+
y = Utility::lookup(digits_, georef[baselen_ + i + prec1]);
|
|
119
|
+
if (!(i || (x < m && y < m)))
|
|
120
|
+
throw GeographicErr("Minutes terms in georef must be less than 60 "
|
|
121
|
+
+ georef.substr(baselen_));
|
|
122
|
+
lon1 = m * lon1 + x;
|
|
123
|
+
lat1 = m * lat1 + y;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (centerp) {
|
|
128
|
+
unit *= 2; lat1 = 2 * lat1 + 1; lon1 = 2 * lon1 + 1;
|
|
129
|
+
}
|
|
130
|
+
lat = (tile_ * lat1) / unit;
|
|
131
|
+
lon = (tile_ * lon1) / unit;
|
|
132
|
+
prec = prec1;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
} // namespace GeographicLib
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* \file Gnomonic.cpp
|
|
3
|
+
* \brief Implementation for GeographicLib::Gnomonic class
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) Charles Karney (2010-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/Gnomonic.hpp>
|
|
11
|
+
|
|
12
|
+
#if defined(_MSC_VER)
|
|
13
|
+
// Squelch warnings about potentially uninitialized local variables and
|
|
14
|
+
// constant conditional expressions
|
|
15
|
+
# pragma warning (disable: 4701 4127)
|
|
16
|
+
#endif
|
|
17
|
+
|
|
18
|
+
namespace GeographicLib {
|
|
19
|
+
|
|
20
|
+
using namespace std;
|
|
21
|
+
|
|
22
|
+
Gnomonic::Gnomonic(const Geodesic& earth)
|
|
23
|
+
: eps0_(numeric_limits<real>::epsilon())
|
|
24
|
+
, eps_(real(0.01) * sqrt(eps0_))
|
|
25
|
+
, _earth(earth)
|
|
26
|
+
, _a(_earth.MajorRadius())
|
|
27
|
+
, _f(_earth.Flattening())
|
|
28
|
+
{}
|
|
29
|
+
|
|
30
|
+
void Gnomonic::Forward(real lat0, real lon0, real lat, real lon,
|
|
31
|
+
real& x, real& y, real& azi, real& rk)
|
|
32
|
+
const {
|
|
33
|
+
real azi0, m, M, t;
|
|
34
|
+
_earth.GenInverse(lat0, lon0, lat, lon,
|
|
35
|
+
Geodesic::AZIMUTH | Geodesic::REDUCEDLENGTH |
|
|
36
|
+
Geodesic::GEODESICSCALE,
|
|
37
|
+
t, azi0, azi, m, M, t, t);
|
|
38
|
+
rk = M;
|
|
39
|
+
if (M <= 0)
|
|
40
|
+
x = y = Math::NaN();
|
|
41
|
+
else {
|
|
42
|
+
real rho = m/M;
|
|
43
|
+
Math::sincosd(azi0, x, y);
|
|
44
|
+
x *= rho; y *= rho;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
void Gnomonic::Reverse(real lat0, real lon0, real x, real y,
|
|
49
|
+
real& lat, real& lon, real& azi, real& rk)
|
|
50
|
+
const {
|
|
51
|
+
real
|
|
52
|
+
azi0 = Math::atan2d(x, y),
|
|
53
|
+
rho = Math::hypot(x, y),
|
|
54
|
+
s = _a * atan(rho/_a);
|
|
55
|
+
bool little = rho <= _a;
|
|
56
|
+
if (!little)
|
|
57
|
+
rho = 1/rho;
|
|
58
|
+
GeodesicLine line(_earth.Line(lat0, lon0, azi0,
|
|
59
|
+
Geodesic::LATITUDE | Geodesic::LONGITUDE |
|
|
60
|
+
Geodesic::AZIMUTH | Geodesic::DISTANCE_IN |
|
|
61
|
+
Geodesic::REDUCEDLENGTH |
|
|
62
|
+
Geodesic::GEODESICSCALE));
|
|
63
|
+
int count = numit_, trip = 0;
|
|
64
|
+
real lat1, lon1, azi1, M;
|
|
65
|
+
while (count-- || GEOGRAPHICLIB_PANIC) {
|
|
66
|
+
real m, t;
|
|
67
|
+
line.Position(s, lat1, lon1, azi1, m, M, t);
|
|
68
|
+
if (trip)
|
|
69
|
+
break;
|
|
70
|
+
// If little, solve rho(s) = rho with drho(s)/ds = 1/M^2
|
|
71
|
+
// else solve 1/rho(s) = 1/rho with d(1/rho(s))/ds = -1/m^2
|
|
72
|
+
real ds = little ? (m/M - rho) * M * M : (rho - M/m) * m * m;
|
|
73
|
+
s -= ds;
|
|
74
|
+
// Reversed test to allow escape with NaNs
|
|
75
|
+
if (!(abs(ds) >= eps_ * _a))
|
|
76
|
+
++trip;
|
|
77
|
+
}
|
|
78
|
+
if (trip) {
|
|
79
|
+
lat = lat1; lon = lon1; azi = azi1; rk = M;
|
|
80
|
+
} else
|
|
81
|
+
lat = lon = azi = rk = Math::NaN();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
} // namespace GeographicLib
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* \file GravityCircle.cpp
|
|
3
|
+
* \brief Implementation for GeographicLib::GravityCircle 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/GravityCircle.hpp>
|
|
11
|
+
#include <fstream>
|
|
12
|
+
#include <sstream>
|
|
13
|
+
#include <GeographicLib/Geocentric.hpp>
|
|
14
|
+
|
|
15
|
+
namespace GeographicLib {
|
|
16
|
+
|
|
17
|
+
using namespace std;
|
|
18
|
+
|
|
19
|
+
Math::real GravityCircle::Gravity(real lon, real& gx, real& gy, real& gz)
|
|
20
|
+
const {
|
|
21
|
+
real slam, clam, M[Geocentric::dim2_];
|
|
22
|
+
Math::sincosd(lon, slam, clam);
|
|
23
|
+
real Wres = W(slam, clam, gx, gy, gz);
|
|
24
|
+
Geocentric::Rotation(_sphi, _cphi, slam, clam, M);
|
|
25
|
+
Geocentric::Unrotate(M, gx, gy, gz, gx, gy, gz);
|
|
26
|
+
return Wres;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
Math::real GravityCircle::Disturbance(real lon, real& deltax, real& deltay,
|
|
30
|
+
real& deltaz) const {
|
|
31
|
+
real slam, clam, M[Geocentric::dim2_];
|
|
32
|
+
Math::sincosd(lon, slam, clam);
|
|
33
|
+
real Tres = InternalT(slam, clam, deltax, deltay, deltaz, true, true);
|
|
34
|
+
Geocentric::Rotation(_sphi, _cphi, slam, clam, M);
|
|
35
|
+
Geocentric::Unrotate(M, deltax, deltay, deltaz, deltax, deltay, deltaz);
|
|
36
|
+
return Tres;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
Math::real GravityCircle::GeoidHeight(real lon) const {
|
|
40
|
+
if ((_caps & GEOID_HEIGHT) != GEOID_HEIGHT)
|
|
41
|
+
return Math::NaN();
|
|
42
|
+
real slam, clam, dummy;
|
|
43
|
+
Math::sincosd(lon, slam, clam);
|
|
44
|
+
real T = InternalT(slam, clam, dummy, dummy, dummy, false, false);
|
|
45
|
+
real correction = _corrmult * _correction(slam, clam);
|
|
46
|
+
return T/_gamma0 + correction;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
void GravityCircle::SphericalAnomaly(real lon,
|
|
50
|
+
real& Dg01, real& xi, real& eta)
|
|
51
|
+
const {
|
|
52
|
+
if ((_caps & SPHERICAL_ANOMALY) != SPHERICAL_ANOMALY) {
|
|
53
|
+
Dg01 = xi = eta = Math::NaN();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
real slam, clam;
|
|
57
|
+
Math::sincosd(lon, slam, clam);
|
|
58
|
+
real
|
|
59
|
+
deltax, deltay, deltaz,
|
|
60
|
+
T = InternalT(slam, clam, deltax, deltay, deltaz, true, false);
|
|
61
|
+
// Rotate cartesian into spherical coordinates
|
|
62
|
+
real MC[Geocentric::dim2_];
|
|
63
|
+
Geocentric::Rotation(_spsi, _cpsi, slam, clam, MC);
|
|
64
|
+
Geocentric::Unrotate(MC, deltax, deltay, deltaz, deltax, deltay, deltaz);
|
|
65
|
+
// H+M, Eq 2-151c
|
|
66
|
+
Dg01 = - deltaz - 2 * T * _invR;
|
|
67
|
+
xi = -(deltay/_gamma) / Math::degree();
|
|
68
|
+
eta = -(deltax/_gamma) / Math::degree();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
Math::real GravityCircle::W(real slam, real clam,
|
|
72
|
+
real& gX, real& gY, real& gZ) const {
|
|
73
|
+
real Wres = V(slam, clam, gX, gY, gZ) + _frot * _Px / 2;
|
|
74
|
+
gX += _frot * clam;
|
|
75
|
+
gY += _frot * slam;
|
|
76
|
+
return Wres;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
Math::real GravityCircle::V(real slam, real clam,
|
|
80
|
+
real& GX, real& GY, real& GZ)
|
|
81
|
+
const {
|
|
82
|
+
if ((_caps & GRAVITY) != GRAVITY) {
|
|
83
|
+
GX = GY = GZ = Math::NaN();
|
|
84
|
+
return Math::NaN();
|
|
85
|
+
}
|
|
86
|
+
real
|
|
87
|
+
Vres = _gravitational(slam, clam, GX, GY, GZ),
|
|
88
|
+
f = _GMmodel / _amodel;
|
|
89
|
+
Vres *= f;
|
|
90
|
+
GX *= f;
|
|
91
|
+
GY *= f;
|
|
92
|
+
GZ *= f;
|
|
93
|
+
return Vres;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
Math::real GravityCircle::InternalT(real slam, real clam,
|
|
97
|
+
real& deltaX, real& deltaY, real& deltaZ,
|
|
98
|
+
bool gradp, bool correct) const {
|
|
99
|
+
if (gradp) {
|
|
100
|
+
if ((_caps & DISTURBANCE) != DISTURBANCE) {
|
|
101
|
+
deltaX = deltaY = deltaZ = Math::NaN();
|
|
102
|
+
return Math::NaN();
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
if ((_caps & DISTURBING_POTENTIAL) != DISTURBING_POTENTIAL)
|
|
106
|
+
return Math::NaN();
|
|
107
|
+
}
|
|
108
|
+
if (_dzonal0 == 0)
|
|
109
|
+
correct = false;
|
|
110
|
+
real T = (gradp
|
|
111
|
+
? _disturbing(slam, clam, deltaX, deltaY, deltaZ)
|
|
112
|
+
: _disturbing(slam, clam));
|
|
113
|
+
T = (T / _amodel - (correct ? _dzonal0 : 0) * _invR) * _GMmodel;
|
|
114
|
+
if (gradp) {
|
|
115
|
+
real f = _GMmodel / _amodel;
|
|
116
|
+
deltaX *= f;
|
|
117
|
+
deltaY *= f;
|
|
118
|
+
deltaZ *= f;
|
|
119
|
+
if (correct) {
|
|
120
|
+
real r3 = _GMmodel * _dzonal0 * _invR * _invR * _invR;
|
|
121
|
+
deltaX += _Px * clam * r3;
|
|
122
|
+
deltaY += _Px * slam * r3;
|
|
123
|
+
deltaZ += _Z * r3;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return T;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
} // namespace GeographicLib
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* \file GravityModel.cpp
|
|
3
|
+
* \brief Implementation for GeographicLib::GravityModel class
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) Charles Karney (2011-2012) <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/GravityModel.hpp>
|
|
11
|
+
#include <fstream>
|
|
12
|
+
#include <GeographicLib/SphericalEngine.hpp>
|
|
13
|
+
#include <GeographicLib/GravityCircle.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_GRAVITY_DEFAULT_NAME)
|
|
25
|
+
# define GEOGRAPHICLIB_GRAVITY_DEFAULT_NAME "egm96"
|
|
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
|
+
GravityModel::GravityModel(const std::string& name,const std::string& path)
|
|
38
|
+
: _name(name)
|
|
39
|
+
, _dir(path)
|
|
40
|
+
, _description("NONE")
|
|
41
|
+
, _date("UNKNOWN")
|
|
42
|
+
, _amodel(Math::NaN())
|
|
43
|
+
, _GMmodel(Math::NaN())
|
|
44
|
+
, _zeta0(0)
|
|
45
|
+
, _corrmult(1)
|
|
46
|
+
, _norm(SphericalHarmonic::FULL)
|
|
47
|
+
{
|
|
48
|
+
if (_dir.empty())
|
|
49
|
+
_dir = DefaultGravityPath();
|
|
50
|
+
ReadMetadata(_name);
|
|
51
|
+
{
|
|
52
|
+
string coeff = _filename + ".cof";
|
|
53
|
+
ifstream coeffstr(coeff.c_str(), ios::binary);
|
|
54
|
+
if (!coeffstr.good())
|
|
55
|
+
throw GeographicErr("Error opening " + coeff);
|
|
56
|
+
char id[idlength_ + 1];
|
|
57
|
+
coeffstr.read(id, idlength_);
|
|
58
|
+
if (!coeffstr.good())
|
|
59
|
+
throw GeographicErr("No header in " + coeff);
|
|
60
|
+
id[idlength_] = '\0';
|
|
61
|
+
if (_id != string(id))
|
|
62
|
+
throw GeographicErr("ID mismatch: " + _id + " vs " + id);
|
|
63
|
+
int N, M;
|
|
64
|
+
SphericalEngine::coeff::readcoeffs(coeffstr, N, M, _Cx, _Sx);
|
|
65
|
+
if (!(N >= 0 && M >= 0))
|
|
66
|
+
throw GeographicErr("Degree and order must be at least 0");
|
|
67
|
+
if (_Cx[0] != 0)
|
|
68
|
+
throw GeographicErr("A degree 0 term should be zero");
|
|
69
|
+
_Cx[0] = 1; // Include the 1/r term in the sum
|
|
70
|
+
_gravitational = SphericalHarmonic(_Cx, _Sx, N, N, M, _amodel, _norm);
|
|
71
|
+
SphericalEngine::coeff::readcoeffs(coeffstr, N, M, _CC, _CS);
|
|
72
|
+
if (N < 0) {
|
|
73
|
+
N = M = 0;
|
|
74
|
+
_CC.resize(1, real(0));
|
|
75
|
+
}
|
|
76
|
+
_CC[0] += _zeta0 / _corrmult;
|
|
77
|
+
_correction = SphericalHarmonic(_CC, _CS, N, N, M, real(1), _norm);
|
|
78
|
+
int pos = int(coeffstr.tellg());
|
|
79
|
+
coeffstr.seekg(0, ios::end);
|
|
80
|
+
if (pos != coeffstr.tellg())
|
|
81
|
+
throw GeographicErr("Extra data in " + coeff);
|
|
82
|
+
}
|
|
83
|
+
int nmx = _gravitational.Coefficients().nmx();
|
|
84
|
+
// Adjust the normalization of the normal potential to match the model.
|
|
85
|
+
real mult = _earth._GM / _GMmodel;
|
|
86
|
+
real amult = Math::sq(_earth._a / _amodel);
|
|
87
|
+
// The 0th term in _zonal should be is 1 + _dzonal0. Instead set it to 1
|
|
88
|
+
// to give exact cancellation with the (0,0) term in the model and account
|
|
89
|
+
// for _dzonal0 separately.
|
|
90
|
+
_zonal.clear(); _zonal.push_back(1);
|
|
91
|
+
_dzonal0 = (_earth.MassConstant() - _GMmodel) / _GMmodel;
|
|
92
|
+
for (int n = 2; n <= nmx; n += 2) {
|
|
93
|
+
// Only include as many normal zonal terms as matter. Figuring the limit
|
|
94
|
+
// in this way works because the coefficients of the normal potential
|
|
95
|
+
// (which is smooth) decay much more rapidly that the corresponding
|
|
96
|
+
// coefficient of the model potential (which is bumpy). Typically this
|
|
97
|
+
// goes out to n = 18.
|
|
98
|
+
mult *= amult;
|
|
99
|
+
real
|
|
100
|
+
r = _Cx[n], // the model term
|
|
101
|
+
s = - mult * _earth.Jn(n) / sqrt(real(2 * n + 1)), // the normal term
|
|
102
|
+
t = r - s; // the difference
|
|
103
|
+
if (t == r) // the normal term is negligible
|
|
104
|
+
break;
|
|
105
|
+
_zonal.push_back(0); // index = n - 1; the odd terms are 0
|
|
106
|
+
_zonal.push_back(s);
|
|
107
|
+
}
|
|
108
|
+
int nmx1 = int(_zonal.size()) - 1;
|
|
109
|
+
_disturbing = SphericalHarmonic1(_Cx, _Sx,
|
|
110
|
+
_gravitational.Coefficients().N(),
|
|
111
|
+
nmx, _gravitational.Coefficients().mmx(),
|
|
112
|
+
_zonal,
|
|
113
|
+
_zonal, // This is not accessed!
|
|
114
|
+
nmx1, nmx1, 0,
|
|
115
|
+
_amodel,
|
|
116
|
+
SphericalHarmonic1::normalization(_norm));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
void GravityModel::ReadMetadata(const std::string& name) {
|
|
120
|
+
const char* spaces = " \t\n\v\f\r";
|
|
121
|
+
_filename = _dir + "/" + name + ".egm";
|
|
122
|
+
ifstream metastr(_filename.c_str());
|
|
123
|
+
if (!metastr.good())
|
|
124
|
+
throw GeographicErr("Cannot open " + _filename);
|
|
125
|
+
string line;
|
|
126
|
+
getline(metastr, line);
|
|
127
|
+
if (!(line.size() >= 6 && line.substr(0,5) == "EGMF-"))
|
|
128
|
+
throw GeographicErr(_filename + " does not contain EGMF-n signature");
|
|
129
|
+
string::size_type n = line.find_first_of(spaces, 5);
|
|
130
|
+
if (n != string::npos)
|
|
131
|
+
n -= 5;
|
|
132
|
+
string version = line.substr(5, n);
|
|
133
|
+
if (version != "1")
|
|
134
|
+
throw GeographicErr("Unknown version in " + _filename + ": " + version);
|
|
135
|
+
string key, val;
|
|
136
|
+
real a = Math::NaN(), GM = a, omega = a, f = a, J2 = a;
|
|
137
|
+
while (getline(metastr, line)) {
|
|
138
|
+
if (!Utility::ParseLine(line, key, val))
|
|
139
|
+
continue;
|
|
140
|
+
// Process key words
|
|
141
|
+
if (key == "Name")
|
|
142
|
+
_name = val;
|
|
143
|
+
else if (key == "Description")
|
|
144
|
+
_description = val;
|
|
145
|
+
else if (key == "ReleaseDate")
|
|
146
|
+
_date = val;
|
|
147
|
+
else if (key == "ModelRadius")
|
|
148
|
+
_amodel = Utility::num<real>(val);
|
|
149
|
+
else if (key == "ModelMass")
|
|
150
|
+
_GMmodel = Utility::num<real>(val);
|
|
151
|
+
else if (key == "AngularVelocity")
|
|
152
|
+
omega = Utility::num<real>(val);
|
|
153
|
+
else if (key == "ReferenceRadius")
|
|
154
|
+
a = Utility::num<real>(val);
|
|
155
|
+
else if (key == "ReferenceMass")
|
|
156
|
+
GM = Utility::num<real>(val);
|
|
157
|
+
else if (key == "Flattening")
|
|
158
|
+
f = Utility::fract<real>(val);
|
|
159
|
+
else if (key == "DynamicalFormFactor")
|
|
160
|
+
J2 = Utility::fract<real>(val);
|
|
161
|
+
else if (key == "HeightOffset")
|
|
162
|
+
_zeta0 = Utility::fract<real>(val);
|
|
163
|
+
else if (key == "CorrectionMultiplier")
|
|
164
|
+
_corrmult = Utility::fract<real>(val);
|
|
165
|
+
else if (key == "Normalization") {
|
|
166
|
+
if (val == "FULL" || val == "Full" || val == "full")
|
|
167
|
+
_norm = SphericalHarmonic::FULL;
|
|
168
|
+
else if (val == "SCHMIDT" || val == "Schmidt" || val == "schmidt")
|
|
169
|
+
_norm = SphericalHarmonic::SCHMIDT;
|
|
170
|
+
else
|
|
171
|
+
throw GeographicErr("Unknown normalization " + val);
|
|
172
|
+
} else if (key == "ByteOrder") {
|
|
173
|
+
if (val == "Big" || val == "big")
|
|
174
|
+
throw GeographicErr("Only little-endian ordering is supported");
|
|
175
|
+
else if (!(val == "Little" || val == "little"))
|
|
176
|
+
throw GeographicErr("Unknown byte ordering " + val);
|
|
177
|
+
} else if (key == "ID")
|
|
178
|
+
_id = val;
|
|
179
|
+
// else unrecognized keywords are skipped
|
|
180
|
+
}
|
|
181
|
+
// Check values
|
|
182
|
+
if (!(Math::isfinite(_amodel) && _amodel > 0))
|
|
183
|
+
throw GeographicErr("Model radius must be positive");
|
|
184
|
+
if (!(Math::isfinite(_GMmodel) && _GMmodel > 0))
|
|
185
|
+
throw GeographicErr("Model mass constant must be positive");
|
|
186
|
+
if (!(Math::isfinite(_corrmult) && _corrmult > 0))
|
|
187
|
+
throw GeographicErr("Correction multiplier must be positive");
|
|
188
|
+
if (!(Math::isfinite(_zeta0)))
|
|
189
|
+
throw GeographicErr("Height offset must be finite");
|
|
190
|
+
if (int(_id.size()) != idlength_)
|
|
191
|
+
throw GeographicErr("Invalid ID");
|
|
192
|
+
_earth = NormalGravity(a, GM, omega, f, J2);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
Math::real GravityModel::InternalT(real X, real Y, real Z,
|
|
196
|
+
real& deltaX, real& deltaY, real& deltaZ,
|
|
197
|
+
bool gradp, bool correct) const {
|
|
198
|
+
// If correct, then produce the correct T = W - U. Otherwise, neglect the
|
|
199
|
+
// n = 0 term (which is proportial to the difference in the model and
|
|
200
|
+
// reference values of GM).
|
|
201
|
+
if (_dzonal0 == 0)
|
|
202
|
+
// No need to do the correction
|
|
203
|
+
correct = false;
|
|
204
|
+
real T, invR = correct ? 1 / Math::hypot(Math::hypot(X, Y), Z) : 1;
|
|
205
|
+
if (gradp) {
|
|
206
|
+
// initial values to suppress warnings
|
|
207
|
+
deltaX = deltaY = deltaZ = 0;
|
|
208
|
+
T = _disturbing(-1, X, Y, Z, deltaX, deltaY, deltaZ);
|
|
209
|
+
real f = _GMmodel / _amodel;
|
|
210
|
+
deltaX *= f;
|
|
211
|
+
deltaY *= f;
|
|
212
|
+
deltaZ *= f;
|
|
213
|
+
if (correct) {
|
|
214
|
+
invR = _GMmodel * _dzonal0 * invR * invR * invR;
|
|
215
|
+
deltaX += X * invR;
|
|
216
|
+
deltaY += Y * invR;
|
|
217
|
+
deltaZ += Z * invR;
|
|
218
|
+
}
|
|
219
|
+
} else
|
|
220
|
+
T = _disturbing(-1, X, Y, Z);
|
|
221
|
+
T = (T / _amodel - (correct ? _dzonal0 : 0) * invR) * _GMmodel;
|
|
222
|
+
return T;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
Math::real GravityModel::V(real X, real Y, real Z,
|
|
226
|
+
real& GX, real& GY, real& GZ) const {
|
|
227
|
+
real
|
|
228
|
+
Vres = _gravitational(X, Y, Z, GX, GY, GZ),
|
|
229
|
+
f = _GMmodel / _amodel;
|
|
230
|
+
Vres *= f;
|
|
231
|
+
GX *= f;
|
|
232
|
+
GY *= f;
|
|
233
|
+
GZ *= f;
|
|
234
|
+
return Vres;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
Math::real GravityModel::W(real X, real Y, real Z,
|
|
238
|
+
real& gX, real& gY, real& gZ) const {
|
|
239
|
+
real fX, fY,
|
|
240
|
+
Wres = V(X, Y, Z, gX, gY, gZ) + _earth.Phi(X, Y, fX, fY);
|
|
241
|
+
gX += fX;
|
|
242
|
+
gY += fY;
|
|
243
|
+
return Wres;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
void GravityModel::SphericalAnomaly(real lat, real lon, real h,
|
|
247
|
+
real& Dg01, real& xi, real& eta)
|
|
248
|
+
const {
|
|
249
|
+
real X, Y, Z, M[Geocentric::dim2_];
|
|
250
|
+
_earth.Earth().IntForward(lat, lon, h, X, Y, Z, M);
|
|
251
|
+
real
|
|
252
|
+
deltax, deltay, deltaz,
|
|
253
|
+
T = InternalT(X, Y, Z, deltax, deltay, deltaz, true, false),
|
|
254
|
+
clam = M[3], slam = -M[0],
|
|
255
|
+
P = Math::hypot(X, Y),
|
|
256
|
+
R = Math::hypot(P, Z),
|
|
257
|
+
// psi is geocentric latitude
|
|
258
|
+
cpsi = R ? P / R : M[7],
|
|
259
|
+
spsi = R ? Z / R : M[8];
|
|
260
|
+
// Rotate cartesian into spherical coordinates
|
|
261
|
+
real MC[Geocentric::dim2_];
|
|
262
|
+
Geocentric::Rotation(spsi, cpsi, slam, clam, MC);
|
|
263
|
+
Geocentric::Unrotate(MC, deltax, deltay, deltaz, deltax, deltay, deltaz);
|
|
264
|
+
// H+M, Eq 2-151c
|
|
265
|
+
Dg01 = - deltaz - 2 * T / R;
|
|
266
|
+
real gammaX, gammaY, gammaZ;
|
|
267
|
+
_earth.U(X, Y, Z, gammaX, gammaY, gammaZ);
|
|
268
|
+
real gamma = Math::hypot( Math::hypot(gammaX, gammaY), gammaZ);
|
|
269
|
+
xi = -(deltay/gamma) / Math::degree();
|
|
270
|
+
eta = -(deltax/gamma) / Math::degree();
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
Math::real GravityModel::GeoidHeight(real lat, real lon) const
|
|
274
|
+
{
|
|
275
|
+
real X, Y, Z;
|
|
276
|
+
_earth.Earth().IntForward(lat, lon, 0, X, Y, Z, NULL);
|
|
277
|
+
real
|
|
278
|
+
gamma0 = _earth.SurfaceGravity(lat),
|
|
279
|
+
dummy,
|
|
280
|
+
T = InternalT(X, Y, Z, dummy, dummy, dummy, false, false),
|
|
281
|
+
invR = 1 / Math::hypot(Math::hypot(X, Y), Z),
|
|
282
|
+
correction = _corrmult * _correction(invR * X, invR * Y, invR * Z);
|
|
283
|
+
// _zeta0 has been included in _correction
|
|
284
|
+
return T/gamma0 + correction;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
Math::real GravityModel::Gravity(real lat, real lon, real h,
|
|
288
|
+
real& gx, real& gy, real& gz) const {
|
|
289
|
+
real X, Y, Z, M[Geocentric::dim2_];
|
|
290
|
+
_earth.Earth().IntForward(lat, lon, h, X, Y, Z, M);
|
|
291
|
+
real Wres = W(X, Y, Z, gx, gy, gz);
|
|
292
|
+
Geocentric::Unrotate(M, gx, gy, gz, gx, gy, gz);
|
|
293
|
+
return Wres;
|
|
294
|
+
}
|
|
295
|
+
Math::real GravityModel::Disturbance(real lat, real lon, real h,
|
|
296
|
+
real& deltax, real& deltay, real& deltaz)
|
|
297
|
+
const {
|
|
298
|
+
real X, Y, Z, M[Geocentric::dim2_];
|
|
299
|
+
_earth.Earth().IntForward(lat, lon, h, X, Y, Z, M);
|
|
300
|
+
real Tres = InternalT(X, Y, Z, deltax, deltay, deltaz, true, true);
|
|
301
|
+
Geocentric::Unrotate(M, deltax, deltay, deltaz, deltax, deltay, deltaz);
|
|
302
|
+
return Tres;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
GravityCircle GravityModel::Circle(real lat, real h, unsigned caps) const {
|
|
306
|
+
if (h != 0)
|
|
307
|
+
// Disallow invoking GeoidHeight unless h is zero.
|
|
308
|
+
caps &= ~(CAP_GAMMA0 | CAP_C);
|
|
309
|
+
real X, Y, Z, M[Geocentric::dim2_];
|
|
310
|
+
_earth.Earth().IntForward(lat, 0, h, X, Y, Z, M);
|
|
311
|
+
// Y = 0, cphi = M[7], sphi = M[8];
|
|
312
|
+
real
|
|
313
|
+
invR = 1 / Math::hypot(X, Z),
|
|
314
|
+
gamma0 = (caps & CAP_GAMMA0 ?_earth.SurfaceGravity(lat)
|
|
315
|
+
: Math::NaN()),
|
|
316
|
+
fx, fy, fz, gamma;
|
|
317
|
+
if (caps & CAP_GAMMA) {
|
|
318
|
+
_earth.U(X, Y, Z, fx, fy, fz); // fy = 0
|
|
319
|
+
gamma = Math::hypot(fx, fz);
|
|
320
|
+
} else
|
|
321
|
+
gamma = Math::NaN();
|
|
322
|
+
_earth.Phi(X, Y, fx, fy);
|
|
323
|
+
return GravityCircle(GravityCircle::mask(caps),
|
|
324
|
+
_earth._a, _earth._f, lat, h, Z, X, M[7], M[8],
|
|
325
|
+
_amodel, _GMmodel, _dzonal0, _corrmult,
|
|
326
|
+
gamma0, gamma, fx,
|
|
327
|
+
caps & CAP_G ?
|
|
328
|
+
_gravitational.Circle(X, Z, true) :
|
|
329
|
+
CircularEngine(),
|
|
330
|
+
// N.B. If CAP_DELTA is set then CAP_T should be too.
|
|
331
|
+
caps & CAP_T ?
|
|
332
|
+
_disturbing.Circle(-1, X, Z, (caps & CAP_DELTA) != 0) :
|
|
333
|
+
CircularEngine(),
|
|
334
|
+
caps & CAP_C ?
|
|
335
|
+
_correction.Circle(invR * X, invR * Z, false) :
|
|
336
|
+
CircularEngine());
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
std::string GravityModel::DefaultGravityPath() {
|
|
340
|
+
string path;
|
|
341
|
+
char* gravitypath = getenv("GEOGRAPHICLIB_GRAVITY_PATH");
|
|
342
|
+
if (gravitypath)
|
|
343
|
+
path = string(gravitypath);
|
|
344
|
+
if (!path.empty())
|
|
345
|
+
return path;
|
|
346
|
+
char* datapath = getenv("GEOGRAPHICLIB_DATA");
|
|
347
|
+
if (datapath)
|
|
348
|
+
path = string(datapath);
|
|
349
|
+
return (!path.empty() ? path : string(GEOGRAPHICLIB_DATA)) + "/gravity";
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
std::string GravityModel::DefaultGravityName() {
|
|
353
|
+
string name;
|
|
354
|
+
char* gravityname = getenv("GEOGRAPHICLIB_GRAVITY_NAME");
|
|
355
|
+
if (gravityname)
|
|
356
|
+
name = string(gravityname);
|
|
357
|
+
return !name.empty() ? name : string(GEOGRAPHICLIB_GRAVITY_DEFAULT_NAME);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
} // namespace GeographicLib
|