Revision 1029 branches/v02_desarrollo/libraries/libCq CMS for java.old/src/org/cresques/cts/GeoCalc.java
GeoCalc.java | ||
---|---|---|
50 | 50 |
* @return |
51 | 51 |
*/ |
52 | 52 |
public double distanceEli(Point2D pt1, Point2D pt2) { |
53 |
|
|
53 | 54 |
double lat1 = Math.toRadians(pt1.getY()); |
54 | 55 |
double lon1 = -Math.toRadians(pt1.getX()); |
55 | 56 |
double lat2 = Math.toRadians(pt2.getY()); |
56 | 57 |
double lon2 = -Math.toRadians(pt2.getX()); |
57 | 58 |
|
58 |
double F = (lat1 + lat2) / 2.0;
|
|
59 |
double G = (lat1 - lat2) / 2.0;
|
|
60 |
double L = (lon1 - lon2) / 2.0;
|
|
59 |
double F = (lat1 + lat2) / 2D;
|
|
60 |
double G = (lat1 - lat2) / 2D;
|
|
61 |
double L = (lon1 - lon2) / 2D;
|
|
61 | 62 |
|
62 | 63 |
double sing = Math.sin(G); |
63 | 64 |
double cosl = Math.cos(L); |
... | ... | |
66 | 67 |
double sinf = Math.sin(F); |
67 | 68 |
double cosg = Math.cos(G); |
68 | 69 |
|
70 |
double flat = 1D / proj.getDatum().getEIFlattening(); |
|
71 |
|
|
69 | 72 |
double S = sing*sing*cosl*cosl + cosf*cosf*sinl*sinl; |
70 | 73 |
double C = cosg*cosg*cosl*cosl + sinf*sinf*sinl*sinl; |
71 | 74 |
double W = Math.atan2(Math.sqrt(S),Math.sqrt(C)); |
72 | 75 |
double R = Math.sqrt((S*C))/W; |
73 |
double H1 = (3 * R - 1.0) / (2.0 * C);
|
|
74 |
double H2 = (3 * R + 1.0) / (2.0 * S);
|
|
75 |
double D = 2 * W * proj.getDatum().getESemiMajorAxis(); |
|
76 |
return (D * (1 + proj.getDatum().getEIFlattening() * H1 * sinf*sinf*cosg*cosg -
|
|
77 |
proj.getDatum().getEIFlattening()*H2*cosf*cosf*sing*sing))*1000D;
|
|
76 |
double H1 = (3D * R - 1D) / (2D * C);
|
|
77 |
double H2 = (3D * R + 1D) / (2D * S);
|
|
78 |
double D = 2D * W * proj.getDatum().getESemiMajorAxis();
|
|
79 |
return (D * (1D + flat * H1 * sinf*sinf*cosg*cosg -
|
|
80 |
flat*H2*cosf*cosf*sing*sing));
|
|
78 | 81 |
} |
79 | 82 |
|
83 |
/* |
|
84 |
* F?rmulas de Vincenty's. |
|
85 |
* (pasadas de http://wegener.mechanik.tu-darmstadt.de/GMT-Help/Archiv/att-8710/Geodetic_py |
|
86 |
* http://www.icsm.gov.au/icsm/gda/gdatm/index.html |
|
87 |
*/ |
|
88 |
|
|
89 |
class GeoData { |
|
90 |
Point2D pt; |
|
91 |
double azimut, revAzimut; |
|
92 |
double dist; |
|
93 |
|
|
94 |
public GeoData(double x, double y) { |
|
95 |
pt = new Point2D.Double(x, y); |
|
96 |
azimut = revAzimut = dist = 0; |
|
97 |
} |
|
98 |
|
|
99 |
public GeoData(double x, double y, double dist, double azi, double rAzi) { |
|
100 |
pt = new Point2D.Double(x, y); |
|
101 |
azimut = azi; |
|
102 |
revAzimut = rAzi; |
|
103 |
this.dist = dist; |
|
104 |
} |
|
105 |
} |
|
80 | 106 |
/** |
81 |
* Superficie de un triangulo (esf?rico). Lops puntos deben de estar |
|
107 |
* Algrothims from Geocentric Datum of Australia Technical Manual |
|
108 |
* |
|
109 |
* http://www.anzlic.org.au/icsm/gdatum/chapter4.html |
|
110 |
* |
|
111 |
* This page last updated 11 May 1999 |
|
112 |
* |
|
113 |
* Computations on the Ellipsoid |
|
114 |
* |
|
115 |
* There are a number of formulae that are available |
|
116 |
* to calculate accurate geodetic positions, |
|
117 |
* azimuths and distances on the ellipsoid. |
|
118 |
* |
|
119 |
* Vincenty's formulae (Vincenty, 1975) may be used |
|
120 |
* for lines ranging from a few cm to nearly 20,000 km, |
|
121 |
* with millimetre accuracy. |
|
122 |
* The formulae have been extensively tested |
|
123 |
* for the Australian region, by comparison with results |
|
124 |
* from other formulae (Rainsford, 1955 & Sodano, 1965). |
|
125 |
* |
|
126 |
* * Inverse problem: azimuth and distance from known |
|
127 |
* latitudes and longitudes |
|
128 |
* * Direct problem: Latitude and longitude from known |
|
129 |
* position, azimuth and distance. |
|
130 |
* * Sample data |
|
131 |
* * Excel spreadsheet |
|
132 |
* |
|
133 |
* Vincenty's Inverse formulae |
|
134 |
* Given: latitude and longitude of two points |
|
135 |
* (phi1, lembda1 and phi2, lembda2), |
|
136 |
* Calculate: the ellipsoidal distance (s) and |
|
137 |
* forward and reverse azimuths between the points (alpha12, alpha21). |
|
138 |
*/ |
|
139 |
|
|
140 |
/** |
|
141 |
* Devuelve la distancia entre dos puntos usando las formulas |
|
142 |
* de vincenty. |
|
143 |
* @param pt1 |
|
144 |
* @param pt2 |
|
145 |
* @return |
|
146 |
*/ |
|
147 |
public double distanceVincenty( Point2D pt1, Point2D pt2 ) { |
|
148 |
return distanceAzimutVincenty(pt1, pt2).dist; |
|
149 |
} |
|
150 |
|
|
151 |
/** |
|
152 |
* Returns the distance between two geographic points on the ellipsoid |
|
153 |
* and the forward and reverse azimuths between these points. |
|
154 |
* lats, longs and azimuths are in decimal degrees, distance in metres |
|
155 |
* Returns ( s, alpha12, alpha21 ) as a tuple |
|
156 |
* @param pt1 |
|
157 |
* @param pt2 |
|
158 |
* @return |
|
159 |
*/ |
|
160 |
public GeoData distanceAzimutVincenty( Point2D pt1, Point2D pt2 ) { |
|
161 |
GeoData gd = new GeoData(0,0); |
|
162 |
double f = 1D / proj.getDatum().getEIFlattening(), |
|
163 |
a = proj.getDatum().getESemiMajorAxis(), |
|
164 |
phi1 = pt1.getY(), lembda1 = pt1.getX(), |
|
165 |
phi2 = pt2.getY(), lembda2 = pt2.getX(); |
|
166 |
|
|
167 |
if ((Math.abs( phi2 - phi1 ) < 1e-8) && ( Math.abs( lembda2 - lembda1) < 1e-8 )) |
|
168 |
return gd; |
|
169 |
|
|
170 |
double piD4 = Math.atan( 1.0 ); |
|
171 |
double two_pi = piD4 * 8.0; |
|
172 |
|
|
173 |
phi1 = phi1 * piD4 / 45.0; |
|
174 |
lembda1 = lembda1 * piD4 / 45.0; // unfortunately lambda is a key word! |
|
175 |
phi2 = phi2 * piD4 / 45.0; |
|
176 |
lembda2 = lembda2 * piD4 / 45.0; |
|
177 |
|
|
178 |
double b = a * (1.0 - f); |
|
179 |
|
|
180 |
double TanU1 = (1-f) * Math.tan( phi1 ); |
|
181 |
double TanU2 = (1-f) * Math.tan( phi2 ); |
|
182 |
|
|
183 |
double U1 = Math.atan(TanU1); |
|
184 |
double U2 = Math.atan(TanU2); |
|
185 |
|
|
186 |
double lembda = lembda2 - lembda1; |
|
187 |
double last_lembda = -4000000.0; // an impossibe value |
|
188 |
double omega = lembda; |
|
189 |
|
|
190 |
// Iterate the following equations, |
|
191 |
// until there is no significant change in lembda |
|
192 |
double Sin_sigma = 0, Cos_sigma = 0; |
|
193 |
double Cos2sigma_m = 0, alpha = 0; |
|
194 |
double sigma = 0, sqr_sin_sigma = 0; |
|
195 |
while ( last_lembda < -3000000.0 || lembda != 0 && Math.abs( (last_lembda - lembda)/lembda) > 1.0e-9 ) { |
|
196 |
|
|
197 |
sqr_sin_sigma = Math.pow( Math.cos(U2) * Math.sin(lembda), 2) + |
|
198 |
Math.pow( (Math.cos(U1) * Math.sin(U2) - |
|
199 |
Math.sin(U1) * Math.cos(U2) * Math.cos(lembda) ), 2 ); |
|
200 |
|
|
201 |
Sin_sigma = Math.sqrt( sqr_sin_sigma ); |
|
202 |
|
|
203 |
Cos_sigma = Math.sin(U1) * Math.sin(U2) + Math.cos(U1) * Math.cos(U2) * Math.cos(lembda); |
|
204 |
|
|
205 |
sigma = Math.atan2( Sin_sigma, Cos_sigma ); |
|
206 |
|
|
207 |
double Sin_alpha = Math.cos(U1) * Math.cos(U2) * Math.sin(lembda) / Math.sin(sigma); |
|
208 |
alpha = Math.asin( Sin_alpha ); |
|
209 |
|
|
210 |
Cos2sigma_m = Math.cos(sigma) - (2 * Math.sin(U1) * Math.sin(U2) / Math.pow(Math.cos(alpha), 2) ); |
|
211 |
|
|
212 |
double C = (f/16) * Math.pow(Math.cos(alpha), 2) * (4 + f * (4 - 3 * Math.pow(Math.cos(alpha), 2))); |
|
213 |
|
|
214 |
last_lembda = lembda; |
|
215 |
|
|
216 |
lembda = omega + (1-C) * f * Math.sin(alpha) * (sigma + C * Math.sin(sigma) * |
|
217 |
(Cos2sigma_m + C * Math.cos(sigma) * (-1 + 2 * Math.pow(Cos2sigma_m, 2) ))); |
|
218 |
} |
|
219 |
|
|
220 |
|
|
221 |
double u2 = Math.pow(Math.cos(alpha),2) * (a*a-b*b) / (b*b); |
|
222 |
|
|
223 |
double A = 1 + (u2/16384) * (4096 + u2 * (-768 + u2 * (320 - 175 * u2))); |
|
224 |
|
|
225 |
double B = (u2/1024) * (256 + u2 * (-128+ u2 * (74 - 47 * u2))); |
|
226 |
|
|
227 |
double delta_sigma = B * Sin_sigma * (Cos2sigma_m + (B/4) * |
|
228 |
(Cos_sigma * (-1 + 2 * Math.pow(Cos2sigma_m, 2) ) - |
|
229 |
(B/6) * Cos2sigma_m * (-3 + 4 * sqr_sin_sigma) * |
|
230 |
(-3 + 4 * Math.pow(Cos2sigma_m,2 ) ))); |
|
231 |
|
|
232 |
double s = b * A * (sigma - delta_sigma); |
|
233 |
|
|
234 |
double alpha12 = Math.atan2( (Math.cos(U2) * Math.sin(lembda)), |
|
235 |
(Math.cos(U1) * Math.sin(U2) - Math.sin(U1) * Math.cos(U2) * Math.cos(lembda))); |
|
236 |
|
|
237 |
double alpha21 = Math.atan2( (Math.cos(U1) * Math.sin(lembda)), |
|
238 |
(-Math.sin(U1) * Math.cos(U2) + Math.cos(U1) * Math.sin(U2) * Math.cos(lembda))); |
|
239 |
|
|
240 |
if ( alpha12 < 0.0 ) |
|
241 |
alpha12 = alpha12 + two_pi; |
|
242 |
if ( alpha12 > two_pi ) |
|
243 |
alpha12 = alpha12 - two_pi; |
|
244 |
|
|
245 |
alpha21 = alpha21 + two_pi / 2.0; |
|
246 |
if ( alpha21 < 0.0 ) |
|
247 |
alpha21 = alpha21 + two_pi; |
|
248 |
if ( alpha21 > two_pi ) |
|
249 |
alpha21 = alpha21 - two_pi; |
|
250 |
|
|
251 |
alpha12 = alpha12 * 45.0 / piD4; |
|
252 |
alpha21 = alpha21 * 45.0 / piD4; |
|
253 |
return new GeoData(0,0, s, alpha12, alpha21); |
|
254 |
} |
|
255 |
|
|
256 |
/** |
|
257 |
* Vincenty's Direct formulae |
|
258 |
* Given: latitude and longitude of a point (phi1, lembda1) and |
|
259 |
* the geodetic azimuth (alpha12) |
|
260 |
* and ellipsoidal distance in metres (s) to a second point, |
|
261 |
* |
|
262 |
* Calculate: the latitude and longitude of the second point (phi2, lembda2) |
|
263 |
* and the reverse azimuth (alpha21). |
|
264 |
*/ |
|
265 |
|
|
266 |
/** |
|
267 |
* Returns the lat and long of projected point and reverse azimuth |
|
268 |
* given a reference point and a distance and azimuth to project. |
|
269 |
* lats, longs and azimuths are passed in decimal degrees. |
|
270 |
* Returns ( phi2, lambda2, alpha21 ) as a tuple |
|
271 |
* @param pt |
|
272 |
* @param azimut |
|
273 |
* @param dist |
|
274 |
* @return |
|
275 |
*/ |
|
276 |
public GeoData getPointVincenty( Point2D pt, double azimut, double dist) { |
|
277 |
GeoData ret = new GeoData(0,0); |
|
278 |
double f = 1D / proj.getDatum().getEIFlattening(), |
|
279 |
a = proj.getDatum().getESemiMajorAxis(), |
|
280 |
phi1 = pt.getY(), lembda1 = pt.getX(), |
|
281 |
alpha12 = azimut, s = dist; |
|
282 |
|
|
283 |
double piD4 = Math.atan( 1.0 ); |
|
284 |
double two_pi = piD4 * 8.0; |
|
285 |
|
|
286 |
phi1 = phi1 * piD4 / 45.0; |
|
287 |
lembda1 = lembda1 * piD4 / 45.0; |
|
288 |
alpha12 = alpha12 * piD4 / 45.0; |
|
289 |
if ( alpha12 < 0.0 ) |
|
290 |
alpha12 = alpha12 + two_pi; |
|
291 |
if ( alpha12 > two_pi ) |
|
292 |
alpha12 = alpha12 - two_pi; |
|
293 |
|
|
294 |
|
|
295 |
double b = a * (1.0 - f); |
|
296 |
|
|
297 |
double TanU1 = (1-f) * Math.tan(phi1); |
|
298 |
double U1 = Math.atan( TanU1 ); |
|
299 |
double sigma1 = Math.atan2( TanU1, Math.cos(alpha12) ); |
|
300 |
double Sinalpha = Math.cos(U1) * Math.sin(alpha12); |
|
301 |
double cosalpha_sq = 1.0 - Sinalpha * Sinalpha; |
|
302 |
|
|
303 |
double u2 = cosalpha_sq * (a * a - b * b ) / (b * b); |
|
304 |
double A = 1.0 + (u2 / 16384) * (4096 + u2 * (-768 + u2 * |
|
305 |
(320 - 175 * u2) ) ); |
|
306 |
double B = (u2 / 1024) * (256 + u2 * (-128 + u2 * (74 - 47 * u2) ) ); |
|
307 |
|
|
308 |
// Starting with the approximation |
|
309 |
double sigma = (s / (b * A)); |
|
310 |
|
|
311 |
double last_sigma = 2.0 * sigma + 2.0; // something impossible |
|
312 |
|
|
313 |
// Iterate the following three equations |
|
314 |
// until there is no significant change in sigma |
|
315 |
|
|
316 |
// two_sigma_m , delta_sigma |
|
317 |
|
|
318 |
double two_sigma_m = 0; |
|
319 |
while ( Math.abs( (last_sigma - sigma) / sigma) > 1.0e-9 ) { |
|
320 |
|
|
321 |
two_sigma_m = 2 * sigma1 + sigma; |
|
322 |
|
|
323 |
double delta_sigma = B * Math.sin(sigma) * ( Math.cos(two_sigma_m) |
|
324 |
+ (B/4) * (Math.cos(sigma) * |
|
325 |
(-1 + 2 * Math.pow( Math.cos(two_sigma_m), 2 ) - |
|
326 |
(B/6) * Math.cos(two_sigma_m) * |
|
327 |
(-3 + 4 * Math.pow(Math.sin(sigma), 2 )) * |
|
328 |
(-3 + 4 * Math.pow( Math.cos (two_sigma_m), 2 ))))); |
|
329 |
|
|
330 |
last_sigma = sigma; |
|
331 |
sigma = (s / (b * A)) + delta_sigma; |
|
332 |
} |
|
333 |
|
|
334 |
|
|
335 |
double phi2 = Math.atan2 ( (Math.sin(U1) * Math.cos(sigma) + Math.cos(U1) * Math.sin(sigma) * Math.cos(alpha12) ), |
|
336 |
((1-f) * Math.sqrt( Math.pow(Sinalpha, 2) + |
|
337 |
Math.pow(Math.sin(U1) * Math.sin(sigma) - Math.cos(U1) * Math.cos(sigma) * Math.cos(alpha12), 2)))); |
|
338 |
|
|
339 |
|
|
340 |
double lembda = Math.atan2( (Math.sin(sigma) * Math.sin(alpha12 )), (Math.cos(U1) * Math.cos(sigma) - |
|
341 |
Math.sin(U1) * Math.sin(sigma) * Math.cos(alpha12))); |
|
342 |
|
|
343 |
double C = (f/16) * cosalpha_sq * (4 + f * (4 - 3 * cosalpha_sq )); |
|
344 |
|
|
345 |
double omega = lembda - (1-C) * f * Sinalpha * |
|
346 |
(sigma + C * Math.sin(sigma) * (Math.cos(two_sigma_m) + |
|
347 |
C * Math.cos(sigma) * (-1 + 2 * Math.pow(Math.cos(two_sigma_m),2) ))); |
|
348 |
|
|
349 |
double lembda2 = lembda1 + omega; |
|
350 |
|
|
351 |
double alpha21 = Math.atan2 ( Sinalpha, (-Math.sin(U1) * Math.sin(sigma) + |
|
352 |
Math.cos(U1) * Math.cos(sigma) * Math.cos(alpha12))); |
|
353 |
|
|
354 |
alpha21 = alpha21 + two_pi / 2.0; |
|
355 |
if ( alpha21 < 0.0 ) |
|
356 |
alpha21 = alpha21 + two_pi; |
|
357 |
if ( alpha21 > two_pi ) |
|
358 |
alpha21 = alpha21 - two_pi; |
|
359 |
|
|
360 |
|
|
361 |
phi2 = phi2 * 45.0 / piD4; |
|
362 |
lembda2 = lembda2 * 45.0 / piD4; |
|
363 |
alpha21 = alpha21 * 45.0 / piD4; |
|
364 |
|
|
365 |
ret.pt = new Point2D.Double(lembda2, phi2); |
|
366 |
ret.azimut = alpha21; |
|
367 |
return ret; |
|
368 |
} |
|
369 |
|
|
370 |
|
|
371 |
/** |
|
372 |
* Superficie de un triangulo (esf?rico). Los puntos deben de estar |
|
82 | 373 |
* en coordenadas geogr?ficas. |
83 | 374 |
* @param pt1 |
84 | 375 |
* @param pt2 |
... | ... | |
90 | 381 |
double A = distanceGeo(pt1, pt2); |
91 | 382 |
double B = distanceGeo(pt2, pt3); |
92 | 383 |
double C = distanceGeo(pt3, pt1); |
384 |
sup = (A+B+C-Math.toRadians(180D))* |
|
385 |
Math.PI*proj.getDatum().getESemiMajorAxis()/Math.toRadians(180D); |
|
93 | 386 |
return sup; |
94 | 387 |
} |
95 | 388 |
} |
Also available in: Unified diff