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,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