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,41 @@
|
|
1
|
+
/**
|
2
|
+
* \file AzimuthalEquidistant.cpp
|
3
|
+
* \brief Implementation for GeographicLib::AzimuthalEquidistant class
|
4
|
+
*
|
5
|
+
* Copyright (c) Charles Karney (2009-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/AzimuthalEquidistant.hpp>
|
11
|
+
|
12
|
+
namespace GeographicLib {
|
13
|
+
|
14
|
+
using namespace std;
|
15
|
+
|
16
|
+
AzimuthalEquidistant::AzimuthalEquidistant(const Geodesic& earth)
|
17
|
+
: eps_(real(0.01) * sqrt(numeric_limits<real>::min()))
|
18
|
+
, _earth(earth) {}
|
19
|
+
|
20
|
+
void AzimuthalEquidistant::Forward(real lat0, real lon0, real lat, real lon,
|
21
|
+
real& x, real& y, real& azi, real& rk)
|
22
|
+
const {
|
23
|
+
real sig, s, azi0, m;
|
24
|
+
sig = _earth.Inverse(lat0, lon0, lat, lon, s, azi0, azi, m);
|
25
|
+
Math::sincosd(azi0, x, y);
|
26
|
+
x *= s; y *= s;
|
27
|
+
rk = !(sig <= eps_) ? m / s : 1;
|
28
|
+
}
|
29
|
+
|
30
|
+
void AzimuthalEquidistant::Reverse(real lat0, real lon0, real x, real y,
|
31
|
+
real& lat, real& lon, real& azi, real& rk)
|
32
|
+
const {
|
33
|
+
real
|
34
|
+
azi0 = Math::atan2d(x, y),
|
35
|
+
s = Math::hypot(x, y);
|
36
|
+
real sig, m;
|
37
|
+
sig = _earth.Direct(lat0, lon0, azi0, s, lat, lon, azi, m);
|
38
|
+
rk = !(sig <= eps_) ? m / s : 1;
|
39
|
+
}
|
40
|
+
|
41
|
+
} // namespace GeographicLib
|
@@ -0,0 +1,89 @@
|
|
1
|
+
/**
|
2
|
+
* \file CassiniSoldner.cpp
|
3
|
+
* \brief Implementation for GeographicLib::CassiniSoldner class
|
4
|
+
*
|
5
|
+
* Copyright (c) Charles Karney (2009-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/CassiniSoldner.hpp>
|
11
|
+
|
12
|
+
namespace GeographicLib {
|
13
|
+
|
14
|
+
using namespace std;
|
15
|
+
|
16
|
+
CassiniSoldner::CassiniSoldner(const Geodesic& earth)
|
17
|
+
: _earth(earth) {}
|
18
|
+
|
19
|
+
CassiniSoldner::CassiniSoldner(real lat0, real lon0, const Geodesic& earth)
|
20
|
+
: _earth(earth)
|
21
|
+
{ Reset(lat0, lon0); }
|
22
|
+
|
23
|
+
void CassiniSoldner::Reset(real lat0, real lon0) {
|
24
|
+
_meridian = _earth.Line(lat0, lon0, real(0),
|
25
|
+
Geodesic::LATITUDE | Geodesic::LONGITUDE |
|
26
|
+
Geodesic::DISTANCE | Geodesic::DISTANCE_IN |
|
27
|
+
Geodesic::AZIMUTH);
|
28
|
+
real f = _earth.Flattening();
|
29
|
+
Math::sincosd(LatitudeOrigin(), _sbet0, _cbet0);
|
30
|
+
_sbet0 *= (1 - f);
|
31
|
+
Math::norm(_sbet0, _cbet0);
|
32
|
+
}
|
33
|
+
|
34
|
+
void CassiniSoldner::Forward(real lat, real lon, real& x, real& y,
|
35
|
+
real& azi, real& rk) const {
|
36
|
+
if (!Init())
|
37
|
+
return;
|
38
|
+
real dlon = Math::AngDiff(LongitudeOrigin(), lon);
|
39
|
+
real sig12, s12, azi1, azi2;
|
40
|
+
sig12 = _earth.Inverse(lat, -abs(dlon), lat, abs(dlon), s12, azi1, azi2);
|
41
|
+
sig12 *= real(0.5);
|
42
|
+
s12 *= real(0.5);
|
43
|
+
if (s12 == 0) {
|
44
|
+
real da = Math::AngDiff(azi1, azi2)/2;
|
45
|
+
if (abs(dlon) <= 90) {
|
46
|
+
azi1 = 90 - da;
|
47
|
+
azi2 = 90 + da;
|
48
|
+
} else {
|
49
|
+
azi1 = -90 - da;
|
50
|
+
azi2 = -90 + da;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
if (dlon < 0) {
|
54
|
+
azi2 = azi1;
|
55
|
+
s12 = -s12;
|
56
|
+
sig12 = -sig12;
|
57
|
+
}
|
58
|
+
x = s12;
|
59
|
+
azi = Math::AngNormalize(azi2);
|
60
|
+
GeodesicLine perp(_earth.Line(lat, dlon, azi, Geodesic::GEODESICSCALE));
|
61
|
+
real t;
|
62
|
+
perp.GenPosition(true, -sig12,
|
63
|
+
Geodesic::GEODESICSCALE,
|
64
|
+
t, t, t, t, t, t, rk, t);
|
65
|
+
|
66
|
+
real salp0, calp0;
|
67
|
+
Math::sincosd(perp.EquatorialAzimuth(), salp0, calp0);
|
68
|
+
real
|
69
|
+
sbet1 = lat >=0 ? calp0 : -calp0,
|
70
|
+
cbet1 = abs(dlon) <= 90 ? abs(salp0) : -abs(salp0),
|
71
|
+
sbet01 = sbet1 * _cbet0 - cbet1 * _sbet0,
|
72
|
+
cbet01 = cbet1 * _cbet0 + sbet1 * _sbet0,
|
73
|
+
sig01 = atan2(sbet01, cbet01) / Math::degree();
|
74
|
+
_meridian.GenPosition(true, sig01,
|
75
|
+
Geodesic::DISTANCE,
|
76
|
+
t, t, t, y, t, t, t, t);
|
77
|
+
}
|
78
|
+
|
79
|
+
void CassiniSoldner::Reverse(real x, real y, real& lat, real& lon,
|
80
|
+
real& azi, real& rk) const {
|
81
|
+
if (!Init())
|
82
|
+
return;
|
83
|
+
real lat1, lon1;
|
84
|
+
real azi0, t;
|
85
|
+
_meridian.Position(y, lat1, lon1, azi0);
|
86
|
+
_earth.Direct(lat1, lon1, azi0 + 90, x, lat, lon, azi, rk, t);
|
87
|
+
}
|
88
|
+
|
89
|
+
} // namespace GeographicLib
|
@@ -0,0 +1,96 @@
|
|
1
|
+
/**
|
2
|
+
* \file CircularEngine.cpp
|
3
|
+
* \brief Implementation for GeographicLib::CircularEngine class
|
4
|
+
*
|
5
|
+
* Copyright (c) Charles Karney (2011) <charles@karney.com> and licensed under
|
6
|
+
* the MIT/X11 License. For more information, see
|
7
|
+
* http://geographiclib.sourceforge.net/
|
8
|
+
**********************************************************************/
|
9
|
+
|
10
|
+
#include <GeographicLib/CircularEngine.hpp>
|
11
|
+
|
12
|
+
namespace GeographicLib {
|
13
|
+
|
14
|
+
using namespace std;
|
15
|
+
|
16
|
+
Math::real CircularEngine::Value(bool gradp, real sl, real cl,
|
17
|
+
real& gradx, real& grady, real& gradz)
|
18
|
+
const {
|
19
|
+
gradp = _gradp && gradp;
|
20
|
+
const vector<real>& root_( SphericalEngine::root_ );
|
21
|
+
|
22
|
+
// Initialize outer sum
|
23
|
+
real vc = 0, vc2 = 0, vs = 0, vs2 = 0; // v [N + 1], v [N + 2]
|
24
|
+
// vr, vt, vl and similar w variable accumulate the sums for the
|
25
|
+
// derivatives wrt r, theta, and lambda, respectively.
|
26
|
+
real vrc = 0, vrc2 = 0, vrs = 0, vrs2 = 0; // vr[N + 1], vr[N + 2]
|
27
|
+
real vtc = 0, vtc2 = 0, vts = 0, vts2 = 0; // vt[N + 1], vt[N + 2]
|
28
|
+
real vlc = 0, vlc2 = 0, vls = 0, vls2 = 0; // vl[N + 1], vl[N + 2]
|
29
|
+
for (int m = _M; m >= 0; --m) { // m = M .. 0
|
30
|
+
// Now Sc[m] = wc, Ss[m] = ws
|
31
|
+
// Sc'[m] = wtc, Ss'[m] = wtc
|
32
|
+
if (m) {
|
33
|
+
real v, A, B; // alpha[m], beta[m + 1]
|
34
|
+
switch (_norm) {
|
35
|
+
case FULL:
|
36
|
+
v = root_[2] * root_[2 * m + 3] / root_[m + 1];
|
37
|
+
A = cl * v * _uq;
|
38
|
+
B = - v * root_[2 * m + 5] / (root_[8] * root_[m + 2]) * _uq2;
|
39
|
+
break;
|
40
|
+
case SCHMIDT:
|
41
|
+
v = root_[2] * root_[2 * m + 1] / root_[m + 1];
|
42
|
+
A = cl * v * _uq;
|
43
|
+
B = - v * root_[2 * m + 3] / (root_[8] * root_[m + 2]) * _uq2;
|
44
|
+
break;
|
45
|
+
default:
|
46
|
+
A = B = 0;
|
47
|
+
}
|
48
|
+
v = A * vc + B * vc2 + _wc[m] ; vc2 = vc ; vc = v;
|
49
|
+
v = A * vs + B * vs2 + _ws[m] ; vs2 = vs ; vs = v;
|
50
|
+
if (gradp) {
|
51
|
+
v = A * vrc + B * vrc2 + _wrc[m]; vrc2 = vrc; vrc = v;
|
52
|
+
v = A * vrs + B * vrs2 + _wrs[m]; vrs2 = vrs; vrs = v;
|
53
|
+
v = A * vtc + B * vtc2 + _wtc[m]; vtc2 = vtc; vtc = v;
|
54
|
+
v = A * vts + B * vts2 + _wts[m]; vts2 = vts; vts = v;
|
55
|
+
v = A * vlc + B * vlc2 + m*_ws[m]; vlc2 = vlc; vlc = v;
|
56
|
+
v = A * vls + B * vls2 - m*_wc[m]; vls2 = vls; vls = v;
|
57
|
+
}
|
58
|
+
} else {
|
59
|
+
real A, B, qs;
|
60
|
+
switch (_norm) {
|
61
|
+
case FULL:
|
62
|
+
A = root_[3] * _uq; // F[1]/(q*cl) or F[1]/(q*sl)
|
63
|
+
B = - root_[15]/2 * _uq2; // beta[1]/q
|
64
|
+
break;
|
65
|
+
case SCHMIDT:
|
66
|
+
A = _uq;
|
67
|
+
B = - root_[3]/2 * _uq2;
|
68
|
+
break;
|
69
|
+
default:
|
70
|
+
A = B = 0;
|
71
|
+
}
|
72
|
+
qs = _q / SphericalEngine::scale();
|
73
|
+
vc = qs * (_wc[m] + A * (cl * vc + sl * vs ) + B * vc2);
|
74
|
+
if (gradp) {
|
75
|
+
qs /= _r;
|
76
|
+
// The components of the gradient in circular coordinates are
|
77
|
+
// r: dV/dr
|
78
|
+
// theta: 1/r * dV/dtheta
|
79
|
+
// lambda: 1/(r*u) * dV/dlambda
|
80
|
+
vrc = - qs * (_wrc[m] + A * (cl * vrc + sl * vrs) + B * vrc2);
|
81
|
+
vtc = qs * (_wtc[m] + A * (cl * vtc + sl * vts) + B * vtc2);
|
82
|
+
vlc = qs / _u * ( A * (cl * vlc + sl * vls) + B * vlc2);
|
83
|
+
}
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
if (gradp) {
|
88
|
+
// Rotate into cartesian (geocentric) coordinates
|
89
|
+
gradx = cl * (_u * vrc + _t * vtc) - sl * vlc;
|
90
|
+
grady = sl * (_u * vrc + _t * vtc) + cl * vlc;
|
91
|
+
gradz = _t * vrc - _u * vtc ;
|
92
|
+
}
|
93
|
+
return vc;
|
94
|
+
}
|
95
|
+
|
96
|
+
} // namespace GeographicLib
|
@@ -0,0 +1,381 @@
|
|
1
|
+
/**
|
2
|
+
* \file DMS.cpp
|
3
|
+
* \brief Implementation for GeographicLib::DMS class
|
4
|
+
*
|
5
|
+
* Copyright (c) Charles Karney (2008-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/DMS.hpp>
|
11
|
+
#include <GeographicLib/Utility.hpp>
|
12
|
+
|
13
|
+
#if defined(_MSC_VER)
|
14
|
+
// Squelch warnings about constant conditional expressions
|
15
|
+
# pragma warning (disable: 4127)
|
16
|
+
#endif
|
17
|
+
|
18
|
+
namespace GeographicLib {
|
19
|
+
|
20
|
+
using namespace std;
|
21
|
+
|
22
|
+
const string DMS::hemispheres_ = "SNWE";
|
23
|
+
const string DMS::signs_ = "-+";
|
24
|
+
const string DMS::digits_ = "0123456789";
|
25
|
+
const string DMS::dmsindicators_ = "D'\":";
|
26
|
+
const string DMS::components_[] = {"degrees", "minutes", "seconds"};
|
27
|
+
|
28
|
+
Math::real DMS::Decode(const std::string& dms, flag& ind) {
|
29
|
+
string dmsa = dms;
|
30
|
+
replace(dmsa, "\xc2\xb0", 'd'); // U+00b0 degree symbol
|
31
|
+
replace(dmsa, "\xc2\xba", 'd'); // U+00ba alt symbol
|
32
|
+
replace(dmsa, "\xe2\x81\xb0", 'd'); // U+2070 sup zero
|
33
|
+
replace(dmsa, "\xcb\x9a", 'd'); // U+02da ring above
|
34
|
+
replace(dmsa, "\xe2\x80\xb2", '\''); // U+2032 prime
|
35
|
+
replace(dmsa, "\xc2\xb4", '\''); // U+00b4 acute accent
|
36
|
+
replace(dmsa, "\xe2\x80\x99", '\''); // U+2019 right single quote
|
37
|
+
replace(dmsa, "\xe2\x80\xb3", '"'); // U+2033 double prime
|
38
|
+
replace(dmsa, "\xe2\x80\x9d", '"'); // U+201d right double quote
|
39
|
+
replace(dmsa, "\xe2\x88\x92", '-'); // U+2212 minus sign
|
40
|
+
replace(dmsa, "\xb0", 'd'); // 0xb0 bare degree symbol
|
41
|
+
replace(dmsa, "\xba", 'd'); // 0xba bare alt symbol
|
42
|
+
replace(dmsa, "\xb4", '\''); // 0xb4 bare acute accent
|
43
|
+
replace(dmsa, "''", '"'); // '' -> "
|
44
|
+
string::size_type
|
45
|
+
beg = 0,
|
46
|
+
end = unsigned(dmsa.size());
|
47
|
+
while (beg < end && isspace(dmsa[beg]))
|
48
|
+
++beg;
|
49
|
+
while (beg < end && isspace(dmsa[end - 1]))
|
50
|
+
--end;
|
51
|
+
// The trimmed string in [beg, end)
|
52
|
+
real v = 0;
|
53
|
+
int i = 0;
|
54
|
+
flag ind1 = NONE;
|
55
|
+
// p is pointer to the next piece that needs decoding
|
56
|
+
for (string::size_type p = beg, pb; p < end; p = pb, ++i) {
|
57
|
+
string::size_type pa = p;
|
58
|
+
// Skip over initial hemisphere letter (for i == 0)
|
59
|
+
if (i == 0 && Utility::lookup(hemispheres_, dmsa[pa]) >= 0)
|
60
|
+
++pa;
|
61
|
+
// Skip over initial sign (checking for it if i == 0)
|
62
|
+
if (i > 0 || (pa < end && Utility::lookup(signs_, dmsa[pa]) >= 0))
|
63
|
+
++pa;
|
64
|
+
// Find next sign
|
65
|
+
pb = min(dmsa.find_first_of(signs_, pa), end);
|
66
|
+
flag ind2 = NONE;
|
67
|
+
v += InternalDecode(dmsa.substr(p, pb - p), ind2);
|
68
|
+
if (ind1 == NONE)
|
69
|
+
ind1 = ind2;
|
70
|
+
else if (!(ind2 == NONE || ind1 == ind2))
|
71
|
+
throw GeographicErr("Incompatible hemisphere specifies in " +
|
72
|
+
dmsa.substr(beg, pb - beg));
|
73
|
+
}
|
74
|
+
if (i == 0)
|
75
|
+
throw GeographicErr("Empty or incomplete DMS string " +
|
76
|
+
dmsa.substr(beg, end - beg));
|
77
|
+
ind = ind1;
|
78
|
+
return v;
|
79
|
+
}
|
80
|
+
|
81
|
+
Math::real DMS::InternalDecode(const std::string& dmsa, flag& ind) {
|
82
|
+
string errormsg;
|
83
|
+
do { // Executed once (provides the ability to break)
|
84
|
+
int sign = 1;
|
85
|
+
unsigned
|
86
|
+
beg = 0,
|
87
|
+
end = unsigned(dmsa.size());
|
88
|
+
flag ind1 = NONE;
|
89
|
+
int k = -1;
|
90
|
+
if (end > beg && (k = Utility::lookup(hemispheres_, dmsa[beg])) >= 0) {
|
91
|
+
ind1 = (k / 2) ? LONGITUDE : LATITUDE;
|
92
|
+
sign = k % 2 ? 1 : -1;
|
93
|
+
++beg;
|
94
|
+
}
|
95
|
+
if (end > beg && (k = Utility::lookup(hemispheres_, dmsa[end-1])) >= 0) {
|
96
|
+
if (k >= 0) {
|
97
|
+
if (ind1 != NONE) {
|
98
|
+
if (toupper(dmsa[beg - 1]) == toupper(dmsa[end - 1]))
|
99
|
+
errormsg = "Repeated hemisphere indicators "
|
100
|
+
+ Utility::str(dmsa[beg - 1])
|
101
|
+
+ " in " + dmsa.substr(beg - 1, end - beg + 1);
|
102
|
+
else
|
103
|
+
errormsg = "Contradictory hemisphere indicators "
|
104
|
+
+ Utility::str(dmsa[beg - 1]) + " and "
|
105
|
+
+ Utility::str(dmsa[end - 1]) + " in "
|
106
|
+
+ dmsa.substr(beg - 1, end - beg + 1);
|
107
|
+
break;
|
108
|
+
}
|
109
|
+
ind1 = (k / 2) ? LONGITUDE : LATITUDE;
|
110
|
+
sign = k % 2 ? 1 : -1;
|
111
|
+
--end;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
if (end > beg && (k = Utility::lookup(signs_, dmsa[beg])) >= 0) {
|
115
|
+
if (k >= 0) {
|
116
|
+
sign *= k ? 1 : -1;
|
117
|
+
++beg;
|
118
|
+
}
|
119
|
+
}
|
120
|
+
if (end == beg) {
|
121
|
+
errormsg = "Empty or incomplete DMS string " + dmsa;
|
122
|
+
break;
|
123
|
+
}
|
124
|
+
real ipieces[] = {0, 0, 0};
|
125
|
+
real fpieces[] = {0, 0, 0};
|
126
|
+
unsigned npiece = 0;
|
127
|
+
real icurrent = 0;
|
128
|
+
real fcurrent = 0;
|
129
|
+
unsigned ncurrent = 0, p = beg;
|
130
|
+
bool pointseen = false;
|
131
|
+
unsigned digcount = 0, intcount = 0;
|
132
|
+
while (p < end) {
|
133
|
+
char x = dmsa[p++];
|
134
|
+
if ((k = Utility::lookup(digits_, x)) >= 0) {
|
135
|
+
++ncurrent;
|
136
|
+
if (digcount > 0)
|
137
|
+
++digcount; // Count of decimal digits
|
138
|
+
else {
|
139
|
+
icurrent = 10 * icurrent + k;
|
140
|
+
++intcount;
|
141
|
+
}
|
142
|
+
} else if (x == '.') {
|
143
|
+
if (pointseen) {
|
144
|
+
errormsg = "Multiple decimal points in "
|
145
|
+
+ dmsa.substr(beg, end - beg);
|
146
|
+
break;
|
147
|
+
}
|
148
|
+
pointseen = true;
|
149
|
+
digcount = 1;
|
150
|
+
} else if ((k = Utility::lookup(dmsindicators_, x)) >= 0) {
|
151
|
+
if (k >= 3) {
|
152
|
+
if (p == end) {
|
153
|
+
errormsg = "Illegal for : to appear at the end of " +
|
154
|
+
dmsa.substr(beg, end - beg);
|
155
|
+
break;
|
156
|
+
}
|
157
|
+
k = npiece;
|
158
|
+
}
|
159
|
+
if (unsigned(k) == npiece - 1) {
|
160
|
+
errormsg = "Repeated " + components_[k] +
|
161
|
+
" component in " + dmsa.substr(beg, end - beg);
|
162
|
+
break;
|
163
|
+
} else if (unsigned(k) < npiece) {
|
164
|
+
errormsg = components_[k] + " component follows "
|
165
|
+
+ components_[npiece - 1] + " component in "
|
166
|
+
+ dmsa.substr(beg, end - beg);
|
167
|
+
break;
|
168
|
+
}
|
169
|
+
if (ncurrent == 0) {
|
170
|
+
errormsg = "Missing numbers in " + components_[k] +
|
171
|
+
" component of " + dmsa.substr(beg, end - beg);
|
172
|
+
break;
|
173
|
+
}
|
174
|
+
if (digcount > 0) {
|
175
|
+
istringstream s(dmsa.substr(p - intcount - digcount - 1,
|
176
|
+
intcount + digcount));
|
177
|
+
s >> fcurrent;
|
178
|
+
icurrent = 0;
|
179
|
+
}
|
180
|
+
ipieces[k] = icurrent;
|
181
|
+
fpieces[k] = icurrent + fcurrent;
|
182
|
+
if (p < end) {
|
183
|
+
npiece = k + 1;
|
184
|
+
icurrent = fcurrent = 0;
|
185
|
+
ncurrent = digcount = intcount = 0;
|
186
|
+
}
|
187
|
+
} else if (Utility::lookup(signs_, x) >= 0) {
|
188
|
+
errormsg = "Internal sign in DMS string "
|
189
|
+
+ dmsa.substr(beg, end - beg);
|
190
|
+
break;
|
191
|
+
} else {
|
192
|
+
errormsg = "Illegal character " + Utility::str(x) + " in DMS string "
|
193
|
+
+ dmsa.substr(beg, end - beg);
|
194
|
+
break;
|
195
|
+
}
|
196
|
+
}
|
197
|
+
if (!errormsg.empty())
|
198
|
+
break;
|
199
|
+
if (Utility::lookup(dmsindicators_, dmsa[p - 1]) < 0) {
|
200
|
+
if (npiece >= 3) {
|
201
|
+
errormsg = "Extra text following seconds in DMS string "
|
202
|
+
+ dmsa.substr(beg, end - beg);
|
203
|
+
break;
|
204
|
+
}
|
205
|
+
if (ncurrent == 0) {
|
206
|
+
errormsg = "Missing numbers in trailing component of "
|
207
|
+
+ dmsa.substr(beg, end - beg);
|
208
|
+
break;
|
209
|
+
}
|
210
|
+
if (digcount > 0) {
|
211
|
+
istringstream s(dmsa.substr(p - intcount - digcount,
|
212
|
+
intcount + digcount));
|
213
|
+
s >> fcurrent;
|
214
|
+
icurrent = 0;
|
215
|
+
}
|
216
|
+
ipieces[npiece] = icurrent;
|
217
|
+
fpieces[npiece] = icurrent + fcurrent;
|
218
|
+
}
|
219
|
+
if (pointseen && digcount == 0) {
|
220
|
+
errormsg = "Decimal point in non-terminal component of "
|
221
|
+
+ dmsa.substr(beg, end - beg);
|
222
|
+
break;
|
223
|
+
}
|
224
|
+
// Note that we accept 59.999999... even though it rounds to 60.
|
225
|
+
if (ipieces[1] >= 60 || fpieces[1] > 60 ) {
|
226
|
+
errormsg = "Minutes " + Utility::str(fpieces[1])
|
227
|
+
+ " not in range [0, 60)";
|
228
|
+
break;
|
229
|
+
}
|
230
|
+
if (ipieces[2] >= 60 || fpieces[2] > 60) {
|
231
|
+
errormsg = "Seconds " + Utility::str(fpieces[2])
|
232
|
+
+ " not in range [0, 60)";
|
233
|
+
break;
|
234
|
+
}
|
235
|
+
ind = ind1;
|
236
|
+
// Assume check on range of result is made by calling routine (which
|
237
|
+
// might be able to offer a better diagnostic).
|
238
|
+
return real(sign) *
|
239
|
+
( fpieces[2] ? (60*(60*fpieces[0] + fpieces[1]) + fpieces[2]) / 3600 :
|
240
|
+
( fpieces[1] ? (60*fpieces[0] + fpieces[1]) / 60 : fpieces[0] ) );
|
241
|
+
} while (false);
|
242
|
+
real val = Utility::nummatch<real>(dmsa);
|
243
|
+
if (val == 0)
|
244
|
+
throw GeographicErr(errormsg);
|
245
|
+
else
|
246
|
+
ind = NONE;
|
247
|
+
return val;
|
248
|
+
}
|
249
|
+
|
250
|
+
void DMS::DecodeLatLon(const std::string& stra, const std::string& strb,
|
251
|
+
real& lat, real& lon,
|
252
|
+
bool longfirst) {
|
253
|
+
real a, b;
|
254
|
+
flag ia, ib;
|
255
|
+
a = Decode(stra, ia);
|
256
|
+
b = Decode(strb, ib);
|
257
|
+
if (ia == NONE && ib == NONE) {
|
258
|
+
// Default to lat, long unless longfirst
|
259
|
+
ia = longfirst ? LONGITUDE : LATITUDE;
|
260
|
+
ib = longfirst ? LATITUDE : LONGITUDE;
|
261
|
+
} else if (ia == NONE)
|
262
|
+
ia = flag(LATITUDE + LONGITUDE - ib);
|
263
|
+
else if (ib == NONE)
|
264
|
+
ib = flag(LATITUDE + LONGITUDE - ia);
|
265
|
+
if (ia == ib)
|
266
|
+
throw GeographicErr("Both " + stra + " and "
|
267
|
+
+ strb + " interpreted as "
|
268
|
+
+ (ia == LATITUDE ? "latitudes" : "longitudes"));
|
269
|
+
real
|
270
|
+
lat1 = ia == LATITUDE ? a : b,
|
271
|
+
lon1 = ia == LATITUDE ? b : a;
|
272
|
+
if (abs(lat1) > 90)
|
273
|
+
throw GeographicErr("Latitude " + Utility::str(lat1)
|
274
|
+
+ "d not in [-90d, 90d]");
|
275
|
+
lat = lat1;
|
276
|
+
lon = lon1;
|
277
|
+
}
|
278
|
+
|
279
|
+
Math::real DMS::DecodeAngle(const std::string& angstr) {
|
280
|
+
flag ind;
|
281
|
+
real ang = Decode(angstr, ind);
|
282
|
+
if (ind != NONE)
|
283
|
+
throw GeographicErr("Arc angle " + angstr
|
284
|
+
+ " includes a hemisphere, N/E/W/S");
|
285
|
+
return ang;
|
286
|
+
}
|
287
|
+
|
288
|
+
Math::real DMS::DecodeAzimuth(const std::string& azistr) {
|
289
|
+
flag ind;
|
290
|
+
real azi = Decode(azistr, ind);
|
291
|
+
if (ind == LATITUDE)
|
292
|
+
throw GeographicErr("Azimuth " + azistr
|
293
|
+
+ " has a latitude hemisphere, N/S");
|
294
|
+
return Math::AngNormalize(azi);
|
295
|
+
}
|
296
|
+
|
297
|
+
string DMS::Encode(real angle, component trailing, unsigned prec, flag ind,
|
298
|
+
char dmssep) {
|
299
|
+
// Assume check on range of input angle has been made by calling
|
300
|
+
// routine (which might be able to offer a better diagnostic).
|
301
|
+
if (!Math::isfinite(angle))
|
302
|
+
return angle < 0 ? string("-inf") :
|
303
|
+
(angle > 0 ? string("inf") : string("nan"));
|
304
|
+
|
305
|
+
// 15 - 2 * trailing = ceiling(log10(2^53/90/60^trailing)).
|
306
|
+
// This suffices to give full real precision for numbers in [-90,90]
|
307
|
+
prec = min(15 + Math::extra_digits() - 2 * unsigned(trailing), prec);
|
308
|
+
real scale = 1;
|
309
|
+
for (unsigned i = 0; i < unsigned(trailing); ++i)
|
310
|
+
scale *= 60;
|
311
|
+
for (unsigned i = 0; i < prec; ++i)
|
312
|
+
scale *= 10;
|
313
|
+
if (ind == AZIMUTH)
|
314
|
+
angle -= floor(angle/360) * 360;
|
315
|
+
int sign = angle < 0 ? -1 : 1;
|
316
|
+
angle *= sign;
|
317
|
+
|
318
|
+
// Break off integer part to preserve precision in manipulation of
|
319
|
+
// fractional part.
|
320
|
+
real
|
321
|
+
idegree = floor(angle),
|
322
|
+
fdegree = (angle - idegree) * scale + real(0.5);
|
323
|
+
{
|
324
|
+
// Implement the "round ties to even" rule
|
325
|
+
real f = floor(fdegree);
|
326
|
+
fdegree = (f == fdegree && fmod(f, real(2)) == 1) ? f - 1 : f;
|
327
|
+
}
|
328
|
+
fdegree /= scale;
|
329
|
+
if (fdegree >= 1) {
|
330
|
+
idegree += 1;
|
331
|
+
fdegree -= 1;
|
332
|
+
}
|
333
|
+
real pieces[3] = {fdegree, 0, 0};
|
334
|
+
for (unsigned i = 1; i <= unsigned(trailing); ++i) {
|
335
|
+
real
|
336
|
+
ip = floor(pieces[i - 1]),
|
337
|
+
fp = pieces[i - 1] - ip;
|
338
|
+
pieces[i] = fp * 60;
|
339
|
+
pieces[i - 1] = ip;
|
340
|
+
}
|
341
|
+
pieces[0] += idegree;
|
342
|
+
ostringstream s;
|
343
|
+
s << fixed << setfill('0');
|
344
|
+
if (ind == NONE && sign < 0)
|
345
|
+
s << '-';
|
346
|
+
switch (trailing) {
|
347
|
+
case DEGREE:
|
348
|
+
if (ind != NONE)
|
349
|
+
s << setw(1 + min(int(ind), 2) + prec + (prec ? 1 : 0));
|
350
|
+
s << Utility::str(pieces[0], prec);
|
351
|
+
// Don't include degree designator (d) if it is the trailing component.
|
352
|
+
break;
|
353
|
+
default:
|
354
|
+
if (ind != NONE)
|
355
|
+
s << setw(1 + min(int(ind), 2));
|
356
|
+
s << int(pieces[0])
|
357
|
+
<< (dmssep ? dmssep : char(tolower(dmsindicators_[0])));
|
358
|
+
switch (trailing) {
|
359
|
+
case MINUTE:
|
360
|
+
s << setw(2 + prec + (prec ? 1 : 0)) << Utility::str(pieces[1], prec);
|
361
|
+
if (!dmssep)
|
362
|
+
s << char(tolower(dmsindicators_[1]));
|
363
|
+
break;
|
364
|
+
case SECOND:
|
365
|
+
s << setw(2)
|
366
|
+
<< int(pieces[1])
|
367
|
+
<< (dmssep ? dmssep : char(tolower(dmsindicators_[1])))
|
368
|
+
<< setw(2 + prec + (prec ? 1 : 0)) << Utility::str(pieces[2], prec);
|
369
|
+
if (!dmssep)
|
370
|
+
s << char(tolower(dmsindicators_[2]));
|
371
|
+
break;
|
372
|
+
default:
|
373
|
+
break;
|
374
|
+
}
|
375
|
+
}
|
376
|
+
if (ind != NONE && ind != AZIMUTH)
|
377
|
+
s << hemispheres_[(ind == LATITUDE ? 0 : 2) + (sign < 0 ? 0 : 1)];
|
378
|
+
return s.str();
|
379
|
+
}
|
380
|
+
|
381
|
+
} // namespace GeographicLib
|