forked from tumic0/GPXSee
-
Notifications
You must be signed in to change notification settings - Fork 0
/
albersequal.cpp
235 lines (197 loc) · 6.85 KB
/
albersequal.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/*
* Based on libgeotrans with the following Source Code Disclaimer:
1. The GEOTRANS source code ("the software") is provided free of charge by
the National Imagery and Mapping Agency (NIMA) of the United States
Department of Defense. Although NIMA makes no copyright claim under Title 17
U.S.C., NIMA claims copyrights in the source code under other legal regimes.
NIMA hereby grants to each user of the software a license to use and
distribute the software, and develop derivative works.
2. Warranty Disclaimer: The software was developed to meet only the internal
requirements of the U.S. National Imagery and Mapping Agency. The software
is provided "as is," and no warranty, express or implied, including but not
limited to the implied warranties of merchantability and fitness for
particular purpose or arising by statute or otherwise in law or from a
course of dealing or usage in trade, is made by NIMA as to the accuracy and
functioning of the software.
3. NIMA and its personnel are not required to provide technical support or
general assistance with respect to the software.
4. Neither NIMA nor its personnel will be liable for any claims, losses, or
damages arising from or connected with the use of the software. The user
agrees to hold harmless the United States National Imagery and Mapping
Agency. The user's sole and exclusive remedy is to stop using the software.
5. NIMA requests that products developed using the software credit the
source of the software with the following statement, "The product was
developed using GEOTRANS, a product of the National Imagery and Mapping
Agency and U.S. Army Engineering Research and Development Center."
6. For any products developed using the software, NIMA requires a disclaimer
that use of the software does not indicate endorsement or approval of the
product by the Secretary of Defense or the National Imagery and Mapping
Agency. Pursuant to the United States Code, 10 U.S.C. Sec. 2797, the name of
the National Imagery and Mapping Agency, the initials "NIMA", the seal of
the National Imagery and Mapping Agency, or any colorable imitation thereof
shall not be used to imply approval, endorsement, or authorization of a
product without prior written permission from United States Secretary of
Defense.
*/
#include "map/ellipsoid.h"
#include "albersequal.h"
#define ONE_MINUS_SQR(x) (1.0 - (x) * (x))
#define ALBERS_Q(slat, one_minus_sqr_e_sin, es_sin) \
(_one_minus_es * ((slat) / (one_minus_sqr_e_sin) - \
(1 / (_two_e)) * log((1 - (es_sin)) / (1 + (es_sin)))))
#define ALBERS_M(clat, one_minus_sqr_e_sin) \
((clat) / sqrt(one_minus_sqr_e_sin))
AlbersEqual::AlbersEqual(const Ellipsoid &ellipsoid, double standardParallel1,
double standardParallel2, double latitudeOrigin, double longitudeOrigin,
double falseEasting, double falseNorthing)
{
double sin_lat, sin_lat1, sin_lat2, cos_lat1, cos_lat2;
double m1, m2, sqr_m1, sqr_m2;
double q0, q1, q2;
double e_sin, e_sin1, e_sin2;
double one_minus_sqr_e_sin1, one_minus_sqr_e_sin2;
double nq0;
double sp1, sp2;
_latitudeOrigin = deg2rad(latitudeOrigin);
_longitudeOrigin = deg2rad(longitudeOrigin);
_falseEasting = falseEasting;
_falseNorthing = falseNorthing;
sp1 = deg2rad(standardParallel1);
sp2 = deg2rad(standardParallel2);
_a2 = ellipsoid.radius() * ellipsoid.radius();
_es = ellipsoid.es();
_e = sqrt(_es);
_one_minus_es = 1 - _es;
_two_e = 2 * _e;
sin_lat = sin(_latitudeOrigin);
e_sin = _e * sin_lat;
q0 = ALBERS_Q(sin_lat, ONE_MINUS_SQR(e_sin), e_sin);
sin_lat1 = sin(sp1);
cos_lat1 = cos(sp1);
e_sin1 = _e * sin_lat1;
one_minus_sqr_e_sin1 = ONE_MINUS_SQR(e_sin1);
m1 = ALBERS_M(cos_lat1, one_minus_sqr_e_sin1);
q1 = ALBERS_Q(sin_lat1, one_minus_sqr_e_sin1, e_sin1);
sqr_m1 = m1 * m1;
if (fabs(sp1 - sp2) > 1.0e-10) {
sin_lat2 = sin(sp2);
cos_lat2 = cos(sp2);
e_sin2 = _e * sin_lat2;
one_minus_sqr_e_sin2 = ONE_MINUS_SQR(e_sin2);
m2 = ALBERS_M(cos_lat2, one_minus_sqr_e_sin2);
q2 = ALBERS_Q(sin_lat2, one_minus_sqr_e_sin2, e_sin2);
sqr_m2 = m2 * m2;
_n = (sqr_m1 - sqr_m2) / (q2 - q1);
} else
_n = sin_lat1;
_c = sqr_m1 + _n * q1;
_a_over_n = ellipsoid.radius() / _n;
nq0 = _n * q0;
_rho0 = (_c < nq0) ? 0 : _a_over_n * sqrt(_c - nq0);
}
PointD AlbersEqual::ll2xy(const Coordinates &c) const
{
double dlam;
double sin_lat;
double e_sin;
double q;
double rho;
double theta;
double nq;
dlam = deg2rad(c.lon()) - _longitudeOrigin;
if (dlam > M_PI)
dlam -= 2 * M_PI;
if (dlam < -M_PI)
dlam += 2 * M_PI;
sin_lat = sin(deg2rad(c.lat()));
e_sin = _e * sin_lat;
q = ALBERS_Q(sin_lat, ONE_MINUS_SQR(e_sin), e_sin);
nq = _n * q;
rho = (_c < nq) ? 0 : _a_over_n * sqrt(_c - nq);
theta = _n * dlam;
return PointD(rho * sin(theta) + _falseEasting,
_rho0 - rho * cos(theta) + _falseNorthing);
}
Coordinates AlbersEqual::xy2ll(const PointD &p) const
{
double dy, dx;
double rho0_minus_dy;
double q, qc, q_over_2;
double rho, rho_n;
double phi, delta_phi = 1.0;
double sin_phi;
double e_sin, one_minus_sqr_e_sin;
double theta = 0.0;
int count = 30;
double tolerance = 4.85e-10;
double lat, lon;
dy = p.y() - _falseNorthing;
dx = p.x() - _falseEasting;
rho0_minus_dy = _rho0 - dy;
rho = sqrt(dx * dx + rho0_minus_dy * rho0_minus_dy);
if (_n < 0) {
rho *= -1.0;
dx *= -1.0;
rho0_minus_dy *= -1.0;
}
if (rho != 0.0)
theta = atan2(dx, rho0_minus_dy);
rho_n = rho * _n;
q = (_c - (rho_n * rho_n) / _a2) / _n;
qc = 1 - ((_one_minus_es) / (_two_e)) * log((1.0 - _e) / (1.0 + _e));
if (fabs(fabs(qc) - fabs(q)) > 1.0e-6) {
q_over_2 = q / 2.0;
if (q_over_2 > 1.0)
lat = M_PI_2;
else if (q_over_2 < -1.0)
lat = -M_PI_2;
else {
phi = asin(q_over_2);
if (_e < 1.0e-10)
lat = phi;
else {
while ((fabs(delta_phi) > tolerance) && count) {
sin_phi = sin(phi);
e_sin = _e * sin_phi;
one_minus_sqr_e_sin = ONE_MINUS_SQR(e_sin);
delta_phi = (one_minus_sqr_e_sin * one_minus_sqr_e_sin)
/ (2.0 * cos(phi)) * (q / (_one_minus_es) - sin_phi
/ one_minus_sqr_e_sin + (log((1.0 - e_sin)
/ (1.0 + e_sin)) / (_two_e)));
phi += delta_phi;
count --;
}
lat = phi;
}
if (lat > M_PI_2)
lat = M_PI_2;
else if (lat < -M_PI_2)
lat = -M_PI_2;
}
} else {
if (q >= 0.0)
lat = M_PI_2;
else
lat = -M_PI_2;
}
lon = _longitudeOrigin + theta / _n;
if (lon > M_PI)
lon -= 2 * M_PI;
if (lon < -M_PI)
lon += 2 * M_PI;
if (lon > M_PI)
lon = M_PI;
else if (lon < -M_PI)
lon = -M_PI;
return Coordinates(rad2deg(lon), rad2deg(lat));
}
bool AlbersEqual::operator==(const CT &ct) const
{
const AlbersEqual *other = dynamic_cast<const AlbersEqual*>(&ct);
return (other != 0 && _latitudeOrigin == other->_latitudeOrigin
&& _longitudeOrigin == other->_longitudeOrigin
&& _falseEasting == other->_falseEasting
&& _falseNorthing == other->_falseNorthing && _a2 == other->_a2
&& _es == other->_es && _rho0 == other->_rho0 && _c == other->_c
&& _n == other->_n);
}