geographiclib 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fa8370a9028f271543b408485a76114b2d7f396f
4
+ data.tar.gz: 21443c4c505ce041d24155701c38e4a5a3ffa420
5
+ SHA512:
6
+ metadata.gz: 3c0efaf0dbadca39751487f1626cb3124b6554fb66e367455e9431316944bcbe5dfb19af4517009349730d306dd59e8c5e07a1bb5c693598cb7dcf3232c9a4ad
7
+ data.tar.gz: 6b4e08090d147a0e4ebaf5adf219485b4f20c7b1b749facbffe63193706b3b5ec4eec4f74bf3049365e4e22f1ce5e45bdcd33a4a2d7ac520be9569b17ab4ad8a
data/AUTHORS ADDED
@@ -0,0 +1,12 @@
1
+ Charles Karney <charles@karney.com>
2
+ Francesco Paolo Lovergine <frankie@debian.org> (autoconfiscation)
3
+ Mathieu Peyréga <mathieu.peyrega@gmail.com> (help with gravity models)
4
+ Andrew MacIntyre <Andrew.MacIntyre@acma.gov.au> (python/setup.py)
5
+ Skip Breidbach <skip@waywally.com> (maven support for Java)
6
+ Scott Heiman <mrmtdew2@outlook.com> (.NET wrappers + C# examples)
7
+ Chris Bennight <chris@bennight.com> (deploying Java library)
8
+ Sebastian Mattheis <Sebastian.Mattheis@bmw.de> (gnomonic projection in Java)
9
+ Yurij Mikhalevich <0@39.yt> (node.js port)
10
+ Phil Miller <phillip.miller@sri.com> (putting tests into python/setup.py)
11
+ Jonathan Takahashi <jtakahashi@gmail.com> (boost-python sample)
12
+ Lukas Joeressen <lukas@joeressen.net> (Ruby wrapper)
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ The MIT License (MIT); this license applies to GeographicLib,
2
+ versions 1.12 and later.
3
+
4
+ Copyright (c) 2008-2016, Charles Karney
5
+
6
+ Permission is hereby granted, free of charge, to any person
7
+ obtaining a copy of this software and associated documentation
8
+ files (the "Software"), to deal in the Software without
9
+ restriction, including without limitation the rights to use, copy,
10
+ modify, merge, publish, distribute, sublicense, and/or sell copies
11
+ of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24
+ DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,23 @@
1
+ /**
2
+ * \file Accumulator.cpp
3
+ * \brief Implementation for GeographicLib::Accumulator class
4
+ *
5
+ * Copyright (c) Charles Karney (2013) <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/Accumulator.hpp>
11
+
12
+ namespace GeographicLib {
13
+
14
+ /// \cond SKIP
15
+
16
+ // Need to instantiate Accumulator to get the code into the shared library
17
+ // (without this, NETGeographic complains about not finding the == and !=
18
+ // operators).
19
+ template class GEOGRAPHICLIB_EXPORT Accumulator<Math::real>;
20
+
21
+ /// \endcond
22
+
23
+ } // namespace GeographicLib
@@ -0,0 +1,445 @@
1
+ /**
2
+ * \file AlbersEqualArea.cpp
3
+ * \brief Implementation for GeographicLib::AlbersEqualArea class
4
+ *
5
+ * Copyright (c) Charles Karney (2010-2015) <charles@karney.com> and licensed
6
+ * under the MIT/X11 License. For more information, see
7
+ * http://geographiclib.sourceforge.net/
8
+ **********************************************************************/
9
+
10
+ #include <GeographicLib/AlbersEqualArea.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
+ AlbersEqualArea::AlbersEqualArea(real a, real f, real stdlat, real k0)
22
+ : eps_(numeric_limits<real>::epsilon())
23
+ , epsx_(Math::sq(eps_))
24
+ , epsx2_(Math::sq(epsx_))
25
+ , tol_(sqrt(eps_))
26
+ , tol0_(tol_ * sqrt(sqrt(eps_)))
27
+ , _a(a)
28
+ , _f(f)
29
+ , _fm(1 - _f)
30
+ , _e2(_f * (2 - _f))
31
+ , _e(sqrt(abs(_e2)))
32
+ , _e2m(1 - _e2)
33
+ , _qZ(1 + _e2m * atanhee(real(1)))
34
+ , _qx(_qZ / ( 2 * _e2m ))
35
+ {
36
+ if (!(Math::isfinite(_a) && _a > 0))
37
+ throw GeographicErr("Major radius is not positive");
38
+ if (!(Math::isfinite(_f) && _f < 1))
39
+ throw GeographicErr("Minor radius is not positive");
40
+ if (!(Math::isfinite(k0) && k0 > 0))
41
+ throw GeographicErr("Scale is not positive");
42
+ if (!(abs(stdlat) <= 90))
43
+ throw GeographicErr("Standard latitude not in [-90d, 90d]");
44
+ real sphi, cphi;
45
+ Math::sincosd(stdlat, sphi, cphi);
46
+ Init(sphi, cphi, sphi, cphi, k0);
47
+ }
48
+
49
+ AlbersEqualArea::AlbersEqualArea(real a, real f, real stdlat1, real stdlat2,
50
+ real k1)
51
+ : eps_(numeric_limits<real>::epsilon())
52
+ , epsx_(Math::sq(eps_))
53
+ , epsx2_(Math::sq(epsx_))
54
+ , tol_(sqrt(eps_))
55
+ , tol0_(tol_ * sqrt(sqrt(eps_)))
56
+ , _a(a)
57
+ , _f(f)
58
+ , _fm(1 - _f)
59
+ , _e2(_f * (2 - _f))
60
+ , _e(sqrt(abs(_e2)))
61
+ , _e2m(1 - _e2)
62
+ , _qZ(1 + _e2m * atanhee(real(1)))
63
+ , _qx(_qZ / ( 2 * _e2m ))
64
+ {
65
+ if (!(Math::isfinite(_a) && _a > 0))
66
+ throw GeographicErr("Major radius is not positive");
67
+ if (!(Math::isfinite(_f) && _f < 1))
68
+ throw GeographicErr("Minor radius is not positive");
69
+ if (!(Math::isfinite(k1) && k1 > 0))
70
+ throw GeographicErr("Scale is not positive");
71
+ if (!(abs(stdlat1) <= 90))
72
+ throw GeographicErr("Standard latitude 1 not in [-90d, 90d]");
73
+ if (!(abs(stdlat2) <= 90))
74
+ throw GeographicErr("Standard latitude 2 not in [-90d, 90d]");
75
+ real sphi1, cphi1, sphi2, cphi2;
76
+ Math::sincosd(stdlat1, sphi1, cphi1);
77
+ Math::sincosd(stdlat2, sphi2, cphi2);
78
+ Init(sphi1, cphi1, sphi2, cphi2, k1);
79
+ }
80
+
81
+ AlbersEqualArea::AlbersEqualArea(real a, real f,
82
+ real sinlat1, real coslat1,
83
+ real sinlat2, real coslat2,
84
+ real k1)
85
+ : eps_(numeric_limits<real>::epsilon())
86
+ , epsx_(Math::sq(eps_))
87
+ , epsx2_(Math::sq(epsx_))
88
+ , tol_(sqrt(eps_))
89
+ , tol0_(tol_ * sqrt(sqrt(eps_)))
90
+ , _a(a)
91
+ , _f(f)
92
+ , _fm(1 - _f)
93
+ , _e2(_f * (2 - _f))
94
+ , _e(sqrt(abs(_e2)))
95
+ , _e2m(1 - _e2)
96
+ , _qZ(1 + _e2m * atanhee(real(1)))
97
+ , _qx(_qZ / ( 2 * _e2m ))
98
+ {
99
+ if (!(Math::isfinite(_a) && _a > 0))
100
+ throw GeographicErr("Major radius is not positive");
101
+ if (!(Math::isfinite(_f) && _f < 1))
102
+ throw GeographicErr("Minor radius is not positive");
103
+ if (!(Math::isfinite(k1) && k1 > 0))
104
+ throw GeographicErr("Scale is not positive");
105
+ if (!(coslat1 >= 0))
106
+ throw GeographicErr("Standard latitude 1 not in [-90d, 90d]");
107
+ if (!(coslat2 >= 0))
108
+ throw GeographicErr("Standard latitude 2 not in [-90d, 90d]");
109
+ if (!(abs(sinlat1) <= 1 && coslat1 <= 1) || (coslat1 == 0 && sinlat1 == 0))
110
+ throw GeographicErr("Bad sine/cosine of standard latitude 1");
111
+ if (!(abs(sinlat2) <= 1 && coslat2 <= 1) || (coslat2 == 0 && sinlat2 == 0))
112
+ throw GeographicErr("Bad sine/cosine of standard latitude 2");
113
+ if (coslat1 == 0 && coslat2 == 0 && sinlat1 * sinlat2 <= 0)
114
+ throw GeographicErr
115
+ ("Standard latitudes cannot be opposite poles");
116
+ Init(sinlat1, coslat1, sinlat2, coslat2, k1);
117
+ }
118
+
119
+ void AlbersEqualArea::Init(real sphi1, real cphi1,
120
+ real sphi2, real cphi2, real k1) {
121
+ {
122
+ real r;
123
+ r = Math::hypot(sphi1, cphi1);
124
+ sphi1 /= r; cphi1 /= r;
125
+ r = Math::hypot(sphi2, cphi2);
126
+ sphi2 /= r; cphi2 /= r;
127
+ }
128
+ bool polar = (cphi1 == 0);
129
+ cphi1 = max(epsx_, cphi1); // Avoid singularities at poles
130
+ cphi2 = max(epsx_, cphi2);
131
+ // Determine hemisphere of tangent latitude
132
+ _sign = sphi1 + sphi2 >= 0 ? 1 : -1;
133
+ // Internally work with tangent latitude positive
134
+ sphi1 *= _sign; sphi2 *= _sign;
135
+ if (sphi1 > sphi2) {
136
+ swap(sphi1, sphi2); swap(cphi1, cphi2); // Make phi1 < phi2
137
+ }
138
+ real
139
+ tphi1 = sphi1/cphi1, tphi2 = sphi2/cphi2;
140
+
141
+ // q = (1-e^2)*(sphi/(1-e^2*sphi^2) - atanhee(sphi))
142
+ // qZ = q(pi/2) = (1 + (1-e^2)*atanhee(1))
143
+ // atanhee(x) = atanh(e*x)/e
144
+ // q = sxi * qZ
145
+ // dq/dphi = 2*(1-e^2)*cphi/(1-e^2*sphi^2)^2
146
+ //
147
+ // n = (m1^2-m2^2)/(q2-q1) -> sin(phi0) for phi1, phi2 -> phi0
148
+ // C = m1^2 + n*q1 = (m1^2*q2-m2^2*q1)/(q2-q1)
149
+ // let
150
+ // rho(pi/2)/rho(-pi/2) = (1-s)/(1+s)
151
+ // s = n*qZ/C
152
+ // = qZ * (m1^2-m2^2)/(m1^2*q2-m2^2*q1)
153
+ // = qZ * (scbet2^2 - scbet1^2)/(scbet2^2*q2 - scbet1^2*q1)
154
+ // = (scbet2^2 - scbet1^2)/(scbet2^2*sxi2 - scbet1^2*sxi1)
155
+ // = (tbet2^2 - tbet1^2)/(scbet2^2*sxi2 - scbet1^2*sxi1)
156
+ // 1-s = -((1-sxi2)*scbet2^2 - (1-sxi1)*scbet1^2)/
157
+ // (scbet2^2*sxi2 - scbet1^2*sxi1)
158
+ //
159
+ // Define phi0 to give same value of s, i.e.,
160
+ // s = sphi0 * qZ / (m0^2 + sphi0*q0)
161
+ // = sphi0 * scbet0^2 / (1/qZ + sphi0 * scbet0^2 * sxi0)
162
+
163
+ real tphi0, C;
164
+ if (polar || tphi1 == tphi2) {
165
+ tphi0 = tphi2;
166
+ C = 1; // ignored
167
+ } else {
168
+ real
169
+ tbet1 = _fm * tphi1, scbet12 = 1 + Math::sq(tbet1),
170
+ tbet2 = _fm * tphi2, scbet22 = 1 + Math::sq(tbet2),
171
+ txi1 = txif(tphi1), cxi1 = 1/hyp(txi1), sxi1 = txi1 * cxi1,
172
+ txi2 = txif(tphi2), cxi2 = 1/hyp(txi2), sxi2 = txi2 * cxi2,
173
+ dtbet2 = _fm * (tbet1 + tbet2),
174
+ es1 = 1 - _e2 * Math::sq(sphi1), es2 = 1 - _e2 * Math::sq(sphi2),
175
+ /*
176
+ dsxi = ( (_e2 * sq(sphi2 + sphi1) + es2 + es1) / (2 * es2 * es1) +
177
+ Datanhee(sphi2, sphi1) ) * Dsn(tphi2, tphi1, sphi2, sphi1) /
178
+ ( 2 * _qx ),
179
+ */
180
+ dsxi = ( (1 + _e2 * sphi1 * sphi2) / (es2 * es1) +
181
+ Datanhee(sphi2, sphi1) ) * Dsn(tphi2, tphi1, sphi2, sphi1) /
182
+ ( 2 * _qx ),
183
+ den = (sxi2 + sxi1) * dtbet2 + (scbet22 + scbet12) * dsxi,
184
+ // s = (sq(tbet2) - sq(tbet1)) / (scbet22*sxi2 - scbet12*sxi1)
185
+ s = 2 * dtbet2 / den,
186
+ // 1-s = -(sq(scbet2)*(1-sxi2) - sq(scbet1)*(1-sxi1)) /
187
+ // (scbet22*sxi2 - scbet12*sxi1)
188
+ // Write
189
+ // sq(scbet)*(1-sxi) = sq(scbet)*(1-sphi) * (1-sxi)/(1-sphi)
190
+ sm1 = -Dsn(tphi2, tphi1, sphi2, sphi1) *
191
+ ( -( ((sphi2 <= 0 ? (1 - sxi2) / (1 - sphi2) :
192
+ Math::sq(cxi2/cphi2) * (1 + sphi2) / (1 + sxi2)) +
193
+ (sphi1 <= 0 ? (1 - sxi1) / (1 - sphi1) :
194
+ Math::sq(cxi1/cphi1) * (1 + sphi1) / (1 + sxi1))) ) *
195
+ (1 + _e2 * (sphi1 + sphi2 + sphi1 * sphi2)) /
196
+ (1 + (sphi1 + sphi2 + sphi1 * sphi2)) +
197
+ (scbet22 * (sphi2 <= 0 ? 1 - sphi2 : Math::sq(cphi2) / ( 1 + sphi2)) +
198
+ scbet12 * (sphi1 <= 0 ? 1 - sphi1 : Math::sq(cphi1) / ( 1 + sphi1)))
199
+ * (_e2 * (1 + sphi1 + sphi2 + _e2 * sphi1 * sphi2)/(es1 * es2)
200
+ +_e2m * DDatanhee(sphi1, sphi2) ) / _qZ ) / den;
201
+ // C = (scbet22*sxi2 - scbet12*sxi1) / (scbet22 * scbet12 * (sx2 - sx1))
202
+ C = den / (2 * scbet12 * scbet22 * dsxi);
203
+ tphi0 = (tphi2 + tphi1)/2;
204
+ real stol = tol0_ * max(real(1), abs(tphi0));
205
+ for (int i = 0; i < 2*numit0_ || GEOGRAPHICLIB_PANIC; ++i) {
206
+ // Solve (scbet0^2 * sphi0) / (1/qZ + scbet0^2 * sphi0 * sxi0) = s
207
+ // for tphi0 by Newton's method on
208
+ // v(tphi0) = (scbet0^2 * sphi0) - s * (1/qZ + scbet0^2 * sphi0 * sxi0)
209
+ // = 0
210
+ // Alt:
211
+ // (scbet0^2 * sphi0) / (1/qZ - scbet0^2 * sphi0 * (1-sxi0)) = s / (1-s)
212
+ // w(tphi0) = (1-s) * (scbet0^2 * sphi0)
213
+ // - s * (1/qZ - scbet0^2 * sphi0 * (1-sxi0))
214
+ // = (1-s) * (scbet0^2 * sphi0)
215
+ // - S/qZ * (1 - scbet0^2 * sphi0 * (qZ-q0))
216
+ // Now
217
+ // qZ-q0 = (1+e2*sphi0)*(1-sphi0)/(1-e2*sphi0^2) +
218
+ // (1-e2)*atanhee((1-sphi0)/(1-e2*sphi0))
219
+ // In limit sphi0 -> 1, qZ-q0 -> 2*(1-sphi0)/(1-e2), so wrte
220
+ // qZ-q0 = 2*(1-sphi0)/(1-e2) + A + B
221
+ // A = (1-sphi0)*( (1+e2*sphi0)/(1-e2*sphi0^2) - (1+e2)/(1-e2) )
222
+ // = -e2 *(1-sphi0)^2 * (2+(1+e2)*sphi0) / ((1-e2)*(1-e2*sphi0^2))
223
+ // B = (1-e2)*atanhee((1-sphi0)/(1-e2*sphi0)) - (1-sphi0)
224
+ // = (1-sphi0)*(1-e2)/(1-e2*sphi0)*
225
+ // ((atanhee(x)/x-1) - e2*(1-sphi0)/(1-e2))
226
+ // x = (1-sphi0)/(1-e2*sphi0), atanhee(x)/x = atanh(e*x)/(e*x)
227
+ //
228
+ // 1 - scbet0^2 * sphi0 * (qZ-q0)
229
+ // = 1 - scbet0^2 * sphi0 * (2*(1-sphi0)/(1-e2) + A + B)
230
+ // = D - scbet0^2 * sphi0 * (A + B)
231
+ // D = 1 - scbet0^2 * sphi0 * 2*(1-sphi0)/(1-e2)
232
+ // = (1-sphi0)*(1-e2*(1+2*sphi0*(1+sphi0)))/((1-e2)*(1+sphi0))
233
+ // dD/dsphi0 = -2*(1-e2*sphi0^2*(2*sphi0+3))/((1-e2)*(1+sphi0)^2)
234
+ // d(A+B)/dsphi0 = 2*(1-sphi0^2)*e2*(2-e2*(1+sphi0^2))/
235
+ // ((1-e2)*(1-e2*sphi0^2)^2)
236
+
237
+ real
238
+ scphi02 = 1 + Math::sq(tphi0), scphi0 = sqrt(scphi02),
239
+ // sphi0m = 1-sin(phi0) = 1/( sec(phi0) * (tan(phi0) + sec(phi0)) )
240
+ sphi0 = tphi0 / scphi0, sphi0m = 1/(scphi0 * (tphi0 + scphi0)),
241
+ // scbet0^2 * sphi0
242
+ g = (1 + Math::sq( _fm * tphi0 )) * sphi0,
243
+ // dg/dsphi0 = dg/dtphi0 * scphi0^3
244
+ dg = _e2m * scphi02 * (1 + 2 * Math::sq(tphi0)) + _e2,
245
+ D = sphi0m * (1 - _e2*(1 + 2*sphi0*(1+sphi0))) / (_e2m * (1+sphi0)),
246
+ // dD/dsphi0
247
+ dD = -2 * (1 - _e2*Math::sq(sphi0) * (2*sphi0+3)) /
248
+ (_e2m * Math::sq(1+sphi0)),
249
+ A = -_e2 * Math::sq(sphi0m) * (2+(1+_e2)*sphi0) /
250
+ (_e2m*(1-_e2*Math::sq(sphi0))),
251
+ B = (sphi0m * _e2m / (1 - _e2*sphi0) *
252
+ (atanhxm1(_e2 *
253
+ Math::sq(sphi0m / (1-_e2*sphi0))) - _e2*sphi0m/_e2m)),
254
+ // d(A+B)/dsphi0
255
+ dAB = (2 * _e2 * (2 - _e2 * (1 + Math::sq(sphi0))) /
256
+ (_e2m * Math::sq(1 - _e2*Math::sq(sphi0)) * scphi02)),
257
+ u = sm1 * g - s/_qZ * ( D - g * (A + B) ),
258
+ // du/dsphi0
259
+ du = sm1 * dg - s/_qZ * (dD - dg * (A + B) - g * dAB),
260
+ dtu = -u/du * (scphi0 * scphi02);
261
+ tphi0 += dtu;
262
+ if (!(abs(dtu) >= stol))
263
+ break;
264
+ }
265
+ }
266
+ _txi0 = txif(tphi0); _scxi0 = hyp(_txi0); _sxi0 = _txi0 / _scxi0;
267
+ _n0 = tphi0/hyp(tphi0);
268
+ _m02 = 1 / (1 + Math::sq(_fm * tphi0));
269
+ _nrho0 = polar ? 0 : _a * sqrt(_m02);
270
+ _k0 = sqrt(tphi1 == tphi2 ? 1 : C / (_m02 + _n0 * _qZ * _sxi0)) * k1;
271
+ _k2 = Math::sq(_k0);
272
+ _lat0 = _sign * atan(tphi0)/Math::degree();
273
+ }
274
+
275
+ const AlbersEqualArea& AlbersEqualArea::CylindricalEqualArea() {
276
+ static const AlbersEqualArea
277
+ cylindricalequalarea(Constants::WGS84_a(), Constants::WGS84_f(),
278
+ real(0), real(1), real(0), real(1), real(1));
279
+ return cylindricalequalarea;
280
+ }
281
+
282
+ const AlbersEqualArea& AlbersEqualArea::AzimuthalEqualAreaNorth() {
283
+ static const AlbersEqualArea
284
+ azimuthalequalareanorth(Constants::WGS84_a(), Constants::WGS84_f(),
285
+ real(1), real(0), real(1), real(0), real(1));
286
+ return azimuthalequalareanorth;
287
+ }
288
+
289
+ const AlbersEqualArea& AlbersEqualArea::AzimuthalEqualAreaSouth() {
290
+ static const AlbersEqualArea
291
+ azimuthalequalareasouth(Constants::WGS84_a(), Constants::WGS84_f(),
292
+ real(-1), real(0), real(-1), real(0), real(1));
293
+ return azimuthalequalareasouth;
294
+ }
295
+
296
+ Math::real AlbersEqualArea::txif(real tphi) const {
297
+ // sxi = ( sphi/(1-e2*sphi^2) + atanhee(sphi) ) /
298
+ // ( 1/(1-e2) + atanhee(1) )
299
+ //
300
+ // txi = ( sphi/(1-e2*sphi^2) + atanhee(sphi) ) /
301
+ // sqrt( ( (1+e2*sphi)*(1-sphi)/( (1-e2*sphi^2) * (1-e2) ) +
302
+ // atanhee((1-sphi)/(1-e2*sphi)) ) *
303
+ // ( (1-e2*sphi)*(1+sphi)/( (1-e2*sphi^2) * (1-e2) ) +
304
+ // atanhee((1+sphi)/(1+e2*sphi)) ) )
305
+ //
306
+ // subst 1-sphi = cphi^2/(1+sphi)
307
+ int s = tphi < 0 ? -1 : 1; // Enforce odd parity
308
+ tphi *= s;
309
+ real
310
+ cphi2 = 1 / (1 + Math::sq(tphi)),
311
+ sphi = tphi * sqrt(cphi2),
312
+ es1 = _e2 * sphi,
313
+ es2m1 = 1 - es1 * sphi,
314
+ sp1 = 1 + sphi,
315
+ es1m1 = (1 - es1) * sp1,
316
+ es2m1a = _e2m * es2m1,
317
+ es1p1 = sp1 / (1 + es1);
318
+ return s * ( sphi / es2m1 + atanhee(sphi) ) /
319
+ sqrt( ( cphi2 / (es1p1 * es2m1a) + atanhee(cphi2 / es1m1) ) *
320
+ ( es1m1 / es2m1a + atanhee(es1p1) ) );
321
+ }
322
+
323
+ Math::real AlbersEqualArea::tphif(real txi) const {
324
+ real
325
+ tphi = txi,
326
+ stol = tol_ * max(real(1), abs(txi));
327
+ // CHECK: min iterations = 1, max iterations = 2; mean = 1.99
328
+ for (int i = 0; i < numit_ || GEOGRAPHICLIB_PANIC; ++i) {
329
+ // dtxi/dtphi = (scxi/scphi)^3 * 2*(1-e^2)/(qZ*(1-e^2*sphi^2)^2)
330
+ real
331
+ txia = txif(tphi),
332
+ tphi2 = Math::sq(tphi),
333
+ scphi2 = 1 + tphi2,
334
+ scterm = scphi2/(1 + Math::sq(txia)),
335
+ dtphi = (txi - txia) * scterm * sqrt(scterm) *
336
+ _qx * Math::sq(1 - _e2 * tphi2 / scphi2);
337
+ tphi += dtphi;
338
+ if (!(abs(dtphi) >= stol))
339
+ break;
340
+ }
341
+ return tphi;
342
+ }
343
+
344
+ // return atanh(sqrt(x))/sqrt(x) - 1 = y/3 + y^2/5 + y^3/7 + ...
345
+ // typical x < e^2 = 2*f
346
+ Math::real AlbersEqualArea::atanhxm1(real x) {
347
+ real s = 0;
348
+ if (abs(x) < real(0.5)) {
349
+ real os = -1, y = 1, k = 1;
350
+ while (os != s) {
351
+ os = s;
352
+ y *= x; // y = x^n
353
+ k += 2; // k = 2*n + 1
354
+ s += y/k; // sum( x^n/(2*n + 1) )
355
+ }
356
+ } else {
357
+ real xs = sqrt(abs(x));
358
+ s = (x > 0 ? Math::atanh(xs) : atan(xs)) / xs - 1;
359
+ }
360
+ return s;
361
+ }
362
+
363
+ // return (Datanhee(1,y) - Datanhee(1,x))/(y-x)
364
+ Math::real AlbersEqualArea::DDatanhee(real x, real y) const {
365
+ real s = 0;
366
+ if (_e2 * (abs(x) + abs(y)) < real(0.5)) {
367
+ real os = -1, z = 1, k = 1, t = 0, c = 0, en = 1;
368
+ while (os != s) {
369
+ os = s;
370
+ t = y * t + z; c += t; z *= x;
371
+ t = y * t + z; c += t; z *= x;
372
+ k += 2; en *= _e2;
373
+ // Here en[l] = e2^l, k[l] = 2*l + 1,
374
+ // c[l] = sum( x^i * y^j; i >= 0, j >= 0, i+j < 2*l)
375
+ s += en * c / k;
376
+ }
377
+ // Taylor expansion is
378
+ // s = sum( c[l] * e2^l / (2*l + 1), l, 1, N)
379
+ } else
380
+ s = (Datanhee(1, y) - Datanhee(x, y))/(1 - x);
381
+ return s;
382
+ }
383
+
384
+ void AlbersEqualArea::Forward(real lon0, real lat, real lon,
385
+ real& x, real& y, real& gamma, real& k)
386
+ const {
387
+ lon = Math::AngDiff(lon0, lon);
388
+ lat *= _sign;
389
+ real sphi, cphi;
390
+ Math::sincosd(Math::LatFix(lat) * _sign, sphi, cphi);
391
+ cphi = max(epsx_, cphi);
392
+ real
393
+ lam = lon * Math::degree(),
394
+ tphi = sphi/cphi, txi = txif(tphi), sxi = txi/hyp(txi),
395
+ dq = _qZ * Dsn(txi, _txi0, sxi, _sxi0) * (txi - _txi0),
396
+ drho = - _a * dq / (sqrt(_m02 - _n0 * dq) + _nrho0 / _a),
397
+ theta = _k2 * _n0 * lam, stheta = sin(theta), ctheta = cos(theta),
398
+ t = _nrho0 + _n0 * drho;
399
+ x = t * (_n0 ? stheta / _n0 : _k2 * lam) / _k0;
400
+ y = (_nrho0 *
401
+ (_n0 ?
402
+ (ctheta < 0 ? 1 - ctheta : Math::sq(stheta)/(1 + ctheta)) / _n0 :
403
+ 0)
404
+ - drho * ctheta) / _k0;
405
+ k = _k0 * (t ? t * hyp(_fm * tphi) / _a : 1);
406
+ y *= _sign;
407
+ gamma = _sign * theta / Math::degree();
408
+ }
409
+
410
+ void AlbersEqualArea::Reverse(real lon0, real x, real y,
411
+ real& lat, real& lon,
412
+ real& gamma, real& k)
413
+ const {
414
+ y *= _sign;
415
+ real
416
+ nx = _k0 * _n0 * x, ny = _k0 * _n0 * y, y1 = _nrho0 - ny,
417
+ den = Math::hypot(nx, y1) + _nrho0, // 0 implies origin with polar aspect
418
+ drho = den ? (_k0*x*nx - 2*_k0*y*_nrho0 + _k0*y*ny) / den : 0,
419
+ // dsxia = scxi0 * dsxi
420
+ dsxia = - _scxi0 * (2 * _nrho0 + _n0 * drho) * drho /
421
+ (Math::sq(_a) * _qZ),
422
+ txi = (_txi0 + dsxia) / sqrt(max(1 - dsxia * (2*_txi0 + dsxia), epsx2_)),
423
+ tphi = tphif(txi),
424
+ theta = atan2(nx, y1),
425
+ lam = _n0 ? theta / (_k2 * _n0) : x / (y1 * _k0);
426
+ gamma = _sign * theta / Math::degree();
427
+ lat = Math::atand(_sign * tphi);
428
+ lon = lam / Math::degree();
429
+ lon = Math::AngNormalize(lon + Math::AngNormalize(lon0));
430
+ k = _k0 * (den ? (_nrho0 + _n0 * drho) * hyp(_fm * tphi) / _a : 1);
431
+ }
432
+
433
+ void AlbersEqualArea::SetScale(real lat, real k) {
434
+ if (!(Math::isfinite(k) && k > 0))
435
+ throw GeographicErr("Scale is not positive");
436
+ if (!(abs(lat) < 90))
437
+ throw GeographicErr("Latitude for SetScale not in (-90d, 90d)");
438
+ real x, y, gamma, kold;
439
+ Forward(0, lat, 0, x, y, gamma, kold);
440
+ k /= kold;
441
+ _k0 *= k;
442
+ _k2 = Math::sq(_k0);
443
+ }
444
+
445
+ } // namespace GeographicLib