geographiclib 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/AUTHORS +12 -0
- data/LICENSE +24 -0
- data/ext/geographiclib/Accumulator.cpp +23 -0
- data/ext/geographiclib/AlbersEqualArea.cpp +445 -0
- data/ext/geographiclib/AzimuthalEquidistant.cpp +41 -0
- data/ext/geographiclib/CassiniSoldner.cpp +89 -0
- data/ext/geographiclib/CircularEngine.cpp +96 -0
- data/ext/geographiclib/DMS.cpp +381 -0
- data/ext/geographiclib/Ellipsoid.cpp +125 -0
- data/ext/geographiclib/EllipticFunction.cpp +512 -0
- data/ext/geographiclib/GARS.cpp +122 -0
- data/ext/geographiclib/GeoCoords.cpp +175 -0
- data/ext/geographiclib/Geocentric.cpp +172 -0
- data/ext/geographiclib/Geodesic.cpp +1908 -0
- data/ext/geographiclib/GeodesicExact.cpp +927 -0
- data/ext/geographiclib/GeodesicExactC4.cpp +7879 -0
- data/ext/geographiclib/GeodesicLine.cpp +321 -0
- data/ext/geographiclib/GeodesicLineExact.cpp +289 -0
- data/ext/geographiclib/GeographicLib/Accumulator.hpp +184 -0
- data/ext/geographiclib/GeographicLib/AlbersEqualArea.hpp +312 -0
- data/ext/geographiclib/GeographicLib/AzimuthalEquidistant.hpp +139 -0
- data/ext/geographiclib/GeographicLib/CassiniSoldner.hpp +204 -0
- data/ext/geographiclib/GeographicLib/CircularEngine.hpp +195 -0
- data/ext/geographiclib/GeographicLib/Config.h +12 -0
- data/ext/geographiclib/GeographicLib/Constants.hpp +387 -0
- data/ext/geographiclib/GeographicLib/DMS.hpp +370 -0
- data/ext/geographiclib/GeographicLib/Ellipsoid.hpp +534 -0
- data/ext/geographiclib/GeographicLib/EllipticFunction.hpp +692 -0
- data/ext/geographiclib/GeographicLib/GARS.hpp +143 -0
- data/ext/geographiclib/GeographicLib/GeoCoords.hpp +544 -0
- data/ext/geographiclib/GeographicLib/Geocentric.hpp +267 -0
- data/ext/geographiclib/GeographicLib/Geodesic.hpp +970 -0
- data/ext/geographiclib/GeographicLib/GeodesicExact.hpp +862 -0
- data/ext/geographiclib/GeographicLib/GeodesicLine.hpp +701 -0
- data/ext/geographiclib/GeographicLib/GeodesicLineExact.hpp +667 -0
- data/ext/geographiclib/GeographicLib/Geohash.hpp +180 -0
- data/ext/geographiclib/GeographicLib/Geoid.hpp +472 -0
- data/ext/geographiclib/GeographicLib/Georef.hpp +160 -0
- data/ext/geographiclib/GeographicLib/Gnomonic.hpp +206 -0
- data/ext/geographiclib/GeographicLib/GravityCircle.hpp +301 -0
- data/ext/geographiclib/GeographicLib/GravityModel.hpp +520 -0
- data/ext/geographiclib/GeographicLib/LambertConformalConic.hpp +313 -0
- data/ext/geographiclib/GeographicLib/LocalCartesian.hpp +236 -0
- data/ext/geographiclib/GeographicLib/MGRS.hpp +355 -0
- data/ext/geographiclib/GeographicLib/MagneticCircle.hpp +178 -0
- data/ext/geographiclib/GeographicLib/MagneticModel.hpp +347 -0
- data/ext/geographiclib/GeographicLib/Math.hpp +920 -0
- data/ext/geographiclib/GeographicLib/NormalGravity.hpp +350 -0
- data/ext/geographiclib/GeographicLib/OSGB.hpp +249 -0
- data/ext/geographiclib/GeographicLib/PolarStereographic.hpp +150 -0
- data/ext/geographiclib/GeographicLib/PolygonArea.hpp +288 -0
- data/ext/geographiclib/GeographicLib/Rhumb.hpp +589 -0
- data/ext/geographiclib/GeographicLib/SphericalEngine.hpp +376 -0
- data/ext/geographiclib/GeographicLib/SphericalHarmonic.hpp +354 -0
- data/ext/geographiclib/GeographicLib/SphericalHarmonic1.hpp +281 -0
- data/ext/geographiclib/GeographicLib/SphericalHarmonic2.hpp +315 -0
- data/ext/geographiclib/GeographicLib/TransverseMercator.hpp +196 -0
- data/ext/geographiclib/GeographicLib/TransverseMercatorExact.hpp +254 -0
- data/ext/geographiclib/GeographicLib/UTMUPS.hpp +421 -0
- data/ext/geographiclib/GeographicLib/Utility.hpp +612 -0
- data/ext/geographiclib/Geohash.cpp +102 -0
- data/ext/geographiclib/Geoid.cpp +509 -0
- data/ext/geographiclib/Georef.cpp +135 -0
- data/ext/geographiclib/Gnomonic.cpp +85 -0
- data/ext/geographiclib/GravityCircle.cpp +129 -0
- data/ext/geographiclib/GravityModel.cpp +360 -0
- data/ext/geographiclib/LambertConformalConic.cpp +456 -0
- data/ext/geographiclib/LocalCartesian.cpp +62 -0
- data/ext/geographiclib/MGRS.cpp +461 -0
- data/ext/geographiclib/MagneticCircle.cpp +52 -0
- data/ext/geographiclib/MagneticModel.cpp +269 -0
- data/ext/geographiclib/Math.cpp +63 -0
- data/ext/geographiclib/NormalGravity.cpp +262 -0
- data/ext/geographiclib/OSGB.cpp +167 -0
- data/ext/geographiclib/PolarStereographic.cpp +108 -0
- data/ext/geographiclib/PolygonArea.cpp +204 -0
- data/ext/geographiclib/Rhumb.cpp +383 -0
- data/ext/geographiclib/SphericalEngine.cpp +477 -0
- data/ext/geographiclib/TransverseMercator.cpp +603 -0
- data/ext/geographiclib/TransverseMercatorExact.cpp +464 -0
- data/ext/geographiclib/UTMUPS.cpp +296 -0
- data/ext/geographiclib/Utility.cpp +61 -0
- data/ext/geographiclib/extconf.rb +3 -0
- data/ext/geographiclib/geographiclib.cpp +62 -0
- data/lib/geographiclib.rb +20 -0
- metadata +140 -0
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* \file LambertConformalConic.cpp
|
|
3
|
+
* \brief Implementation for GeographicLib::LambertConformalConic 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/LambertConformalConic.hpp>
|
|
11
|
+
|
|
12
|
+
namespace GeographicLib {
|
|
13
|
+
|
|
14
|
+
using namespace std;
|
|
15
|
+
|
|
16
|
+
LambertConformalConic::LambertConformalConic(real a, real f,
|
|
17
|
+
real stdlat, real k0)
|
|
18
|
+
: eps_(numeric_limits<real>::epsilon())
|
|
19
|
+
, epsx_(Math::sq(eps_))
|
|
20
|
+
, ahypover_(Math::digits() * log(real(numeric_limits<real>::radix)) + 2)
|
|
21
|
+
, _a(a)
|
|
22
|
+
, _f(f)
|
|
23
|
+
, _fm(1 - _f)
|
|
24
|
+
, _e2(_f * (2 - _f))
|
|
25
|
+
, _es((_f < 0 ? -1 : 1) * sqrt(abs(_e2)))
|
|
26
|
+
{
|
|
27
|
+
if (!(Math::isfinite(_a) && _a > 0))
|
|
28
|
+
throw GeographicErr("Major radius is not positive");
|
|
29
|
+
if (!(Math::isfinite(_f) && _f < 1))
|
|
30
|
+
throw GeographicErr("Minor radius is not positive");
|
|
31
|
+
if (!(Math::isfinite(k0) && k0 > 0))
|
|
32
|
+
throw GeographicErr("Scale is not positive");
|
|
33
|
+
if (!(abs(stdlat) <= 90))
|
|
34
|
+
throw GeographicErr("Standard latitude not in [-90d, 90d]");
|
|
35
|
+
real sphi, cphi;
|
|
36
|
+
Math::sincosd(stdlat, sphi, cphi);
|
|
37
|
+
Init(sphi, cphi, sphi, cphi, k0);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
LambertConformalConic::LambertConformalConic(real a, real f,
|
|
41
|
+
real stdlat1, real stdlat2,
|
|
42
|
+
real k1)
|
|
43
|
+
: eps_(numeric_limits<real>::epsilon())
|
|
44
|
+
, epsx_(Math::sq(eps_))
|
|
45
|
+
, ahypover_(Math::digits() * log(real(numeric_limits<real>::radix)) + 2)
|
|
46
|
+
, _a(a)
|
|
47
|
+
, _f(f)
|
|
48
|
+
, _fm(1 - _f)
|
|
49
|
+
, _e2(_f * (2 - _f))
|
|
50
|
+
, _es((_f < 0 ? -1 : 1) * sqrt(abs(_e2)))
|
|
51
|
+
{
|
|
52
|
+
if (!(Math::isfinite(_a) && _a > 0))
|
|
53
|
+
throw GeographicErr("Major radius is not positive");
|
|
54
|
+
if (!(Math::isfinite(_f) && _f < 1))
|
|
55
|
+
throw GeographicErr("Minor radius is not positive");
|
|
56
|
+
if (!(Math::isfinite(k1) && k1 > 0))
|
|
57
|
+
throw GeographicErr("Scale is not positive");
|
|
58
|
+
if (!(abs(stdlat1) <= 90))
|
|
59
|
+
throw GeographicErr("Standard latitude 1 not in [-90d, 90d]");
|
|
60
|
+
if (!(abs(stdlat2) <= 90))
|
|
61
|
+
throw GeographicErr("Standard latitude 2 not in [-90d, 90d]");
|
|
62
|
+
real sphi1, cphi1, sphi2, cphi2;
|
|
63
|
+
Math::sincosd(stdlat1, sphi1, cphi1);
|
|
64
|
+
Math::sincosd(stdlat2, sphi2, cphi2);
|
|
65
|
+
Init(sphi1, cphi1, sphi2, cphi2, k1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
LambertConformalConic::LambertConformalConic(real a, real f,
|
|
69
|
+
real sinlat1, real coslat1,
|
|
70
|
+
real sinlat2, real coslat2,
|
|
71
|
+
real k1)
|
|
72
|
+
: eps_(numeric_limits<real>::epsilon())
|
|
73
|
+
, epsx_(Math::sq(eps_))
|
|
74
|
+
, ahypover_(Math::digits() * log(real(numeric_limits<real>::radix)) + 2)
|
|
75
|
+
, _a(a)
|
|
76
|
+
, _f(f)
|
|
77
|
+
, _fm(1 - _f)
|
|
78
|
+
, _e2(_f * (2 - _f))
|
|
79
|
+
, _es((_f < 0 ? -1 : 1) * sqrt(abs(_e2)))
|
|
80
|
+
{
|
|
81
|
+
if (!(Math::isfinite(_a) && _a > 0))
|
|
82
|
+
throw GeographicErr("Major radius is not positive");
|
|
83
|
+
if (!(Math::isfinite(_f) && _f < 1))
|
|
84
|
+
throw GeographicErr("Minor radius is not positive");
|
|
85
|
+
if (!(Math::isfinite(k1) && k1 > 0))
|
|
86
|
+
throw GeographicErr("Scale is not positive");
|
|
87
|
+
if (!(coslat1 >= 0))
|
|
88
|
+
throw GeographicErr("Standard latitude 1 not in [-90d, 90d]");
|
|
89
|
+
if (!(coslat2 >= 0))
|
|
90
|
+
throw GeographicErr("Standard latitude 2 not in [-90d, 90d]");
|
|
91
|
+
if (!(abs(sinlat1) <= 1 && coslat1 <= 1) || (coslat1 == 0 && sinlat1 == 0))
|
|
92
|
+
throw GeographicErr("Bad sine/cosine of standard latitude 1");
|
|
93
|
+
if (!(abs(sinlat2) <= 1 && coslat2 <= 1) || (coslat2 == 0 && sinlat2 == 0))
|
|
94
|
+
throw GeographicErr("Bad sine/cosine of standard latitude 2");
|
|
95
|
+
if (coslat1 == 0 || coslat2 == 0)
|
|
96
|
+
if (!(coslat1 == coslat2 && sinlat1 == sinlat2))
|
|
97
|
+
throw GeographicErr
|
|
98
|
+
("Standard latitudes must be equal is either is a pole");
|
|
99
|
+
Init(sinlat1, coslat1, sinlat2, coslat2, k1);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
void LambertConformalConic::Init(real sphi1, real cphi1,
|
|
103
|
+
real sphi2, real cphi2, real k1) {
|
|
104
|
+
{
|
|
105
|
+
real r;
|
|
106
|
+
r = Math::hypot(sphi1, cphi1);
|
|
107
|
+
sphi1 /= r; cphi1 /= r;
|
|
108
|
+
r = Math::hypot(sphi2, cphi2);
|
|
109
|
+
sphi2 /= r; cphi2 /= r;
|
|
110
|
+
}
|
|
111
|
+
bool polar = (cphi1 == 0);
|
|
112
|
+
cphi1 = max(epsx_, cphi1); // Avoid singularities at poles
|
|
113
|
+
cphi2 = max(epsx_, cphi2);
|
|
114
|
+
// Determine hemisphere of tangent latitude
|
|
115
|
+
_sign = sphi1 + sphi2 >= 0 ? 1 : -1;
|
|
116
|
+
// Internally work with tangent latitude positive
|
|
117
|
+
sphi1 *= _sign; sphi2 *= _sign;
|
|
118
|
+
if (sphi1 > sphi2) {
|
|
119
|
+
swap(sphi1, sphi2); swap(cphi1, cphi2); // Make phi1 < phi2
|
|
120
|
+
}
|
|
121
|
+
real
|
|
122
|
+
tphi1 = sphi1/cphi1, tphi2 = sphi2/cphi2, tphi0;
|
|
123
|
+
//
|
|
124
|
+
// Snyder: 15-8: n = (log(m1) - log(m2))/(log(t1)-log(t2))
|
|
125
|
+
//
|
|
126
|
+
// m = cos(bet) = 1/sec(bet) = 1/sqrt(1+tan(bet)^2)
|
|
127
|
+
// bet = parametric lat, tan(bet) = (1-f)*tan(phi)
|
|
128
|
+
//
|
|
129
|
+
// t = tan(pi/4-chi/2) = 1/(sec(chi) + tan(chi)) = sec(chi) - tan(chi)
|
|
130
|
+
// log(t) = -asinh(tan(chi)) = -psi
|
|
131
|
+
// chi = conformal lat
|
|
132
|
+
// tan(chi) = tan(phi)*cosh(xi) - sinh(xi)*sec(phi)
|
|
133
|
+
// xi = eatanhe(sin(phi)), eatanhe(x) = e * atanh(e*x)
|
|
134
|
+
//
|
|
135
|
+
// n = (log(sec(bet2))-log(sec(bet1)))/(asinh(tan(chi2))-asinh(tan(chi1)))
|
|
136
|
+
//
|
|
137
|
+
// Let log(sec(bet)) = b(tphi), asinh(tan(chi)) = c(tphi)
|
|
138
|
+
// Then n = Db(tphi2, tphi1)/Dc(tphi2, tphi1)
|
|
139
|
+
// In limit tphi2 -> tphi1, n -> sphi1
|
|
140
|
+
//
|
|
141
|
+
real
|
|
142
|
+
tbet1 = _fm * tphi1, scbet1 = hyp(tbet1),
|
|
143
|
+
tbet2 = _fm * tphi2, scbet2 = hyp(tbet2);
|
|
144
|
+
real
|
|
145
|
+
scphi1 = 1/cphi1,
|
|
146
|
+
xi1 = Math::eatanhe(sphi1, _es), shxi1 = sinh(xi1), chxi1 = hyp(shxi1),
|
|
147
|
+
tchi1 = chxi1 * tphi1 - shxi1 * scphi1, scchi1 = hyp(tchi1),
|
|
148
|
+
scphi2 = 1/cphi2,
|
|
149
|
+
xi2 = Math::eatanhe(sphi2, _es), shxi2 = sinh(xi2), chxi2 = hyp(shxi2),
|
|
150
|
+
tchi2 = chxi2 * tphi2 - shxi2 * scphi2, scchi2 = hyp(tchi2),
|
|
151
|
+
psi1 = Math::asinh(tchi1);
|
|
152
|
+
if (tphi2 - tphi1 != 0) {
|
|
153
|
+
// Db(tphi2, tphi1)
|
|
154
|
+
real num = Dlog1p(Math::sq(tbet2)/(1 + scbet2),
|
|
155
|
+
Math::sq(tbet1)/(1 + scbet1))
|
|
156
|
+
* Dhyp(tbet2, tbet1, scbet2, scbet1) * _fm;
|
|
157
|
+
// Dc(tphi2, tphi1)
|
|
158
|
+
real den = Dasinh(tphi2, tphi1, scphi2, scphi1)
|
|
159
|
+
- Deatanhe(sphi2, sphi1) * Dsn(tphi2, tphi1, sphi2, sphi1);
|
|
160
|
+
_n = num/den;
|
|
161
|
+
|
|
162
|
+
if (_n < 0.25)
|
|
163
|
+
_nc = sqrt((1 - _n) * (1 + _n));
|
|
164
|
+
else {
|
|
165
|
+
// Compute nc = cos(phi0) = sqrt((1 - n) * (1 + n)), evaluating 1 - n
|
|
166
|
+
// carefully. First write
|
|
167
|
+
//
|
|
168
|
+
// Dc(tphi2, tphi1) * (tphi2 - tphi1)
|
|
169
|
+
// = log(tchi2 + scchi2) - log(tchi1 + scchi1)
|
|
170
|
+
//
|
|
171
|
+
// then den * (1 - n) =
|
|
172
|
+
// (log((tchi2 + scchi2)/(2*scbet2)) - log((tchi1 + scchi1)/(2*scbet1)))
|
|
173
|
+
// / (tphi2 - tphi1)
|
|
174
|
+
// = Dlog1p(a2, a1) * (tchi2+scchi2 + tchi1+scchi1)/(4*scbet1*scbet2)
|
|
175
|
+
// * fm * Q
|
|
176
|
+
//
|
|
177
|
+
// where
|
|
178
|
+
// a1 = ( (tchi1 - scbet1) + (scchi1 - scbet1) ) / (2 * scbet1)
|
|
179
|
+
// Q = ((scbet2 + scbet1)/fm)/((scchi2 + scchi1)/D(tchi2, tchi1))
|
|
180
|
+
// - (tbet2 + tbet1)/(scbet2 + scbet1)
|
|
181
|
+
real t;
|
|
182
|
+
{
|
|
183
|
+
real
|
|
184
|
+
// s1 = (scbet1 - scchi1) * (scbet1 + scchi1)
|
|
185
|
+
s1 = (tphi1 * (2 * shxi1 * chxi1 * scphi1 - _e2 * tphi1) -
|
|
186
|
+
Math::sq(shxi1) * (1 + 2 * Math::sq(tphi1))),
|
|
187
|
+
s2 = (tphi2 * (2 * shxi2 * chxi2 * scphi2 - _e2 * tphi2) -
|
|
188
|
+
Math::sq(shxi2) * (1 + 2 * Math::sq(tphi2))),
|
|
189
|
+
// t1 = scbet1 - tchi1
|
|
190
|
+
t1 = tchi1 < 0 ? scbet1 - tchi1 : (s1 + 1)/(scbet1 + tchi1),
|
|
191
|
+
t2 = tchi2 < 0 ? scbet2 - tchi2 : (s2 + 1)/(scbet2 + tchi2),
|
|
192
|
+
a2 = -(s2 / (scbet2 + scchi2) + t2) / (2 * scbet2),
|
|
193
|
+
a1 = -(s1 / (scbet1 + scchi1) + t1) / (2 * scbet1);
|
|
194
|
+
t = Dlog1p(a2, a1) / den;
|
|
195
|
+
}
|
|
196
|
+
// multiply by (tchi2 + scchi2 + tchi1 + scchi1)/(4*scbet1*scbet2) * fm
|
|
197
|
+
t *= ( ( (tchi2 >= 0 ? scchi2 + tchi2 : 1/(scchi2 - tchi2)) +
|
|
198
|
+
(tchi1 >= 0 ? scchi1 + tchi1 : 1/(scchi1 - tchi1)) ) /
|
|
199
|
+
(4 * scbet1 * scbet2) ) * _fm;
|
|
200
|
+
|
|
201
|
+
// Rewrite
|
|
202
|
+
// Q = (1 - (tbet2 + tbet1)/(scbet2 + scbet1)) -
|
|
203
|
+
// (1 - ((scbet2 + scbet1)/fm)/((scchi2 + scchi1)/D(tchi2, tchi1)))
|
|
204
|
+
// = tbm - tam
|
|
205
|
+
// where
|
|
206
|
+
real tbm = ( ((tbet1 > 0 ? 1/(scbet1+tbet1) : scbet1 - tbet1) +
|
|
207
|
+
(tbet2 > 0 ? 1/(scbet2+tbet2) : scbet2 - tbet2)) /
|
|
208
|
+
(scbet1+scbet2) );
|
|
209
|
+
|
|
210
|
+
// tam = (1 - ((scbet2+scbet1)/fm)/((scchi2+scchi1)/D(tchi2, tchi1)))
|
|
211
|
+
//
|
|
212
|
+
// Let
|
|
213
|
+
// (scbet2 + scbet1)/fm = scphi2 + scphi1 + dbet
|
|
214
|
+
// (scchi2 + scchi1)/D(tchi2, tchi1) = scphi2 + scphi1 + dchi
|
|
215
|
+
// then
|
|
216
|
+
// tam = D(tchi2, tchi1) * (dchi - dbet) / (scchi1 + scchi2)
|
|
217
|
+
real
|
|
218
|
+
// D(tchi2, tchi1)
|
|
219
|
+
dtchi = den / Dasinh(tchi2, tchi1, scchi2, scchi1),
|
|
220
|
+
// (scbet2 + scbet1)/fm - (scphi2 + scphi1)
|
|
221
|
+
dbet = (_e2/_fm) * ( 1 / (scbet2 + _fm * scphi2) +
|
|
222
|
+
1 / (scbet1 + _fm * scphi1) );
|
|
223
|
+
|
|
224
|
+
// dchi = (scchi2 + scchi1)/D(tchi2, tchi1) - (scphi2 + scphi1)
|
|
225
|
+
// Let
|
|
226
|
+
// tzet = chxiZ * tphi - shxiZ * scphi
|
|
227
|
+
// tchi = tzet + nu
|
|
228
|
+
// scchi = sczet + mu
|
|
229
|
+
// where
|
|
230
|
+
// xiZ = eatanhe(1), shxiZ = sinh(xiZ), chxiZ = cosh(xiZ)
|
|
231
|
+
// nu = scphi * (shxiZ - shxi) - tphi * (chxiZ - chxi)
|
|
232
|
+
// mu = - scphi * (chxiZ - chxi) + tphi * (shxiZ - shxi)
|
|
233
|
+
// then
|
|
234
|
+
// dchi = ((mu2 + mu1) - D(nu2, nu1) * (scphi2 + scphi1)) /
|
|
235
|
+
// D(tchi2, tchi1)
|
|
236
|
+
real
|
|
237
|
+
xiZ = Math::eatanhe(real(1), _es),
|
|
238
|
+
shxiZ = sinh(xiZ), chxiZ = hyp(shxiZ),
|
|
239
|
+
// These are differences not divided differences
|
|
240
|
+
// dxiZ1 = xiZ - xi1; dshxiZ1 = shxiZ - shxi; dchxiZ1 = chxiZ - chxi
|
|
241
|
+
dxiZ1 = Deatanhe(real(1), sphi1)/(scphi1*(tphi1+scphi1)),
|
|
242
|
+
dxiZ2 = Deatanhe(real(1), sphi2)/(scphi2*(tphi2+scphi2)),
|
|
243
|
+
dshxiZ1 = Dsinh(xiZ, xi1, shxiZ, shxi1, chxiZ, chxi1) * dxiZ1,
|
|
244
|
+
dshxiZ2 = Dsinh(xiZ, xi2, shxiZ, shxi2, chxiZ, chxi2) * dxiZ2,
|
|
245
|
+
dchxiZ1 = Dhyp(shxiZ, shxi1, chxiZ, chxi1) * dshxiZ1,
|
|
246
|
+
dchxiZ2 = Dhyp(shxiZ, shxi2, chxiZ, chxi2) * dshxiZ2,
|
|
247
|
+
// mu1 + mu2
|
|
248
|
+
amu12 = (- scphi1 * dchxiZ1 + tphi1 * dshxiZ1
|
|
249
|
+
- scphi2 * dchxiZ2 + tphi2 * dshxiZ2),
|
|
250
|
+
// D(xi2, xi1)
|
|
251
|
+
dxi = Deatanhe(sphi1, sphi2) * Dsn(tphi2, tphi1, sphi2, sphi1),
|
|
252
|
+
// D(nu2, nu1)
|
|
253
|
+
dnu12 =
|
|
254
|
+
( (_f * 4 * scphi2 * dshxiZ2 > _f * scphi1 * dshxiZ1 ?
|
|
255
|
+
// Use divided differences
|
|
256
|
+
(dshxiZ1 + dshxiZ2)/2 * Dhyp(tphi1, tphi2, scphi1, scphi2)
|
|
257
|
+
- ( (scphi1 + scphi2)/2
|
|
258
|
+
* Dsinh(xi1, xi2, shxi1, shxi2, chxi1, chxi2) * dxi ) :
|
|
259
|
+
// Use ratio of differences
|
|
260
|
+
(scphi2 * dshxiZ2 - scphi1 * dshxiZ1)/(tphi2 - tphi1))
|
|
261
|
+
+ ( (tphi1 + tphi2)/2 * Dhyp(shxi1, shxi2, chxi1, chxi2)
|
|
262
|
+
* Dsinh(xi1, xi2, shxi1, shxi2, chxi1, chxi2) * dxi )
|
|
263
|
+
- (dchxiZ1 + dchxiZ2)/2 ),
|
|
264
|
+
// dtchi * dchi
|
|
265
|
+
dchia = (amu12 - dnu12 * (scphi2 + scphi1)),
|
|
266
|
+
tam = (dchia - dtchi * dbet) / (scchi1 + scchi2);
|
|
267
|
+
t *= tbm - tam;
|
|
268
|
+
_nc = sqrt(max(real(0), t) * (1 + _n));
|
|
269
|
+
}
|
|
270
|
+
{
|
|
271
|
+
real r = Math::hypot(_n, _nc);
|
|
272
|
+
_n /= r;
|
|
273
|
+
_nc /= r;
|
|
274
|
+
}
|
|
275
|
+
tphi0 = _n / _nc;
|
|
276
|
+
} else {
|
|
277
|
+
tphi0 = tphi1;
|
|
278
|
+
_nc = 1/hyp(tphi0);
|
|
279
|
+
_n = tphi0 * _nc;
|
|
280
|
+
if (polar)
|
|
281
|
+
_nc = 0;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
_scbet0 = hyp(_fm * tphi0);
|
|
285
|
+
real shxi0 = sinh(Math::eatanhe(_n, _es));
|
|
286
|
+
_tchi0 = tphi0 * hyp(shxi0) - shxi0 * hyp(tphi0); _scchi0 = hyp(_tchi0);
|
|
287
|
+
_psi0 = Math::asinh(_tchi0);
|
|
288
|
+
|
|
289
|
+
_lat0 = atan(_sign * tphi0) / Math::degree();
|
|
290
|
+
_t0nm1 = Math::expm1(- _n * _psi0); // Snyder's t0^n - 1
|
|
291
|
+
// a * k1 * m1/t1^n = a * k1 * m2/t2^n = a * k1 * n * (Snyder's F)
|
|
292
|
+
// = a * k1 / (scbet1 * exp(-n * psi1))
|
|
293
|
+
_scale = _a * k1 / scbet1 *
|
|
294
|
+
// exp(n * psi1) = exp(- (1 - n) * psi1) * exp(psi1)
|
|
295
|
+
// with (1-n) = nc^2/(1+n) and exp(-psi1) = scchi1 + tchi1
|
|
296
|
+
exp( - (Math::sq(_nc)/(1 + _n)) * psi1 )
|
|
297
|
+
* (tchi1 >= 0 ? scchi1 + tchi1 : 1 / (scchi1 - tchi1));
|
|
298
|
+
// Scale at phi0 = k0 = k1 * (scbet0*exp(-n*psi0))/(scbet1*exp(-n*psi1))
|
|
299
|
+
// = k1 * scbet0/scbet1 * exp(n * (psi1 - psi0))
|
|
300
|
+
// psi1 - psi0 = Dasinh(tchi1, tchi0) * (tchi1 - tchi0)
|
|
301
|
+
_k0 = k1 * (_scbet0/scbet1) *
|
|
302
|
+
exp( - (Math::sq(_nc)/(1 + _n)) *
|
|
303
|
+
Dasinh(tchi1, _tchi0, scchi1, _scchi0) * (tchi1 - _tchi0))
|
|
304
|
+
* (tchi1 >= 0 ? scchi1 + tchi1 : 1 / (scchi1 - tchi1)) /
|
|
305
|
+
(_scchi0 + _tchi0);
|
|
306
|
+
_nrho0 = polar ? 0 : _a * _k0 / _scbet0;
|
|
307
|
+
{
|
|
308
|
+
// Figure _drhomax using code at beginning of Forward with lat = -90
|
|
309
|
+
real
|
|
310
|
+
sphi = -1, cphi = epsx_,
|
|
311
|
+
tphi = sphi/cphi,
|
|
312
|
+
scphi = 1/cphi, shxi = sinh(Math::eatanhe(sphi, _es)),
|
|
313
|
+
tchi = hyp(shxi) * tphi - shxi * scphi, scchi = hyp(tchi),
|
|
314
|
+
psi = Math::asinh(tchi),
|
|
315
|
+
dpsi = Dasinh(tchi, _tchi0, scchi, _scchi0) * (tchi - _tchi0);
|
|
316
|
+
_drhomax = - _scale * (2 * _nc < 1 && dpsi != 0 ?
|
|
317
|
+
(exp(Math::sq(_nc)/(1 + _n) * psi ) *
|
|
318
|
+
(tchi > 0 ? 1/(scchi + tchi) : (scchi - tchi))
|
|
319
|
+
- (_t0nm1 + 1))/(-_n) :
|
|
320
|
+
Dexp(-_n * psi, -_n * _psi0) * dpsi);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const LambertConformalConic& LambertConformalConic::Mercator() {
|
|
325
|
+
static const LambertConformalConic mercator(Constants::WGS84_a(),
|
|
326
|
+
Constants::WGS84_f(),
|
|
327
|
+
real(0), real(1));
|
|
328
|
+
return mercator;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
void LambertConformalConic::Forward(real lon0, real lat, real lon,
|
|
332
|
+
real& x, real& y, real& gamma, real& k)
|
|
333
|
+
const {
|
|
334
|
+
lon = Math::AngDiff(lon0, lon);
|
|
335
|
+
// From Snyder, we have
|
|
336
|
+
//
|
|
337
|
+
// theta = n * lambda
|
|
338
|
+
// x = rho * sin(theta)
|
|
339
|
+
// = (nrho0 + n * drho) * sin(theta)/n
|
|
340
|
+
// y = rho0 - rho * cos(theta)
|
|
341
|
+
// = nrho0 * (1-cos(theta))/n - drho * cos(theta)
|
|
342
|
+
//
|
|
343
|
+
// where nrho0 = n * rho0, drho = rho - rho0
|
|
344
|
+
// and drho is evaluated with divided differences
|
|
345
|
+
real sphi, cphi;
|
|
346
|
+
Math::sincosd(Math::LatFix(lat) * _sign, sphi, cphi);
|
|
347
|
+
cphi = max(epsx_, cphi);
|
|
348
|
+
real
|
|
349
|
+
lam = lon * Math::degree(),
|
|
350
|
+
tphi = sphi/cphi, scbet = hyp(_fm * tphi),
|
|
351
|
+
scphi = 1/cphi, shxi = sinh(Math::eatanhe(sphi, _es)),
|
|
352
|
+
tchi = hyp(shxi) * tphi - shxi * scphi, scchi = hyp(tchi),
|
|
353
|
+
psi = Math::asinh(tchi),
|
|
354
|
+
theta = _n * lam, stheta = sin(theta), ctheta = cos(theta),
|
|
355
|
+
dpsi = Dasinh(tchi, _tchi0, scchi, _scchi0) * (tchi - _tchi0),
|
|
356
|
+
drho = - _scale * (2 * _nc < 1 && dpsi != 0 ?
|
|
357
|
+
(exp(Math::sq(_nc)/(1 + _n) * psi ) *
|
|
358
|
+
(tchi > 0 ? 1/(scchi + tchi) : (scchi - tchi))
|
|
359
|
+
- (_t0nm1 + 1))/(-_n) :
|
|
360
|
+
Dexp(-_n * psi, -_n * _psi0) * dpsi);
|
|
361
|
+
x = (_nrho0 + _n * drho) * (_n ? stheta / _n : lam);
|
|
362
|
+
y = _nrho0 *
|
|
363
|
+
(_n ?
|
|
364
|
+
(ctheta < 0 ? 1 - ctheta : Math::sq(stheta)/(1 + ctheta)) / _n : 0)
|
|
365
|
+
- drho * ctheta;
|
|
366
|
+
k = _k0 * (scbet/_scbet0) /
|
|
367
|
+
(exp( - (Math::sq(_nc)/(1 + _n)) * dpsi )
|
|
368
|
+
* (tchi >= 0 ? scchi + tchi : 1 / (scchi - tchi)) / (_scchi0 + _tchi0));
|
|
369
|
+
y *= _sign;
|
|
370
|
+
gamma = _sign * theta / Math::degree();
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
void LambertConformalConic::Reverse(real lon0, real x, real y,
|
|
374
|
+
real& lat, real& lon,
|
|
375
|
+
real& gamma, real& k)
|
|
376
|
+
const {
|
|
377
|
+
// From Snyder, we have
|
|
378
|
+
//
|
|
379
|
+
// x = rho * sin(theta)
|
|
380
|
+
// rho0 - y = rho * cos(theta)
|
|
381
|
+
//
|
|
382
|
+
// rho = hypot(x, rho0 - y)
|
|
383
|
+
// drho = (n*x^2 - 2*y*nrho0 + n*y^2)/(hypot(n*x, nrho0-n*y) + nrho0)
|
|
384
|
+
// theta = atan2(n*x, nrho0-n*y)
|
|
385
|
+
//
|
|
386
|
+
// From drho, obtain t^n-1
|
|
387
|
+
// psi = -log(t), so
|
|
388
|
+
// dpsi = - Dlog1p(t^n-1, t0^n-1) * drho / scale
|
|
389
|
+
y *= _sign;
|
|
390
|
+
real
|
|
391
|
+
// Guard against 0 * inf in computation of ny
|
|
392
|
+
nx = _n * x, ny = _n ? _n * y : 0, y1 = _nrho0 - ny,
|
|
393
|
+
den = Math::hypot(nx, y1) + _nrho0, // 0 implies origin with polar aspect
|
|
394
|
+
// isfinite test is to avoid inf/inf
|
|
395
|
+
drho = ((den != 0 && Math::isfinite(den))
|
|
396
|
+
? (x*nx + y * (ny - 2*_nrho0)) / den
|
|
397
|
+
: den);
|
|
398
|
+
drho = min(drho, _drhomax);
|
|
399
|
+
if (_n == 0)
|
|
400
|
+
drho = max(drho, -_drhomax);
|
|
401
|
+
real
|
|
402
|
+
tnm1 = _t0nm1 + _n * drho/_scale,
|
|
403
|
+
dpsi = (den == 0 ? 0 :
|
|
404
|
+
(tnm1 + 1 != 0 ? - Dlog1p(tnm1, _t0nm1) * drho / _scale :
|
|
405
|
+
ahypover_));
|
|
406
|
+
real tchi;
|
|
407
|
+
if (2 * _n <= 1) {
|
|
408
|
+
// tchi = sinh(psi)
|
|
409
|
+
real
|
|
410
|
+
psi = _psi0 + dpsi, tchia = sinh(psi), scchi = hyp(tchia),
|
|
411
|
+
dtchi = Dsinh(psi, _psi0, tchia, _tchi0, scchi, _scchi0) * dpsi;
|
|
412
|
+
tchi = _tchi0 + dtchi; // Update tchi using divided difference
|
|
413
|
+
} else {
|
|
414
|
+
// tchi = sinh(-1/n * log(tn))
|
|
415
|
+
// = sinh((1-1/n) * log(tn) - log(tn))
|
|
416
|
+
// = + sinh((1-1/n) * log(tn)) * cosh(log(tn))
|
|
417
|
+
// - cosh((1-1/n) * log(tn)) * sinh(log(tn))
|
|
418
|
+
// (1-1/n) = - nc^2/(n*(1+n))
|
|
419
|
+
// cosh(log(tn)) = (tn + 1/tn)/2; sinh(log(tn)) = (tn - 1/tn)/2
|
|
420
|
+
real
|
|
421
|
+
tn = tnm1 + 1 == 0 ? epsx_ : tnm1 + 1,
|
|
422
|
+
sh = sinh( -Math::sq(_nc)/(_n * (1 + _n)) *
|
|
423
|
+
(2 * tn > 1 ? Math::log1p(tnm1) : log(tn)) );
|
|
424
|
+
tchi = sh * (tn + 1/tn)/2 - hyp(sh) * (tnm1 * (tn + 1)/tn)/2;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// log(t) = -asinh(tan(chi)) = -psi
|
|
428
|
+
gamma = atan2(nx, y1);
|
|
429
|
+
real
|
|
430
|
+
tphi = Math::tauf(tchi, _es),
|
|
431
|
+
scbet = hyp(_fm * tphi), scchi = hyp(tchi),
|
|
432
|
+
lam = _n ? gamma / _n : x / y1;
|
|
433
|
+
lat = Math::atand(_sign * tphi);
|
|
434
|
+
lon = lam / Math::degree();
|
|
435
|
+
lon = Math::AngNormalize(lon + Math::AngNormalize(lon0));
|
|
436
|
+
k = _k0 * (scbet/_scbet0) /
|
|
437
|
+
(exp(_nc ? - (Math::sq(_nc)/(1 + _n)) * dpsi : 0)
|
|
438
|
+
* (tchi >= 0 ? scchi + tchi : 1 / (scchi - tchi)) / (_scchi0 + _tchi0));
|
|
439
|
+
gamma /= _sign * Math::degree();
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
void LambertConformalConic::SetScale(real lat, real k) {
|
|
443
|
+
if (!(Math::isfinite(k) && k > 0))
|
|
444
|
+
throw GeographicErr("Scale is not positive");
|
|
445
|
+
if (!(abs(lat) <= 90))
|
|
446
|
+
throw GeographicErr("Latitude for SetScale not in [-90d, 90d]");
|
|
447
|
+
if (abs(lat) == 90 && !(_nc == 0 && lat * _n > 0))
|
|
448
|
+
throw GeographicErr("Incompatible polar latitude in SetScale");
|
|
449
|
+
real x, y, gamma, kold;
|
|
450
|
+
Forward(0, lat, 0, x, y, gamma, kold);
|
|
451
|
+
k /= kold;
|
|
452
|
+
_scale *= k;
|
|
453
|
+
_k0 *= k;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
} // namespace GeographicLib
|