Revision 1029 branches/v02_desarrollo/libraries/libCq CMS for java.old/src/org/cresques/cts/GeoCalc.java

View differences:

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