geographiclib 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,125 @@
|
|
1
|
+
/**
|
2
|
+
* \file Ellipsoid.cpp
|
3
|
+
* \brief Implementation for GeographicLib::Ellipsoid class
|
4
|
+
*
|
5
|
+
* Copyright (c) Charles Karney (2012-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/Ellipsoid.hpp>
|
11
|
+
|
12
|
+
namespace GeographicLib {
|
13
|
+
|
14
|
+
using namespace std;
|
15
|
+
|
16
|
+
Ellipsoid::Ellipsoid(real a, real f)
|
17
|
+
: stol_(real(0.01) * sqrt(numeric_limits<real>::epsilon()))
|
18
|
+
, _a(a)
|
19
|
+
, _f(f)
|
20
|
+
, _f1(1 - _f)
|
21
|
+
, _f12(Math::sq(_f1))
|
22
|
+
, _e2(_f * (2 - _f))
|
23
|
+
, _es((_f < 0 ? -1 : 1) * sqrt(abs(_e2)))
|
24
|
+
, _e12(_e2 / (1 - _e2))
|
25
|
+
, _n(_f / (2 - _f))
|
26
|
+
, _b(_a * _f1)
|
27
|
+
, _tm(_a, _f, real(1))
|
28
|
+
, _ell(-_e12)
|
29
|
+
, _au(_a, _f, real(0), real(1), real(0), real(1), real(1))
|
30
|
+
{}
|
31
|
+
|
32
|
+
const Ellipsoid& Ellipsoid::WGS84() {
|
33
|
+
static const Ellipsoid wgs84(Constants::WGS84_a(), Constants::WGS84_f());
|
34
|
+
return wgs84;
|
35
|
+
}
|
36
|
+
|
37
|
+
Math::real Ellipsoid::QuarterMeridian() const
|
38
|
+
{ return _b * _ell.E(); }
|
39
|
+
|
40
|
+
Math::real Ellipsoid::Area() const {
|
41
|
+
return 4 * Math::pi() *
|
42
|
+
((Math::sq(_a) + Math::sq(_b) *
|
43
|
+
(_e2 == 0 ? 1 :
|
44
|
+
(_e2 > 0 ? Math::atanh(sqrt(_e2)) : atan(sqrt(-_e2))) /
|
45
|
+
sqrt(abs(_e2))))/2);
|
46
|
+
}
|
47
|
+
|
48
|
+
Math::real Ellipsoid::ParametricLatitude(real phi) const
|
49
|
+
{ return Math::atand(_f1 * Math::tand(Math::LatFix(phi))); }
|
50
|
+
|
51
|
+
Math::real Ellipsoid::InverseParametricLatitude(real beta) const
|
52
|
+
{ return Math::atand(Math::tand(Math::LatFix(beta)) / _f1); }
|
53
|
+
|
54
|
+
Math::real Ellipsoid::GeocentricLatitude(real phi) const
|
55
|
+
{ return Math::atand(_f12 * Math::tand(Math::LatFix(phi))); }
|
56
|
+
|
57
|
+
Math::real Ellipsoid::InverseGeocentricLatitude(real theta) const
|
58
|
+
{ return Math::atand(Math::tand(Math::LatFix(theta)) / _f12); }
|
59
|
+
|
60
|
+
Math::real Ellipsoid::RectifyingLatitude(real phi) const {
|
61
|
+
return abs(phi) == 90 ? phi:
|
62
|
+
90 * MeridianDistance(phi) / QuarterMeridian();
|
63
|
+
}
|
64
|
+
|
65
|
+
Math::real Ellipsoid::InverseRectifyingLatitude(real mu) const {
|
66
|
+
if (abs(mu) == 90)
|
67
|
+
return mu;
|
68
|
+
return InverseParametricLatitude(_ell.Einv(mu * _ell.E() / 90) /
|
69
|
+
Math::degree());
|
70
|
+
}
|
71
|
+
|
72
|
+
Math::real Ellipsoid::AuthalicLatitude(real phi) const
|
73
|
+
{ return Math::atand(_au.txif(Math::tand(Math::LatFix(phi)))); }
|
74
|
+
|
75
|
+
Math::real Ellipsoid::InverseAuthalicLatitude(real xi) const
|
76
|
+
{ return Math::atand(_au.tphif(Math::tand(Math::LatFix(xi)))); }
|
77
|
+
|
78
|
+
Math::real Ellipsoid::ConformalLatitude(real phi) const
|
79
|
+
{ return Math::atand(Math::taupf(Math::tand(Math::LatFix(phi)), _es)); }
|
80
|
+
|
81
|
+
Math::real Ellipsoid::InverseConformalLatitude(real chi) const
|
82
|
+
{ return Math::atand(Math::tauf(Math::tand(Math::LatFix(chi)), _es)); }
|
83
|
+
|
84
|
+
Math::real Ellipsoid::IsometricLatitude(real phi) const
|
85
|
+
{ return Math::asinh(Math::taupf(Math::tand(Math::LatFix(phi)), _es)) /
|
86
|
+
Math::degree(); }
|
87
|
+
|
88
|
+
Math::real Ellipsoid::InverseIsometricLatitude(real psi) const
|
89
|
+
{ return Math::atand(Math::tauf(sinh(psi * Math::degree()), _es)); }
|
90
|
+
|
91
|
+
Math::real Ellipsoid::CircleRadius(real phi) const {
|
92
|
+
return abs(phi) == 90 ? 0 :
|
93
|
+
// a * cos(beta)
|
94
|
+
_a / Math::hypot(real(1), _f1 * Math::tand(Math::LatFix(phi)));
|
95
|
+
}
|
96
|
+
|
97
|
+
Math::real Ellipsoid::CircleHeight(real phi) const {
|
98
|
+
real tbeta = _f1 * Math::tand(phi);
|
99
|
+
// b * sin(beta)
|
100
|
+
return _b * tbeta / Math::hypot(real(1),
|
101
|
+
_f1 * Math::tand(Math::LatFix(phi)));
|
102
|
+
}
|
103
|
+
|
104
|
+
Math::real Ellipsoid::MeridianDistance(real phi) const
|
105
|
+
{ return _b * _ell.Ed( ParametricLatitude(phi) ); }
|
106
|
+
|
107
|
+
Math::real Ellipsoid::MeridionalCurvatureRadius(real phi) const {
|
108
|
+
real v = 1 - _e2 * Math::sq(Math::sind(Math::LatFix(phi)));
|
109
|
+
return _a * (1 - _e2) / (v * sqrt(v));
|
110
|
+
}
|
111
|
+
|
112
|
+
Math::real Ellipsoid::TransverseCurvatureRadius(real phi) const {
|
113
|
+
real v = 1 - _e2 * Math::sq(Math::sind(Math::LatFix(phi)));
|
114
|
+
return _a / sqrt(v);
|
115
|
+
}
|
116
|
+
|
117
|
+
Math::real Ellipsoid::NormalCurvatureRadius(real phi, real azi)
|
118
|
+
const {
|
119
|
+
real calp, salp,
|
120
|
+
v = 1 - _e2 * Math::sq(Math::sind(Math::LatFix(phi)));
|
121
|
+
Math::sincosd(azi, salp, calp);
|
122
|
+
return _a / (sqrt(v) * (Math::sq(calp) * v / (1 - _e2) + Math::sq(salp)));
|
123
|
+
}
|
124
|
+
|
125
|
+
} // namespace GeographicLib
|
@@ -0,0 +1,512 @@
|
|
1
|
+
/**
|
2
|
+
* \file EllipticFunction.cpp
|
3
|
+
* \brief Implementation for GeographicLib::EllipticFunction 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/EllipticFunction.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
|
+
/*
|
22
|
+
* Implementation of methods given in
|
23
|
+
*
|
24
|
+
* B. C. Carlson
|
25
|
+
* Computation of elliptic integrals
|
26
|
+
* Numerical Algorithms 10, 13-26 (1995)
|
27
|
+
*/
|
28
|
+
|
29
|
+
Math::real EllipticFunction::RF(real x, real y, real z) {
|
30
|
+
// Carlson, eqs 2.2 - 2.7
|
31
|
+
real tolRF =
|
32
|
+
pow(3 * numeric_limits<real>::epsilon() * real(0.01), 1/real(8));
|
33
|
+
real
|
34
|
+
A0 = (x + y + z)/3,
|
35
|
+
An = A0,
|
36
|
+
Q = max(max(abs(A0-x), abs(A0-y)), abs(A0-z)) / tolRF,
|
37
|
+
x0 = x,
|
38
|
+
y0 = y,
|
39
|
+
z0 = z,
|
40
|
+
mul = 1;
|
41
|
+
while (Q >= mul * abs(An)) {
|
42
|
+
// Max 6 trips
|
43
|
+
real lam = sqrt(x0)*sqrt(y0) + sqrt(y0)*sqrt(z0) + sqrt(z0)*sqrt(x0);
|
44
|
+
An = (An + lam)/4;
|
45
|
+
x0 = (x0 + lam)/4;
|
46
|
+
y0 = (y0 + lam)/4;
|
47
|
+
z0 = (z0 + lam)/4;
|
48
|
+
mul *= 4;
|
49
|
+
}
|
50
|
+
real
|
51
|
+
X = (A0 - x) / (mul * An),
|
52
|
+
Y = (A0 - y) / (mul * An),
|
53
|
+
Z = - (X + Y),
|
54
|
+
E2 = X*Y - Z*Z,
|
55
|
+
E3 = X*Y*Z;
|
56
|
+
// http://dlmf.nist.gov/19.36.E1
|
57
|
+
// Polynomial is
|
58
|
+
// (1 - E2/10 + E3/14 + E2^2/24 - 3*E2*E3/44
|
59
|
+
// - 5*E2^3/208 + 3*E3^2/104 + E2^2*E3/16)
|
60
|
+
// convert to Horner form...
|
61
|
+
return (E3 * (6930 * E3 + E2 * (15015 * E2 - 16380) + 17160) +
|
62
|
+
E2 * ((10010 - 5775 * E2) * E2 - 24024) + 240240) /
|
63
|
+
(240240 * sqrt(An));
|
64
|
+
}
|
65
|
+
|
66
|
+
Math::real EllipticFunction::RF(real x, real y) {
|
67
|
+
// Carlson, eqs 2.36 - 2.38
|
68
|
+
real tolRG0 =
|
69
|
+
real(2.7) * sqrt((numeric_limits<real>::epsilon() * real(0.01)));
|
70
|
+
real xn = sqrt(x), yn = sqrt(y);
|
71
|
+
if (xn < yn) swap(xn, yn);
|
72
|
+
while (abs(xn-yn) > tolRG0 * xn) {
|
73
|
+
// Max 4 trips
|
74
|
+
real t = (xn + yn) /2;
|
75
|
+
yn = sqrt(xn * yn);
|
76
|
+
xn = t;
|
77
|
+
}
|
78
|
+
return Math::pi() / (xn + yn);
|
79
|
+
}
|
80
|
+
|
81
|
+
Math::real EllipticFunction::RC(real x, real y) {
|
82
|
+
// Defined only for y != 0 and x >= 0.
|
83
|
+
return ( !(x >= y) ? // x < y and catch nans
|
84
|
+
// http://dlmf.nist.gov/19.2.E18
|
85
|
+
atan(sqrt((y - x) / x)) / sqrt(y - x) :
|
86
|
+
( x == y ? 1 / sqrt(y) :
|
87
|
+
Math::asinh( y > 0 ?
|
88
|
+
// http://dlmf.nist.gov/19.2.E19
|
89
|
+
// atanh(sqrt((x - y) / x))
|
90
|
+
sqrt((x - y) / y) :
|
91
|
+
// http://dlmf.nist.gov/19.2.E20
|
92
|
+
// atanh(sqrt(x / (x - y)))
|
93
|
+
sqrt(-x / y) ) / sqrt(x - y) ) );
|
94
|
+
}
|
95
|
+
|
96
|
+
Math::real EllipticFunction::RG(real x, real y, real z) {
|
97
|
+
if (z == 0)
|
98
|
+
swap(y, z);
|
99
|
+
// Carlson, eq 1.7
|
100
|
+
return (z * RF(x, y, z) - (x-z) * (y-z) * RD(x, y, z) / 3
|
101
|
+
+ sqrt(x * y / z)) / 2;
|
102
|
+
}
|
103
|
+
|
104
|
+
Math::real EllipticFunction::RG(real x, real y) {
|
105
|
+
// Carlson, eqs 2.36 - 2.39
|
106
|
+
real tolRG0 =
|
107
|
+
real(2.7) * sqrt((numeric_limits<real>::epsilon() * real(0.01)));
|
108
|
+
real
|
109
|
+
x0 = sqrt(max(x, y)),
|
110
|
+
y0 = sqrt(min(x, y)),
|
111
|
+
xn = x0,
|
112
|
+
yn = y0,
|
113
|
+
s = 0,
|
114
|
+
mul = real(0.25);
|
115
|
+
while (abs(xn-yn) > tolRG0 * xn) {
|
116
|
+
// Max 4 trips
|
117
|
+
real t = (xn + yn) /2;
|
118
|
+
yn = sqrt(xn * yn);
|
119
|
+
xn = t;
|
120
|
+
mul *= 2;
|
121
|
+
t = xn - yn;
|
122
|
+
s += mul * t * t;
|
123
|
+
}
|
124
|
+
return (Math::sq( (x0 + y0)/2 ) - s) * Math::pi() / (2 * (xn + yn));
|
125
|
+
}
|
126
|
+
|
127
|
+
Math::real EllipticFunction::RJ(real x, real y, real z, real p) {
|
128
|
+
// Carlson, eqs 2.17 - 2.25
|
129
|
+
real tolRD = pow(real(0.2) * (numeric_limits<real>::epsilon() * real(0.01)),
|
130
|
+
1/real(8));
|
131
|
+
real
|
132
|
+
A0 = (x + y + z + 2*p)/5,
|
133
|
+
An = A0,
|
134
|
+
delta = (p-x) * (p-y) * (p-z),
|
135
|
+
Q = max(max(abs(A0-x), abs(A0-y)), max(abs(A0-z), abs(A0-p))) / tolRD,
|
136
|
+
x0 = x,
|
137
|
+
y0 = y,
|
138
|
+
z0 = z,
|
139
|
+
p0 = p,
|
140
|
+
mul = 1,
|
141
|
+
mul3 = 1,
|
142
|
+
s = 0;
|
143
|
+
while (Q >= mul * abs(An)) {
|
144
|
+
// Max 7 trips
|
145
|
+
real
|
146
|
+
lam = sqrt(x0)*sqrt(y0) + sqrt(y0)*sqrt(z0) + sqrt(z0)*sqrt(x0),
|
147
|
+
d0 = (sqrt(p0)+sqrt(x0)) * (sqrt(p0)+sqrt(y0)) * (sqrt(p0)+sqrt(z0)),
|
148
|
+
e0 = delta/(mul3 * Math::sq(d0));
|
149
|
+
s += RC(1, 1 + e0)/(mul * d0);
|
150
|
+
An = (An + lam)/4;
|
151
|
+
x0 = (x0 + lam)/4;
|
152
|
+
y0 = (y0 + lam)/4;
|
153
|
+
z0 = (z0 + lam)/4;
|
154
|
+
p0 = (p0 + lam)/4;
|
155
|
+
mul *= 4;
|
156
|
+
mul3 *= 64;
|
157
|
+
}
|
158
|
+
real
|
159
|
+
X = (A0 - x) / (mul * An),
|
160
|
+
Y = (A0 - y) / (mul * An),
|
161
|
+
Z = (A0 - z) / (mul * An),
|
162
|
+
P = -(X + Y + Z) / 2,
|
163
|
+
E2 = X*Y + X*Z + Y*Z - 3*P*P,
|
164
|
+
E3 = X*Y*Z + 2*P * (E2 + 2*P*P),
|
165
|
+
E4 = (2*X*Y*Z + P * (E2 + 3*P*P)) * P,
|
166
|
+
E5 = X*Y*Z*P*P;
|
167
|
+
// http://dlmf.nist.gov/19.36.E2
|
168
|
+
// Polynomial is
|
169
|
+
// (1 - 3*E2/14 + E3/6 + 9*E2^2/88 - 3*E4/22 - 9*E2*E3/52 + 3*E5/26
|
170
|
+
// - E2^3/16 + 3*E3^2/40 + 3*E2*E4/20 + 45*E2^2*E3/272
|
171
|
+
// - 9*(E3*E4+E2*E5)/68)
|
172
|
+
return ((471240 - 540540 * E2) * E5 +
|
173
|
+
(612612 * E2 - 540540 * E3 - 556920) * E4 +
|
174
|
+
E3 * (306306 * E3 + E2 * (675675 * E2 - 706860) + 680680) +
|
175
|
+
E2 * ((417690 - 255255 * E2) * E2 - 875160) + 4084080) /
|
176
|
+
(4084080 * mul * An * sqrt(An)) + 6 * s;
|
177
|
+
}
|
178
|
+
|
179
|
+
Math::real EllipticFunction::RD(real x, real y, real z) {
|
180
|
+
// Carlson, eqs 2.28 - 2.34
|
181
|
+
real tolRD = pow(real(0.2) * (numeric_limits<real>::epsilon() * real(0.01)),
|
182
|
+
1/real(8));
|
183
|
+
real
|
184
|
+
A0 = (x + y + 3*z)/5,
|
185
|
+
An = A0,
|
186
|
+
Q = max(max(abs(A0-x), abs(A0-y)), abs(A0-z)) / tolRD,
|
187
|
+
x0 = x,
|
188
|
+
y0 = y,
|
189
|
+
z0 = z,
|
190
|
+
mul = 1,
|
191
|
+
s = 0;
|
192
|
+
while (Q >= mul * abs(An)) {
|
193
|
+
// Max 7 trips
|
194
|
+
real lam = sqrt(x0)*sqrt(y0) + sqrt(y0)*sqrt(z0) + sqrt(z0)*sqrt(x0);
|
195
|
+
s += 1/(mul * sqrt(z0) * (z0 + lam));
|
196
|
+
An = (An + lam)/4;
|
197
|
+
x0 = (x0 + lam)/4;
|
198
|
+
y0 = (y0 + lam)/4;
|
199
|
+
z0 = (z0 + lam)/4;
|
200
|
+
mul *= 4;
|
201
|
+
}
|
202
|
+
real
|
203
|
+
X = (A0 - x) / (mul * An),
|
204
|
+
Y = (A0 - y) / (mul * An),
|
205
|
+
Z = -(X + Y) / 3,
|
206
|
+
E2 = X*Y - 6*Z*Z,
|
207
|
+
E3 = (3*X*Y - 8*Z*Z)*Z,
|
208
|
+
E4 = 3 * (X*Y - Z*Z) * Z*Z,
|
209
|
+
E5 = X*Y*Z*Z*Z;
|
210
|
+
// http://dlmf.nist.gov/19.36.E2
|
211
|
+
// Polynomial is
|
212
|
+
// (1 - 3*E2/14 + E3/6 + 9*E2^2/88 - 3*E4/22 - 9*E2*E3/52 + 3*E5/26
|
213
|
+
// - E2^3/16 + 3*E3^2/40 + 3*E2*E4/20 + 45*E2^2*E3/272
|
214
|
+
// - 9*(E3*E4+E2*E5)/68)
|
215
|
+
return ((471240 - 540540 * E2) * E5 +
|
216
|
+
(612612 * E2 - 540540 * E3 - 556920) * E4 +
|
217
|
+
E3 * (306306 * E3 + E2 * (675675 * E2 - 706860) + 680680) +
|
218
|
+
E2 * ((417690 - 255255 * E2) * E2 - 875160) + 4084080) /
|
219
|
+
(4084080 * mul * An * sqrt(An)) + 3 * s;
|
220
|
+
}
|
221
|
+
|
222
|
+
void EllipticFunction::Reset(real k2, real alpha2,
|
223
|
+
real kp2, real alphap2) {
|
224
|
+
_k2 = k2;
|
225
|
+
_kp2 = kp2;
|
226
|
+
_alpha2 = alpha2;
|
227
|
+
_alphap2 = alphap2;
|
228
|
+
_eps = _k2/Math::sq(sqrt(_kp2) + 1);
|
229
|
+
if (_k2) {
|
230
|
+
// Complete elliptic integral K(k), Carlson eq. 4.1
|
231
|
+
// http://dlmf.nist.gov/19.25.E1
|
232
|
+
_Kc = _kp2 ? RF(_kp2, 1) : Math::infinity();
|
233
|
+
// Complete elliptic integral E(k), Carlson eq. 4.2
|
234
|
+
// http://dlmf.nist.gov/19.25.E1
|
235
|
+
_Ec = _kp2 ? 2 * RG(_kp2, 1) : 1;
|
236
|
+
// D(k) = (K(k) - E(k))/k^2, Carlson eq.4.3
|
237
|
+
// http://dlmf.nist.gov/19.25.E1
|
238
|
+
_Dc = _kp2 ? RD(real(0), _kp2, 1) / 3 : Math::infinity();
|
239
|
+
} else {
|
240
|
+
_Kc = _Ec = Math::pi()/2; _Dc = _Kc/2;
|
241
|
+
}
|
242
|
+
if (_alpha2) {
|
243
|
+
// http://dlmf.nist.gov/19.25.E2
|
244
|
+
real rj = _kp2 ? RJ(0, _kp2, 1, _alphap2) : Math::infinity();
|
245
|
+
// Pi(alpha^2, k)
|
246
|
+
_Pic = _Kc + _alpha2 * rj / 3;
|
247
|
+
// G(alpha^2, k)
|
248
|
+
_Gc = _kp2 ? _Kc + (_alpha2 - _k2) * rj / 3 : RC(1, _alphap2);
|
249
|
+
// H(alpha^2, k)
|
250
|
+
_Hc = _kp2 ? _Kc - _alphap2 * rj / 3 : RC(1, _alphap2);
|
251
|
+
} else {
|
252
|
+
_Pic = _Kc; _Gc = _Ec; _Hc = _Kc - _Dc;
|
253
|
+
}
|
254
|
+
}
|
255
|
+
|
256
|
+
/*
|
257
|
+
* Implementation of methods given in
|
258
|
+
*
|
259
|
+
* R. Bulirsch
|
260
|
+
* Numerical Calculation of Elliptic Integrals and Elliptic Functions
|
261
|
+
* Numericshe Mathematik 7, 78-90 (1965)
|
262
|
+
*/
|
263
|
+
|
264
|
+
void EllipticFunction::sncndn(real x, real& sn, real& cn, real& dn)
|
265
|
+
const {
|
266
|
+
// Bulirsch's sncndn routine, p 89.
|
267
|
+
real tolJAC = sqrt(numeric_limits<real>::epsilon() * real(0.01));
|
268
|
+
if (_kp2 != 0) {
|
269
|
+
real mc = _kp2, d = 0;
|
270
|
+
if (_kp2 < 0) {
|
271
|
+
d = 1 - mc;
|
272
|
+
mc /= -d;
|
273
|
+
d = sqrt(d);
|
274
|
+
x *= d;
|
275
|
+
}
|
276
|
+
real c = 0; // To suppress warning about uninitialized variable
|
277
|
+
real m[num_], n[num_];
|
278
|
+
unsigned l = 0;
|
279
|
+
for (real a = 1; l < num_ || GEOGRAPHICLIB_PANIC; ++l) {
|
280
|
+
// This converges quadratically. Max 5 trips
|
281
|
+
m[l] = a;
|
282
|
+
n[l] = mc = sqrt(mc);
|
283
|
+
c = (a + mc) / 2;
|
284
|
+
if (!(abs(a - mc) > tolJAC * a)) {
|
285
|
+
++l;
|
286
|
+
break;
|
287
|
+
}
|
288
|
+
mc *= a;
|
289
|
+
a = c;
|
290
|
+
}
|
291
|
+
x *= c;
|
292
|
+
sn = sin(x);
|
293
|
+
cn = cos(x);
|
294
|
+
dn = 1;
|
295
|
+
if (sn != 0) {
|
296
|
+
real a = cn / sn;
|
297
|
+
c *= a;
|
298
|
+
while (l--) {
|
299
|
+
real b = m[l];
|
300
|
+
a *= c;
|
301
|
+
c *= dn;
|
302
|
+
dn = (n[l] + a) / (b + a);
|
303
|
+
a = c / b;
|
304
|
+
}
|
305
|
+
a = 1 / sqrt(c*c + 1);
|
306
|
+
sn = sn < 0 ? -a : a;
|
307
|
+
cn = c * sn;
|
308
|
+
if (_kp2 < 0) {
|
309
|
+
swap(cn, dn);
|
310
|
+
sn /= d;
|
311
|
+
}
|
312
|
+
}
|
313
|
+
} else {
|
314
|
+
sn = tanh(x);
|
315
|
+
dn = cn = 1 / cosh(x);
|
316
|
+
}
|
317
|
+
}
|
318
|
+
|
319
|
+
Math::real EllipticFunction::F(real sn, real cn, real dn) const {
|
320
|
+
// Carlson, eq. 4.5 and
|
321
|
+
// http://dlmf.nist.gov/19.25.E5
|
322
|
+
real fi = abs(sn) * RF(cn*cn, dn*dn, 1);
|
323
|
+
// Enforce usual trig-like symmetries
|
324
|
+
if (cn < 0)
|
325
|
+
fi = 2 * K() - fi;
|
326
|
+
if (sn < 0)
|
327
|
+
fi = -fi;
|
328
|
+
return fi;
|
329
|
+
}
|
330
|
+
|
331
|
+
Math::real EllipticFunction::E(real sn, real cn, real dn) const {
|
332
|
+
real
|
333
|
+
cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn,
|
334
|
+
ei = ( _k2 <= 0 ?
|
335
|
+
// Carlson, eq. 4.6 and
|
336
|
+
// http://dlmf.nist.gov/19.25.E9
|
337
|
+
RF(cn2, dn2, 1) - _k2 * sn2 * RD(cn2, dn2, 1) / 3 :
|
338
|
+
( _kp2 >= 0 ?
|
339
|
+
// http://dlmf.nist.gov/19.25.E10
|
340
|
+
_kp2 * RF(cn2, dn2, 1) +
|
341
|
+
_k2 * _kp2 * sn2 * RD(cn2, 1, dn2) / 3 +
|
342
|
+
_k2 * abs(cn) / dn :
|
343
|
+
// http://dlmf.nist.gov/19.25.E11
|
344
|
+
- _kp2 * sn2 * RD(dn2, 1, cn2) / 3 + dn / abs(cn) ) );
|
345
|
+
ei *= abs(sn);
|
346
|
+
// Enforce usual trig-like symmetries
|
347
|
+
if (cn < 0)
|
348
|
+
ei = 2 * E() - ei;
|
349
|
+
if (sn < 0)
|
350
|
+
ei = -ei;
|
351
|
+
return ei;
|
352
|
+
}
|
353
|
+
|
354
|
+
Math::real EllipticFunction::D(real sn, real cn, real dn) const {
|
355
|
+
// Carlson, eq. 4.8 and
|
356
|
+
// http://dlmf.nist.gov/19.25.E13
|
357
|
+
real di = abs(sn) * sn*sn * RD(cn*cn, dn*dn, 1) / 3;
|
358
|
+
// Enforce usual trig-like symmetries
|
359
|
+
if (cn < 0)
|
360
|
+
di = 2 * D() - di;
|
361
|
+
if (sn < 0)
|
362
|
+
di = -di;
|
363
|
+
return di;
|
364
|
+
}
|
365
|
+
|
366
|
+
Math::real EllipticFunction::Pi(real sn, real cn, real dn) const {
|
367
|
+
// Carlson, eq. 4.7 and
|
368
|
+
// http://dlmf.nist.gov/19.25.E14
|
369
|
+
real
|
370
|
+
cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn,
|
371
|
+
pii = abs(sn) * (RF(cn2, dn2, 1) +
|
372
|
+
_alpha2 * sn2 * RJ(cn2, dn2, 1, 1 - _alpha2 * sn2) / 3);
|
373
|
+
// Enforce usual trig-like symmetries
|
374
|
+
if (cn < 0)
|
375
|
+
pii = 2 * Pi() - pii;
|
376
|
+
if (sn < 0)
|
377
|
+
pii = -pii;
|
378
|
+
return pii;
|
379
|
+
}
|
380
|
+
|
381
|
+
Math::real EllipticFunction::G(real sn, real cn, real dn) const {
|
382
|
+
real
|
383
|
+
cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn,
|
384
|
+
gi = abs(sn) * (RF(cn2, dn2, 1) +
|
385
|
+
(_alpha2 - _k2) * sn2 *
|
386
|
+
RJ(cn2, dn2, 1, cn2 + _alphap2 * sn2) / 3);
|
387
|
+
// Enforce usual trig-like symmetries
|
388
|
+
if (cn < 0)
|
389
|
+
gi = 2 * G() - gi;
|
390
|
+
if (sn < 0)
|
391
|
+
gi = -gi;
|
392
|
+
return gi;
|
393
|
+
}
|
394
|
+
|
395
|
+
Math::real EllipticFunction::H(real sn, real cn, real dn) const {
|
396
|
+
real
|
397
|
+
cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn,
|
398
|
+
hi = abs(sn) * (RF(cn2, dn2, 1) -
|
399
|
+
_alphap2 * sn2 *
|
400
|
+
RJ(cn2, dn2, 1, cn2 + _alphap2 * sn2) / 3);
|
401
|
+
// Enforce usual trig-like symmetries
|
402
|
+
if (cn < 0)
|
403
|
+
hi = 2 * H() - hi;
|
404
|
+
if (sn < 0)
|
405
|
+
hi = -hi;
|
406
|
+
return hi;
|
407
|
+
}
|
408
|
+
|
409
|
+
Math::real EllipticFunction::deltaF(real sn, real cn, real dn) const {
|
410
|
+
// Function is periodic with period pi
|
411
|
+
if (cn < 0) { cn = -cn; sn = -sn; }
|
412
|
+
return F(sn, cn, dn) * (Math::pi()/2) / K() - atan2(sn, cn);
|
413
|
+
}
|
414
|
+
|
415
|
+
Math::real EllipticFunction::deltaE(real sn, real cn, real dn) const {
|
416
|
+
// Function is periodic with period pi
|
417
|
+
if (cn < 0) { cn = -cn; sn = -sn; }
|
418
|
+
return E(sn, cn, dn) * (Math::pi()/2) / E() - atan2(sn, cn);
|
419
|
+
}
|
420
|
+
|
421
|
+
Math::real EllipticFunction::deltaPi(real sn, real cn, real dn)
|
422
|
+
const {
|
423
|
+
// Function is periodic with period pi
|
424
|
+
if (cn < 0) { cn = -cn; sn = -sn; }
|
425
|
+
return Pi(sn, cn, dn) * (Math::pi()/2) / Pi() - atan2(sn, cn);
|
426
|
+
}
|
427
|
+
|
428
|
+
Math::real EllipticFunction::deltaD(real sn, real cn, real dn) const {
|
429
|
+
// Function is periodic with period pi
|
430
|
+
if (cn < 0) { cn = -cn; sn = -sn; }
|
431
|
+
return D(sn, cn, dn) * (Math::pi()/2) / D() - atan2(sn, cn);
|
432
|
+
}
|
433
|
+
|
434
|
+
Math::real EllipticFunction::deltaG(real sn, real cn, real dn) const {
|
435
|
+
// Function is periodic with period pi
|
436
|
+
if (cn < 0) { cn = -cn; sn = -sn; }
|
437
|
+
return G(sn, cn, dn) * (Math::pi()/2) / G() - atan2(sn, cn);
|
438
|
+
}
|
439
|
+
|
440
|
+
Math::real EllipticFunction::deltaH(real sn, real cn, real dn) const {
|
441
|
+
// Function is periodic with period pi
|
442
|
+
if (cn < 0) { cn = -cn; sn = -sn; }
|
443
|
+
return H(sn, cn, dn) * (Math::pi()/2) / H() - atan2(sn, cn);
|
444
|
+
}
|
445
|
+
|
446
|
+
Math::real EllipticFunction::F(real phi) const {
|
447
|
+
real sn = sin(phi), cn = cos(phi);
|
448
|
+
return (deltaF(sn, cn, Delta(sn, cn)) + phi) * K() / (Math::pi()/2);
|
449
|
+
}
|
450
|
+
|
451
|
+
Math::real EllipticFunction::E(real phi) const {
|
452
|
+
real sn = sin(phi), cn = cos(phi);
|
453
|
+
return (deltaE(sn, cn, Delta(sn, cn)) + phi) * E() / (Math::pi()/2);
|
454
|
+
}
|
455
|
+
|
456
|
+
Math::real EllipticFunction::Ed(real ang) const {
|
457
|
+
real n = ceil(ang/360 - real(0.5));
|
458
|
+
ang -= 360 * n;
|
459
|
+
real sn, cn;
|
460
|
+
Math::sincosd(ang, sn, cn);
|
461
|
+
return E(sn, cn, Delta(sn, cn)) + 4 * E() * n;
|
462
|
+
}
|
463
|
+
|
464
|
+
Math::real EllipticFunction::Pi(real phi) const {
|
465
|
+
real sn = sin(phi), cn = cos(phi);
|
466
|
+
return (deltaPi(sn, cn, Delta(sn, cn)) + phi) * Pi() / (Math::pi()/2);
|
467
|
+
}
|
468
|
+
|
469
|
+
Math::real EllipticFunction::D(real phi) const {
|
470
|
+
real sn = sin(phi), cn = cos(phi);
|
471
|
+
return (deltaD(sn, cn, Delta(sn, cn)) + phi) * D() / (Math::pi()/2);
|
472
|
+
}
|
473
|
+
|
474
|
+
Math::real EllipticFunction::G(real phi) const {
|
475
|
+
real sn = sin(phi), cn = cos(phi);
|
476
|
+
return (deltaG(sn, cn, Delta(sn, cn)) + phi) * G() / (Math::pi()/2);
|
477
|
+
}
|
478
|
+
|
479
|
+
Math::real EllipticFunction::H(real phi) const {
|
480
|
+
real sn = sin(phi), cn = cos(phi);
|
481
|
+
return (deltaH(sn, cn, Delta(sn, cn)) + phi) * H() / (Math::pi()/2);
|
482
|
+
}
|
483
|
+
|
484
|
+
Math::real EllipticFunction::Einv(real x) const {
|
485
|
+
real tolJAC = sqrt(numeric_limits<real>::epsilon() * real(0.01));
|
486
|
+
real n = floor(x / (2 * _Ec) + 0.5);
|
487
|
+
x -= 2 * _Ec * n; // x now in [-ec, ec)
|
488
|
+
// Linear approximation
|
489
|
+
real phi = Math::pi() * x / (2 * _Ec); // phi in [-pi/2, pi/2)
|
490
|
+
// First order correction
|
491
|
+
phi -= _eps * sin(2 * phi) / 2;
|
492
|
+
for (int i = 0; i < num_ || GEOGRAPHICLIB_PANIC; ++i) {
|
493
|
+
real
|
494
|
+
sn = sin(phi),
|
495
|
+
cn = cos(phi),
|
496
|
+
dn = Delta(sn, cn),
|
497
|
+
err = (E(sn, cn, dn) - x)/dn;
|
498
|
+
phi = phi - err;
|
499
|
+
if (abs(err) < tolJAC)
|
500
|
+
break;
|
501
|
+
}
|
502
|
+
return n * Math::pi() + phi;
|
503
|
+
}
|
504
|
+
|
505
|
+
Math::real EllipticFunction::deltaEinv(real stau, real ctau) const {
|
506
|
+
// Function is periodic with period pi
|
507
|
+
if (ctau < 0) { ctau = -ctau; stau = -stau; }
|
508
|
+
real tau = atan2(stau, ctau);
|
509
|
+
return Einv( tau * E() / (Math::pi()/2) ) - tau;
|
510
|
+
}
|
511
|
+
|
512
|
+
} // namespace GeographicLib
|