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.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +12 -0
  3. data/LICENSE +24 -0
  4. data/ext/geographiclib/Accumulator.cpp +23 -0
  5. data/ext/geographiclib/AlbersEqualArea.cpp +445 -0
  6. data/ext/geographiclib/AzimuthalEquidistant.cpp +41 -0
  7. data/ext/geographiclib/CassiniSoldner.cpp +89 -0
  8. data/ext/geographiclib/CircularEngine.cpp +96 -0
  9. data/ext/geographiclib/DMS.cpp +381 -0
  10. data/ext/geographiclib/Ellipsoid.cpp +125 -0
  11. data/ext/geographiclib/EllipticFunction.cpp +512 -0
  12. data/ext/geographiclib/GARS.cpp +122 -0
  13. data/ext/geographiclib/GeoCoords.cpp +175 -0
  14. data/ext/geographiclib/Geocentric.cpp +172 -0
  15. data/ext/geographiclib/Geodesic.cpp +1908 -0
  16. data/ext/geographiclib/GeodesicExact.cpp +927 -0
  17. data/ext/geographiclib/GeodesicExactC4.cpp +7879 -0
  18. data/ext/geographiclib/GeodesicLine.cpp +321 -0
  19. data/ext/geographiclib/GeodesicLineExact.cpp +289 -0
  20. data/ext/geographiclib/GeographicLib/Accumulator.hpp +184 -0
  21. data/ext/geographiclib/GeographicLib/AlbersEqualArea.hpp +312 -0
  22. data/ext/geographiclib/GeographicLib/AzimuthalEquidistant.hpp +139 -0
  23. data/ext/geographiclib/GeographicLib/CassiniSoldner.hpp +204 -0
  24. data/ext/geographiclib/GeographicLib/CircularEngine.hpp +195 -0
  25. data/ext/geographiclib/GeographicLib/Config.h +12 -0
  26. data/ext/geographiclib/GeographicLib/Constants.hpp +387 -0
  27. data/ext/geographiclib/GeographicLib/DMS.hpp +370 -0
  28. data/ext/geographiclib/GeographicLib/Ellipsoid.hpp +534 -0
  29. data/ext/geographiclib/GeographicLib/EllipticFunction.hpp +692 -0
  30. data/ext/geographiclib/GeographicLib/GARS.hpp +143 -0
  31. data/ext/geographiclib/GeographicLib/GeoCoords.hpp +544 -0
  32. data/ext/geographiclib/GeographicLib/Geocentric.hpp +267 -0
  33. data/ext/geographiclib/GeographicLib/Geodesic.hpp +970 -0
  34. data/ext/geographiclib/GeographicLib/GeodesicExact.hpp +862 -0
  35. data/ext/geographiclib/GeographicLib/GeodesicLine.hpp +701 -0
  36. data/ext/geographiclib/GeographicLib/GeodesicLineExact.hpp +667 -0
  37. data/ext/geographiclib/GeographicLib/Geohash.hpp +180 -0
  38. data/ext/geographiclib/GeographicLib/Geoid.hpp +472 -0
  39. data/ext/geographiclib/GeographicLib/Georef.hpp +160 -0
  40. data/ext/geographiclib/GeographicLib/Gnomonic.hpp +206 -0
  41. data/ext/geographiclib/GeographicLib/GravityCircle.hpp +301 -0
  42. data/ext/geographiclib/GeographicLib/GravityModel.hpp +520 -0
  43. data/ext/geographiclib/GeographicLib/LambertConformalConic.hpp +313 -0
  44. data/ext/geographiclib/GeographicLib/LocalCartesian.hpp +236 -0
  45. data/ext/geographiclib/GeographicLib/MGRS.hpp +355 -0
  46. data/ext/geographiclib/GeographicLib/MagneticCircle.hpp +178 -0
  47. data/ext/geographiclib/GeographicLib/MagneticModel.hpp +347 -0
  48. data/ext/geographiclib/GeographicLib/Math.hpp +920 -0
  49. data/ext/geographiclib/GeographicLib/NormalGravity.hpp +350 -0
  50. data/ext/geographiclib/GeographicLib/OSGB.hpp +249 -0
  51. data/ext/geographiclib/GeographicLib/PolarStereographic.hpp +150 -0
  52. data/ext/geographiclib/GeographicLib/PolygonArea.hpp +288 -0
  53. data/ext/geographiclib/GeographicLib/Rhumb.hpp +589 -0
  54. data/ext/geographiclib/GeographicLib/SphericalEngine.hpp +376 -0
  55. data/ext/geographiclib/GeographicLib/SphericalHarmonic.hpp +354 -0
  56. data/ext/geographiclib/GeographicLib/SphericalHarmonic1.hpp +281 -0
  57. data/ext/geographiclib/GeographicLib/SphericalHarmonic2.hpp +315 -0
  58. data/ext/geographiclib/GeographicLib/TransverseMercator.hpp +196 -0
  59. data/ext/geographiclib/GeographicLib/TransverseMercatorExact.hpp +254 -0
  60. data/ext/geographiclib/GeographicLib/UTMUPS.hpp +421 -0
  61. data/ext/geographiclib/GeographicLib/Utility.hpp +612 -0
  62. data/ext/geographiclib/Geohash.cpp +102 -0
  63. data/ext/geographiclib/Geoid.cpp +509 -0
  64. data/ext/geographiclib/Georef.cpp +135 -0
  65. data/ext/geographiclib/Gnomonic.cpp +85 -0
  66. data/ext/geographiclib/GravityCircle.cpp +129 -0
  67. data/ext/geographiclib/GravityModel.cpp +360 -0
  68. data/ext/geographiclib/LambertConformalConic.cpp +456 -0
  69. data/ext/geographiclib/LocalCartesian.cpp +62 -0
  70. data/ext/geographiclib/MGRS.cpp +461 -0
  71. data/ext/geographiclib/MagneticCircle.cpp +52 -0
  72. data/ext/geographiclib/MagneticModel.cpp +269 -0
  73. data/ext/geographiclib/Math.cpp +63 -0
  74. data/ext/geographiclib/NormalGravity.cpp +262 -0
  75. data/ext/geographiclib/OSGB.cpp +167 -0
  76. data/ext/geographiclib/PolarStereographic.cpp +108 -0
  77. data/ext/geographiclib/PolygonArea.cpp +204 -0
  78. data/ext/geographiclib/Rhumb.cpp +383 -0
  79. data/ext/geographiclib/SphericalEngine.cpp +477 -0
  80. data/ext/geographiclib/TransverseMercator.cpp +603 -0
  81. data/ext/geographiclib/TransverseMercatorExact.cpp +464 -0
  82. data/ext/geographiclib/UTMUPS.cpp +296 -0
  83. data/ext/geographiclib/Utility.cpp +61 -0
  84. data/ext/geographiclib/extconf.rb +3 -0
  85. data/ext/geographiclib/geographiclib.cpp +62 -0
  86. data/lib/geographiclib.rb +20 -0
  87. 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