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,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* \file GARS.cpp
|
|
3
|
+
* \brief Implementation for GeographicLib::GARS 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/GARS.hpp>
|
|
11
|
+
#include <GeographicLib/Utility.hpp>
|
|
12
|
+
|
|
13
|
+
namespace GeographicLib {
|
|
14
|
+
|
|
15
|
+
using namespace std;
|
|
16
|
+
|
|
17
|
+
const string GARS::digits_ = "0123456789";
|
|
18
|
+
const string GARS::letters_ = "ABCDEFGHJKLMNPQRSTUVWXYZ";
|
|
19
|
+
|
|
20
|
+
void GARS::Forward(real lat, real lon, int prec, std::string& gars) {
|
|
21
|
+
if (abs(lat) > 90)
|
|
22
|
+
throw GeographicErr("Latitude " + Utility::str(lat)
|
|
23
|
+
+ "d not in [-90d, 90d]");
|
|
24
|
+
if (Math::isnan(lat) || Math::isnan(lon)) {
|
|
25
|
+
gars = "INVALID";
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
lon = Math::AngNormalize(lon); // lon in [-180,180)
|
|
29
|
+
if (lat == 90) lat *= (1 - numeric_limits<real>::epsilon() / 2);
|
|
30
|
+
prec = max(0, min(int(maxprec_), prec));
|
|
31
|
+
int
|
|
32
|
+
x = int(floor(lon * m_)) - lonorig_ * m_,
|
|
33
|
+
y = int(floor(lat * m_)) - latorig_ * m_,
|
|
34
|
+
ilon = x * mult1_ / m_,
|
|
35
|
+
ilat = y * mult1_ / m_;
|
|
36
|
+
x -= ilon * m_ / mult1_; y -= ilat * m_ / mult1_;
|
|
37
|
+
char gars1[maxlen_];
|
|
38
|
+
++ilon;
|
|
39
|
+
for (int c = lonlen_; c--;) {
|
|
40
|
+
gars1[c] = digits_[ ilon % baselon_]; ilon /= baselon_;
|
|
41
|
+
}
|
|
42
|
+
for (int c = latlen_; c--;) {
|
|
43
|
+
gars1[lonlen_ + c] = letters_[ilat % baselat_]; ilat /= baselat_;
|
|
44
|
+
}
|
|
45
|
+
if (prec > 0) {
|
|
46
|
+
ilon = x / mult3_; ilat = y / mult3_;
|
|
47
|
+
gars1[baselen_] = digits_[mult2_ * (mult2_ - 1 - ilat) + ilon + 1];
|
|
48
|
+
if (prec > 1) {
|
|
49
|
+
ilon = x % mult3_; ilat = y % mult3_;
|
|
50
|
+
gars1[baselen_ + 1] = digits_[mult3_ * (mult3_ - 1 - ilat) + ilon + 1];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
gars.resize(baselen_ + prec);
|
|
54
|
+
copy(gars1, gars1 + baselen_ + prec, gars.begin());
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
void GARS::Reverse(const std::string& gars, real& lat, real& lon,
|
|
58
|
+
int& prec, bool centerp) {
|
|
59
|
+
int len = int(gars.length());
|
|
60
|
+
if (len >= 3 &&
|
|
61
|
+
toupper(gars[0]) == 'I' &&
|
|
62
|
+
toupper(gars[1]) == 'N' &&
|
|
63
|
+
toupper(gars[2]) == 'V') {
|
|
64
|
+
lat = lon = Math::NaN();
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (len < baselen_)
|
|
68
|
+
throw GeographicErr("GARS must have at least 5 characters " + gars);
|
|
69
|
+
if (len > maxlen_)
|
|
70
|
+
throw GeographicErr("GARS can have at most 7 characters " + gars);
|
|
71
|
+
int prec1 = len - baselen_;
|
|
72
|
+
int ilon = 0;
|
|
73
|
+
for (int c = 0; c < lonlen_; ++c) {
|
|
74
|
+
int k = Utility::lookup(digits_, gars[c]);
|
|
75
|
+
if (k < 0)
|
|
76
|
+
throw GeographicErr("GARS must start with 3 digits " + gars);
|
|
77
|
+
ilon = ilon * baselon_ + k;
|
|
78
|
+
}
|
|
79
|
+
if (!(ilon >= 1 && ilon <= 720))
|
|
80
|
+
throw GeographicErr("Initial digits in GARS must lie in [1, 720] " +
|
|
81
|
+
gars);
|
|
82
|
+
--ilon;
|
|
83
|
+
int ilat = 0;
|
|
84
|
+
for (int c = 0; c < latlen_; ++c) {
|
|
85
|
+
int k = Utility::lookup(letters_, gars[lonlen_ + c]);
|
|
86
|
+
if (k < 0)
|
|
87
|
+
throw GeographicErr("Illegal letters in GARS " + gars.substr(3,2));
|
|
88
|
+
ilat = ilat * baselat_ + k;
|
|
89
|
+
}
|
|
90
|
+
if (!(ilat < 360))
|
|
91
|
+
throw GeographicErr("GARS letters must lie in [AA, QZ] " + gars);
|
|
92
|
+
real
|
|
93
|
+
unit = mult1_,
|
|
94
|
+
lat1 = ilat + latorig_ * unit,
|
|
95
|
+
lon1 = ilon + lonorig_ * unit;
|
|
96
|
+
if (prec1 > 0) {
|
|
97
|
+
int k = Utility::lookup(digits_, gars[baselen_]);
|
|
98
|
+
if (!(k >= 1 && k <= mult2_ * mult2_))
|
|
99
|
+
throw GeographicErr("6th character in GARS must [1, 4] " + gars);
|
|
100
|
+
--k;
|
|
101
|
+
unit *= mult2_;
|
|
102
|
+
lat1 = mult2_ * lat1 + (mult2_ - 1 - k / mult2_);
|
|
103
|
+
lon1 = mult2_ * lon1 + (k % mult2_);
|
|
104
|
+
if (prec1 > 1) {
|
|
105
|
+
k = Utility::lookup(digits_, gars[baselen_ + 1]);
|
|
106
|
+
if (!(k >= 1 /* && k <= mult3_ * mult3_ */))
|
|
107
|
+
throw GeographicErr("7th character in GARS must [1, 9] " + gars);
|
|
108
|
+
--k;
|
|
109
|
+
unit *= mult3_;
|
|
110
|
+
lat1 = mult3_ * lat1 + (mult3_ - 1 - k / mult3_);
|
|
111
|
+
lon1 = mult3_ * lon1 + (k % mult3_);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (centerp) {
|
|
115
|
+
unit *= 2; lat1 = 2 * lat1 + 1; lon1 = 2 * lon1 + 1;
|
|
116
|
+
}
|
|
117
|
+
lat = lat1 / unit;
|
|
118
|
+
lon = lon1 / unit;
|
|
119
|
+
prec = prec1;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
} // namespace GeographicLib
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* \file GeoCoords.cpp
|
|
3
|
+
* \brief Implementation for GeographicLib::GeoCoords 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/GeoCoords.hpp>
|
|
11
|
+
#include <GeographicLib/MGRS.hpp>
|
|
12
|
+
#include <GeographicLib/DMS.hpp>
|
|
13
|
+
#include <GeographicLib/Utility.hpp>
|
|
14
|
+
|
|
15
|
+
namespace GeographicLib {
|
|
16
|
+
|
|
17
|
+
using namespace std;
|
|
18
|
+
|
|
19
|
+
void GeoCoords::Reset(const std::string& s, bool centerp, bool longfirst) {
|
|
20
|
+
vector<string> sa;
|
|
21
|
+
const char* spaces = " \t\n\v\f\r,"; // Include comma as a space
|
|
22
|
+
for (string::size_type pos0 = 0, pos1; pos0 != string::npos;) {
|
|
23
|
+
pos1 = s.find_first_not_of(spaces, pos0);
|
|
24
|
+
if (pos1 == string::npos)
|
|
25
|
+
break;
|
|
26
|
+
pos0 = s.find_first_of(spaces, pos1);
|
|
27
|
+
sa.push_back(s.substr(pos1, pos0 == string::npos ? pos0 : pos0 - pos1));
|
|
28
|
+
}
|
|
29
|
+
if (sa.size() == 1) {
|
|
30
|
+
int prec;
|
|
31
|
+
MGRS::Reverse(sa[0], _zone, _northp, _easting, _northing, prec, centerp);
|
|
32
|
+
UTMUPS::Reverse(_zone, _northp, _easting, _northing,
|
|
33
|
+
_lat, _long, _gamma, _k);
|
|
34
|
+
} else if (sa.size() == 2) {
|
|
35
|
+
DMS::DecodeLatLon(sa[0], sa[1], _lat, _long, longfirst);
|
|
36
|
+
_long = Math::AngNormalize(_long);
|
|
37
|
+
UTMUPS::Forward( _lat, _long,
|
|
38
|
+
_zone, _northp, _easting, _northing, _gamma, _k);
|
|
39
|
+
} else if (sa.size() == 3) {
|
|
40
|
+
unsigned zoneind, coordind;
|
|
41
|
+
if (sa[0].size() > 0 && isalpha(sa[0][sa[0].size() - 1])) {
|
|
42
|
+
zoneind = 0;
|
|
43
|
+
coordind = 1;
|
|
44
|
+
} else if (sa[2].size() > 0 && isalpha(sa[2][sa[2].size() - 1])) {
|
|
45
|
+
zoneind = 2;
|
|
46
|
+
coordind = 0;
|
|
47
|
+
} else
|
|
48
|
+
throw GeographicErr("Neither " + sa[0] + " nor " + sa[2]
|
|
49
|
+
+ " of the form UTM/UPS Zone + Hemisphere"
|
|
50
|
+
+ " (ex: 38n, 09s, n)");
|
|
51
|
+
UTMUPS::DecodeZone(sa[zoneind], _zone, _northp);
|
|
52
|
+
for (unsigned i = 0; i < 2; ++i)
|
|
53
|
+
(i ? _northing : _easting) = Utility::num<real>(sa[coordind + i]);
|
|
54
|
+
UTMUPS::Reverse(_zone, _northp, _easting, _northing,
|
|
55
|
+
_lat, _long, _gamma, _k);
|
|
56
|
+
FixHemisphere();
|
|
57
|
+
} else
|
|
58
|
+
throw GeographicErr("Coordinate requires 1, 2, or 3 elements");
|
|
59
|
+
CopyToAlt();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
string GeoCoords::GeoRepresentation(int prec, bool longfirst) const {
|
|
63
|
+
prec = max(0, min(9 + Math::extra_digits(), prec) + 5);
|
|
64
|
+
ostringstream os;
|
|
65
|
+
os << fixed << setprecision(prec);
|
|
66
|
+
real a = longfirst ? _long : _lat;
|
|
67
|
+
real b = longfirst ? _lat : _long;
|
|
68
|
+
if (!Math::isnan(a))
|
|
69
|
+
os << a;
|
|
70
|
+
else
|
|
71
|
+
os << "nan";
|
|
72
|
+
os << " ";
|
|
73
|
+
if (!Math::isnan(b))
|
|
74
|
+
os << b;
|
|
75
|
+
else
|
|
76
|
+
os << "nan";
|
|
77
|
+
return os.str();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
string GeoCoords::DMSRepresentation(int prec, bool longfirst,
|
|
81
|
+
char dmssep) const {
|
|
82
|
+
prec = max(0, min(10 + Math::extra_digits(), prec) + 5);
|
|
83
|
+
return DMS::Encode(longfirst ? _long : _lat, unsigned(prec),
|
|
84
|
+
longfirst ? DMS::LONGITUDE : DMS::LATITUDE, dmssep) +
|
|
85
|
+
" " + DMS::Encode(longfirst ? _lat : _long, unsigned(prec),
|
|
86
|
+
longfirst ? DMS::LATITUDE : DMS::LONGITUDE, dmssep);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
string GeoCoords::MGRSRepresentation(int prec) const {
|
|
90
|
+
// Max precision is um
|
|
91
|
+
prec = max(-1, min(6, prec) + 5);
|
|
92
|
+
string mgrs;
|
|
93
|
+
MGRS::Forward(_zone, _northp, _easting, _northing, _lat, prec, mgrs);
|
|
94
|
+
return mgrs;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
string GeoCoords::AltMGRSRepresentation(int prec) const {
|
|
98
|
+
// Max precision is um
|
|
99
|
+
prec = max(-1, min(6, prec) + 5);
|
|
100
|
+
string mgrs;
|
|
101
|
+
MGRS::Forward(_alt_zone, _northp, _alt_easting, _alt_northing, _lat, prec,
|
|
102
|
+
mgrs);
|
|
103
|
+
return mgrs;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
void GeoCoords::UTMUPSString(int zone, bool northp,
|
|
107
|
+
real easting, real northing, int prec,
|
|
108
|
+
bool abbrev, std::string& utm) {
|
|
109
|
+
ostringstream os;
|
|
110
|
+
prec = max(-5, min(9 + Math::extra_digits(), prec));
|
|
111
|
+
real scale = prec < 0 ? pow(real(10), -prec) : real(1);
|
|
112
|
+
os << UTMUPS::EncodeZone(zone, northp, abbrev) << fixed << setfill('0');
|
|
113
|
+
if (Math::isfinite(easting)) {
|
|
114
|
+
os << " " << Utility::str(easting / scale, max(0, prec));
|
|
115
|
+
if (prec < 0 && abs(easting / scale) > real(0.5))
|
|
116
|
+
os << setw(-prec) << 0;
|
|
117
|
+
} else
|
|
118
|
+
os << " nan";
|
|
119
|
+
if (Math::isfinite(northing)) {
|
|
120
|
+
os << " " << Utility::str(northing / scale, max(0, prec));
|
|
121
|
+
if (prec < 0 && abs(northing / scale) > real(0.5))
|
|
122
|
+
os << setw(-prec) << 0;
|
|
123
|
+
} else
|
|
124
|
+
os << " nan";
|
|
125
|
+
utm = os.str();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
string GeoCoords::UTMUPSRepresentation(int prec, bool abbrev) const {
|
|
129
|
+
string utm;
|
|
130
|
+
UTMUPSString(_zone, _northp, _easting, _northing, prec, abbrev, utm);
|
|
131
|
+
return utm;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
string GeoCoords::UTMUPSRepresentation(bool northp, int prec, bool abbrev)
|
|
135
|
+
const {
|
|
136
|
+
real e, n;
|
|
137
|
+
int z;
|
|
138
|
+
UTMUPS::Transfer(_zone, _northp, _easting, _northing,
|
|
139
|
+
_zone, northp, e, n, z);
|
|
140
|
+
string utm;
|
|
141
|
+
UTMUPSString(_zone, northp, e, n, prec, abbrev, utm);
|
|
142
|
+
return utm;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
string GeoCoords::AltUTMUPSRepresentation(int prec, bool abbrev) const {
|
|
146
|
+
string utm;
|
|
147
|
+
UTMUPSString(_alt_zone, _northp, _alt_easting, _alt_northing, prec,
|
|
148
|
+
abbrev, utm);
|
|
149
|
+
return utm;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
string GeoCoords::AltUTMUPSRepresentation(bool northp, int prec, bool abbrev)
|
|
153
|
+
const {
|
|
154
|
+
real e, n;
|
|
155
|
+
int z;
|
|
156
|
+
UTMUPS::Transfer(_alt_zone, _northp, _alt_easting, _alt_northing,
|
|
157
|
+
_alt_zone, northp, e, n, z);
|
|
158
|
+
string utm;
|
|
159
|
+
UTMUPSString(_alt_zone, northp, e, n, prec, abbrev, utm);
|
|
160
|
+
return utm;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
void GeoCoords::FixHemisphere() {
|
|
164
|
+
if (_lat == 0 || (_northp && _lat >= 0) || (!_northp && _lat < 0) ||
|
|
165
|
+
Math::isnan(_lat))
|
|
166
|
+
// Allow either hemisphere for equator
|
|
167
|
+
return;
|
|
168
|
+
if (_zone != UTMUPS::UPS) {
|
|
169
|
+
_northing += (_northp ? 1 : -1) * UTMUPS::UTMShift();
|
|
170
|
+
_northp = !_northp;
|
|
171
|
+
} else
|
|
172
|
+
throw GeographicErr("Hemisphere mixup");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
} // namespace GeographicLib
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* \file Geocentric.cpp
|
|
3
|
+
* \brief Implementation for GeographicLib::Geocentric 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/Geocentric.hpp>
|
|
11
|
+
|
|
12
|
+
namespace GeographicLib {
|
|
13
|
+
|
|
14
|
+
using namespace std;
|
|
15
|
+
|
|
16
|
+
Geocentric::Geocentric(real a, real f)
|
|
17
|
+
: _a(a)
|
|
18
|
+
, _f(f)
|
|
19
|
+
, _e2(_f * (2 - _f))
|
|
20
|
+
, _e2m(Math::sq(1 - _f)) // 1 - _e2
|
|
21
|
+
, _e2a(abs(_e2))
|
|
22
|
+
, _e4a(Math::sq(_e2))
|
|
23
|
+
, _maxrad(2 * _a / numeric_limits<real>::epsilon())
|
|
24
|
+
{
|
|
25
|
+
if (!(Math::isfinite(_a) && _a > 0))
|
|
26
|
+
throw GeographicErr("Major radius is not positive");
|
|
27
|
+
if (!(Math::isfinite(_f) && _f < 1))
|
|
28
|
+
throw GeographicErr("Minor radius is not positive");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const Geocentric& Geocentric::WGS84() {
|
|
32
|
+
static const Geocentric wgs84(Constants::WGS84_a(), Constants::WGS84_f());
|
|
33
|
+
return wgs84;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
void Geocentric::IntForward(real lat, real lon, real h,
|
|
37
|
+
real& X, real& Y, real& Z,
|
|
38
|
+
real M[dim2_]) const {
|
|
39
|
+
real sphi, cphi, slam, clam;
|
|
40
|
+
Math::sincosd(Math::LatFix(lat), sphi, cphi);
|
|
41
|
+
Math::sincosd(lon, slam, clam);
|
|
42
|
+
real n = _a/sqrt(1 - _e2 * Math::sq(sphi));
|
|
43
|
+
Z = (_e2m * n + h) * sphi;
|
|
44
|
+
X = (n + h) * cphi;
|
|
45
|
+
Y = X * slam;
|
|
46
|
+
X *= clam;
|
|
47
|
+
if (M)
|
|
48
|
+
Rotation(sphi, cphi, slam, clam, M);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
void Geocentric::IntReverse(real X, real Y, real Z,
|
|
52
|
+
real& lat, real& lon, real& h,
|
|
53
|
+
real M[dim2_]) const {
|
|
54
|
+
real
|
|
55
|
+
R = Math::hypot(X, Y),
|
|
56
|
+
slam = R ? Y / R : 0,
|
|
57
|
+
clam = R ? X / R : 1;
|
|
58
|
+
h = Math::hypot(R, Z); // Distance to center of earth
|
|
59
|
+
real sphi, cphi;
|
|
60
|
+
if (h > _maxrad) {
|
|
61
|
+
// We really far away (> 12 million light years); treat the earth as a
|
|
62
|
+
// point and h, above, is an acceptable approximation to the height.
|
|
63
|
+
// This avoids overflow, e.g., in the computation of disc below. It's
|
|
64
|
+
// possible that h has overflowed to inf; but that's OK.
|
|
65
|
+
//
|
|
66
|
+
// Treat the case X, Y finite, but R overflows to +inf by scaling by 2.
|
|
67
|
+
R = Math::hypot(X/2, Y/2);
|
|
68
|
+
slam = R ? (Y/2) / R : 0;
|
|
69
|
+
clam = R ? (X/2) / R : 1;
|
|
70
|
+
real H = Math::hypot(Z/2, R);
|
|
71
|
+
sphi = (Z/2) / H;
|
|
72
|
+
cphi = R / H;
|
|
73
|
+
} else if (_e4a == 0) {
|
|
74
|
+
// Treat the spherical case. Dealing with underflow in the general case
|
|
75
|
+
// with _e2 = 0 is difficult. Origin maps to N pole same as with
|
|
76
|
+
// ellipsoid.
|
|
77
|
+
real H = Math::hypot(h == 0 ? 1 : Z, R);
|
|
78
|
+
sphi = (h == 0 ? 1 : Z) / H;
|
|
79
|
+
cphi = R / H;
|
|
80
|
+
h -= _a;
|
|
81
|
+
} else {
|
|
82
|
+
// Treat prolate spheroids by swapping R and Z here and by switching
|
|
83
|
+
// the arguments to phi = atan2(...) at the end.
|
|
84
|
+
real
|
|
85
|
+
p = Math::sq(R / _a),
|
|
86
|
+
q = _e2m * Math::sq(Z / _a),
|
|
87
|
+
r = (p + q - _e4a) / 6;
|
|
88
|
+
if (_f < 0) swap(p, q);
|
|
89
|
+
if ( !(_e4a * q == 0 && r <= 0) ) {
|
|
90
|
+
real
|
|
91
|
+
// Avoid possible division by zero when r = 0 by multiplying
|
|
92
|
+
// equations for s and t by r^3 and r, resp.
|
|
93
|
+
S = _e4a * p * q / 4, // S = r^3 * s
|
|
94
|
+
r2 = Math::sq(r),
|
|
95
|
+
r3 = r * r2,
|
|
96
|
+
disc = S * (2 * r3 + S);
|
|
97
|
+
real u = r;
|
|
98
|
+
if (disc >= 0) {
|
|
99
|
+
real T3 = S + r3;
|
|
100
|
+
// Pick the sign on the sqrt to maximize abs(T3). This minimizes
|
|
101
|
+
// loss of precision due to cancellation. The result is unchanged
|
|
102
|
+
// because of the way the T is used in definition of u.
|
|
103
|
+
T3 += T3 < 0 ? -sqrt(disc) : sqrt(disc); // T3 = (r * t)^3
|
|
104
|
+
// N.B. cbrt always returns the real root. cbrt(-8) = -2.
|
|
105
|
+
real T = Math::cbrt(T3); // T = r * t
|
|
106
|
+
// T can be zero; but then r2 / T -> 0.
|
|
107
|
+
u += T + (T ? r2 / T : 0);
|
|
108
|
+
} else {
|
|
109
|
+
// T is complex, but the way u is defined the result is real.
|
|
110
|
+
real ang = atan2(sqrt(-disc), -(S + r3));
|
|
111
|
+
// There are three possible cube roots. We choose the root which
|
|
112
|
+
// avoids cancellation. Note that disc < 0 implies that r < 0.
|
|
113
|
+
u += 2 * r * cos(ang / 3);
|
|
114
|
+
}
|
|
115
|
+
real
|
|
116
|
+
v = sqrt(Math::sq(u) + _e4a * q), // guaranteed positive
|
|
117
|
+
// Avoid loss of accuracy when u < 0. Underflow doesn't occur in
|
|
118
|
+
// e4 * q / (v - u) because u ~ e^4 when q is small and u < 0.
|
|
119
|
+
uv = u < 0 ? _e4a * q / (v - u) : u + v, // u+v, guaranteed positive
|
|
120
|
+
// Need to guard against w going negative due to roundoff in uv - q.
|
|
121
|
+
w = max(real(0), _e2a * (uv - q) / (2 * v)),
|
|
122
|
+
// Rearrange expression for k to avoid loss of accuracy due to
|
|
123
|
+
// subtraction. Division by 0 not possible because uv > 0, w >= 0.
|
|
124
|
+
k = uv / (sqrt(uv + Math::sq(w)) + w),
|
|
125
|
+
k1 = _f >= 0 ? k : k - _e2,
|
|
126
|
+
k2 = _f >= 0 ? k + _e2 : k,
|
|
127
|
+
d = k1 * R / k2,
|
|
128
|
+
H = Math::hypot(Z/k1, R/k2);
|
|
129
|
+
sphi = (Z/k1) / H;
|
|
130
|
+
cphi = (R/k2) / H;
|
|
131
|
+
h = (1 - _e2m/k1) * Math::hypot(d, Z);
|
|
132
|
+
} else { // e4 * q == 0 && r <= 0
|
|
133
|
+
// This leads to k = 0 (oblate, equatorial plane) and k + e^2 = 0
|
|
134
|
+
// (prolate, rotation axis) and the generation of 0/0 in the general
|
|
135
|
+
// formulas for phi and h. using the general formula and division by 0
|
|
136
|
+
// in formula for h. So handle this case by taking the limits:
|
|
137
|
+
// f > 0: z -> 0, k -> e2 * sqrt(q)/sqrt(e4 - p)
|
|
138
|
+
// f < 0: R -> 0, k + e2 -> - e2 * sqrt(q)/sqrt(e4 - p)
|
|
139
|
+
real
|
|
140
|
+
zz = sqrt((_f >= 0 ? _e4a - p : p) / _e2m),
|
|
141
|
+
xx = sqrt( _f < 0 ? _e4a - p : p ),
|
|
142
|
+
H = Math::hypot(zz, xx);
|
|
143
|
+
sphi = zz / H;
|
|
144
|
+
cphi = xx / H;
|
|
145
|
+
if (Z < 0) sphi = -sphi; // for tiny negative Z (not for prolate)
|
|
146
|
+
h = - _a * (_f >= 0 ? _e2m : 1) * H / _e2a;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
lat = Math::atan2d(sphi, cphi);
|
|
150
|
+
lon = Math::atan2d(slam, clam);
|
|
151
|
+
if (M)
|
|
152
|
+
Rotation(sphi, cphi, slam, clam, M);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
void Geocentric::Rotation(real sphi, real cphi, real slam, real clam,
|
|
156
|
+
real M[dim2_]) {
|
|
157
|
+
// This rotation matrix is given by the following quaternion operations
|
|
158
|
+
// qrot(lam, [0,0,1]) * qrot(phi, [0,-1,0]) * [1,1,1,1]/2
|
|
159
|
+
// or
|
|
160
|
+
// qrot(pi/2 + lam, [0,0,1]) * qrot(-pi/2 + phi , [-1,0,0])
|
|
161
|
+
// where
|
|
162
|
+
// qrot(t,v) = [cos(t/2), sin(t/2)*v[1], sin(t/2)*v[2], sin(t/2)*v[3]]
|
|
163
|
+
|
|
164
|
+
// Local X axis (east) in geocentric coords
|
|
165
|
+
M[0] = -slam; M[3] = clam; M[6] = 0;
|
|
166
|
+
// Local Y axis (north) in geocentric coords
|
|
167
|
+
M[1] = -clam * sphi; M[4] = -slam * sphi; M[7] = cphi;
|
|
168
|
+
// Local Z axis (up) in geocentric coords
|
|
169
|
+
M[2] = clam * cphi; M[5] = slam * cphi; M[8] = sphi;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
} // namespace GeographicLib
|