001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/crs/projections/ProjectionUtils.java $
002 /*----------------------------------------------------------------------------
003 This file is part of deegree, http://deegree.org/
004 Copyright (C) 2001-2009 by:
005 Department of Geography, University of Bonn
006 and
007 lat/lon GmbH
008
009 This library is free software; you can redistribute it and/or modify it under
010 the terms of the GNU Lesser General Public License as published by the Free
011 Software Foundation; either version 2.1 of the License, or (at your option)
012 any later version.
013 This library is distributed in the hope that it will be useful, but WITHOUT
014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016 details.
017 You should have received a copy of the GNU Lesser General Public License
018 along with this library; if not, write to the Free Software Foundation, Inc.,
019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020
021 Contact information:
022
023 lat/lon GmbH
024 Aennchenstr. 19, 53177 Bonn
025 Germany
026 http://lat-lon.de/
027
028 Department of Geography, University of Bonn
029 Prof. Dr. Klaus Greve
030 Postfach 1147, 53001 Bonn
031 Germany
032 http://www.geographie.uni-bonn.de/deegree/
033
034 e-mail: info@deegree.org
035 ----------------------------------------------------------------------------*/
036
037 package org.deegree.crs.projections;
038
039 import java.awt.geom.Rectangle2D;
040
041 /**
042 * The <code>Utils</code> class combines some helpful constants and forms.
043 *
044 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
045 *
046 * @author last edited by: $Author: mschneider $
047 *
048 * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
049 *
050 */
051
052 public class ProjectionUtils {
053
054 // Very handy for setting maximum number of iterations in a for loop.
055 private final static int MAX_ITER = 10;
056
057 /**
058 * A small epsilon value
059 */
060 public final static double EPS10 = 1e-10;
061
062 /**
063 * An even smaller epsilon value
064 */
065 public final static double EPS11 = 1e-11;
066
067 /**
068 * Cotaining the value 0.5*pi
069 */
070 public final static double HALFPI = Math.PI * 0.5;
071
072 /**
073 * Containing the value 0.25*pi
074 */
075 public final static double QUARTERPI = Math.PI * 0.25;
076
077 /**
078 * Containing the value 2*pi
079 */
080 public final static double TWOPI = Math.PI * 2.0;
081
082 /**
083 * Radians to Degrees (180.0/Math.PI)
084 */
085 public final static double RTD = 180.0 / Math.PI;
086
087 /**
088 * Degrees to Radians (Math.PI/180.0)
089 */
090 public final static double DTR = Math.PI / 180.0;
091
092 /**
093 * The max and min of the projected word map in radians (-Math.PI, -HALFPI, TWOPI, Math.PI)
094 */
095 public final static Rectangle2D WORLD_BOUNDS_RAD = new Rectangle2D.Double( -Math.PI, -HALFPI, TWOPI, Math.PI );
096
097 /**
098 * The max and min of the projected word map in degrees (-180, -90, 360, 180)
099 */
100 public final static Rectangle2D WORLD_BOUNDS = new Rectangle2D.Double( -180, -90, 360, 180 );
101
102 /**
103 * From the proj4 library, to determine small q which is needed to calculate the authalic (equal-areaed) latitude
104 * beta, on a sphere having the same surface area as the ellipsoid, relative to the ellipsoid. Snyder (3 -12).
105 *
106 * @param sinphi
107 * the sine of the angle between the positive z-axis and the line formed between the origin and P.
108 * @param e
109 * the eccentricity
110 * @return the q value from Snyder (3-12)
111 * @deprecated use {@link ProjectionUtils#calcQForAuthalicLatitude(double, double)} instead.
112 */
113 @Deprecated
114 public static double qsfn( double sinphi, double e ) {
115 return calcQForAuthalicLatitude( sinphi, e );
116 }
117
118 /**
119 * From the proj4 library, to determine small q which is needed to calculate the authalic (equal-areaed) latitude
120 * beta, on a sphere having the same surface area as the ellipsoid, relative to the ellipsoid. Snyder (3 -12).
121 *
122 * @param sinphi
123 * the sine of the angle between the positive z-axis and the line formed between the origin and P.
124 * @param eccentricity
125 * the eccentricity of the ellipsoid to map the sphere to.
126 * @return the q value from Snyder (3-12)
127 */
128 public static double calcQForAuthalicLatitude( double sinphi, double eccentricity ) {
129 if ( eccentricity >= EPS10 ) {
130 double eAndSinphi = eccentricity * sinphi;
131 double es = eccentricity * eccentricity;
132 return ( 1 - es )
133 * ( sinphi / ( 1. - eAndSinphi * eAndSinphi ) - ( .5 / eccentricity )
134 * Math.log( ( 1. - eAndSinphi ) / ( 1. + eAndSinphi ) ) );
135 }
136 // we have a sphere.
137 return ( sinphi + sinphi );
138 }
139
140 /**
141 * Pre-calculated values for Snyder's formula (3-5)
142 */
143 private final static double T00 = 0.5;
144
145 private final static double T01 = .20833333333333333333;/* 5/24. */
146
147 private final static double T02 = .08333333333333333333;/* 1/12. */
148
149 private final static double T03 = .03611111111111111111;/* 13/360 */
150
151 private final static double T10 = .14583333333333333333;/* 7/48 */
152
153 private final static double T11 = .12083333333333333333;/* 29/240 */
154
155 private final static double T12 = .07039930555555555555;/* 811/11520 */
156
157 private final static double T20 = .05833333333333333333;/* 7/120 */
158
159 private final static double T21 = .07232142857142857142;/* 81/1120 */
160
161 private final static double T30 = .02653149801587301587;/* 4279/161280 */
162
163 /**
164 * Pre-Calculates the values (used for the adams? series) which will be used to calculate the phi value of an
165 * inverse projection. Snyder (3-5).
166 *
167 * @param eccentricitySquared
168 * the squared eccentricity from the ellipsoid to calculate the theta for.
169 * @return the precalculated values.
170 */
171 public static double[] preCalcedThetaSeries( double eccentricitySquared ) {
172 double[] precalculatedSerie = new double[4];
173 precalculatedSerie[0] = eccentricitySquared * T00;
174
175 // eccentricity^4
176 double tmp = eccentricitySquared * eccentricitySquared;
177 precalculatedSerie[0] += tmp * T01;
178 precalculatedSerie[1] = tmp * T10;
179
180 // eccentricity^6
181 tmp *= eccentricitySquared;
182 precalculatedSerie[0] += tmp * T02;
183 precalculatedSerie[1] += tmp * T11;
184 precalculatedSerie[2] = tmp * T20;
185
186 // eccentricity^8
187 tmp *= eccentricitySquared;
188 precalculatedSerie[0] += tmp * T03;
189 precalculatedSerie[1] += tmp * T12;
190 precalculatedSerie[2] += tmp * T21;
191 precalculatedSerie[3] = tmp * T30;
192
193 return precalculatedSerie;
194 }
195
196 /**
197 * Gets Phi from the given conformal latitude chi and the precalculated values (gotten from
198 * {@link ProjectionUtils#preCalcedThetaSeries(double)} ) of the adams? serie. From Snyder (3-5).
199 *
200 * @param chi
201 * the conformal latitude
202 * @param APA
203 * the precalculated values from the serie gotten from
204 * {@link ProjectionUtils#preCalcedThetaSeries(double)}.
205 * @return the Phi as a polarcoordinate on the ellipsoid or chi if the length of APA != 4.
206 */
207 public static double calcPhiFromConformalLatitude( double chi, double[] APA ) {
208 if ( APA.length != 4 ) {
209 return chi;
210 }
211 double tmp = chi + chi;
212 return ( chi + APA[0] * Math.sin( tmp ) + APA[1] * Math.sin( tmp + tmp ) + APA[2] * Math.sin( tmp + tmp + tmp ) + APA[3]
213 * Math.sin( tmp
214 + tmp
215 + tmp
216 + tmp ) );
217 }
218
219 /**
220 * P[0][0-2] = 1/3, 31/180, 517/5040, P[1][0-2] = 23/360, 251/3780 P[2][0] = 761/45360
221 */
222 private final static double P00 = .33333333333333333333; /* 1/3 */
223
224 private final static double P01 = .17222222222222222222; /* 31 / 180 */
225
226 private final static double P02 = .10257936507936507936; /* 517 / 5040 */
227
228 private final static double P10 = .06388888888888888888; /* 23/360 */
229
230 private final static double P11 = .06640211640211640211; /* 251/3780 */
231
232 private final static double P20 = .01641501294219154443; /* 761/45360 */
233
234 /**
235 * Pre-Calculates the values (used for the adams? series) which will be used to calculate the authalic latitude.
236 * Snyder (3-18).
237 *
238 * @param eccentricitySquared
239 * the squared eccentricity from the ellipsoid to calculate the authalic latitude for.
240 * @return the precalculated values.
241 * @deprecated use {@link ProjectionUtils#getAuthalicLatitudeSeriesValues(double)} instead.;
242 */
243 @Deprecated
244 public static double[] authset( double eccentricitySquared ) {
245 return getAuthalicLatitudeSeriesValues( eccentricitySquared );
246 }
247
248 /**
249 * Pre-Calculates the values (used for the adams? series) which will be used to calculate the authalic latitude.
250 * Snyder (3-18).
251 *
252 * @param eccentricitySquared
253 * the squared eccentricity from the ellipsoid to calculate the authalic latitude for.
254 * @return the precalculated values [0] = e^2/3 + e^4*(31/180) + e^6*(517/5040), [1]= e^4*(23/360) + e^6*(251/3780)
255 * and [2] = e^6*(761/45360).
256 */
257 public static double[] getAuthalicLatitudeSeriesValues( double eccentricitySquared ) {
258 double[] precalculatedSerie = new double[3];
259 precalculatedSerie[0] = eccentricitySquared * P00;
260 double t = eccentricitySquared * eccentricitySquared;
261 precalculatedSerie[0] += t * P01;
262 precalculatedSerie[1] = t * P10;
263 t *= eccentricitySquared;
264 precalculatedSerie[0] += t * P02;
265 precalculatedSerie[1] += t * P11;
266 precalculatedSerie[2] = t * P20;
267 return precalculatedSerie;
268 }
269
270 /**
271 * Gets phi from the authalic latitude beta and the precalculated values of the adams? serie. From Snyder (3-18).
272 *
273 * @param beta
274 * authalic latitude.
275 * @param APA
276 * the precalculated values from the series gotten from
277 * {@link ProjectionUtils#getAuthalicLatitudeSeriesValues(double)}.
278 * @return the phi on the ellipsoid.
279 * @deprecated use {@link ProjectionUtils#calcPhiFromAuthalicLatitude(double, double[])} instead.;
280 */
281 @Deprecated
282 public static double authlat( double beta, double[] APA ) {
283 return calcPhiFromAuthalicLatitude( beta, APA );
284 }
285
286 /**
287 * Gets phi from the authalic latitude beta and the precalculated values of the adams? serie. From Snyder (3-18).
288 *
289 * @param beta
290 * authalic latitude.
291 * @param APA
292 * the precalculated values from the serie gotten from
293 * {@link ProjectionUtils#getAuthalicLatitudeSeriesValues(double)}.
294 * @return the phi on the ellipsoid.
295 */
296 public static double calcPhiFromAuthalicLatitude( double beta, double[] APA ) {
297 double t = beta + beta;
298 return ( beta + APA[0] * Math.sin( t ) + APA[1] * Math.sin( t + t ) + APA[2] * Math.sin( t + t + t ) );
299 }
300
301 /**
302 * Calcs the length of a vector given by two points x and y
303 *
304 * @param dx
305 * of the vector
306 * @param dy
307 * of the vector
308 * @return the length
309 */
310 public static double length( double dx, double dy ) {
311 return Math.hypot( dx, dy );
312 }
313
314 /**
315 * This method calculates the innerpart of the conformal latitude's definition (Snyder p.15 3-1). This formula is
316 * almost equal to the calculation of the half colatitude from the conformal latitude (Snyder p.108 15-9). They only
317 * differ a sign in the first term.
318 *
319 * @param phi
320 * to calculate the conformal latitude from
321 * @param sinphi
322 * the sinus of the phi.
323 * @param eccentricity
324 * of the ellipsoid to which the phi should be made conformal to.
325 * @return the value of the innerpart of the conformal latitude formula. i.e. tan( pi/4 <b>+</b> phi/2)<b>*</b>[(1-e*sin(phi))/1+e*sin(phi))]^e/2.
326 */
327 public static double conformalLatitudeInnerPart( double phi, double sinphi, double eccentricity ) {
328 sinphi *= eccentricity;
329 return ( Math.tan( .5 * ( HALFPI + phi ) ) ) * Math.pow( ( 1. - sinphi ) / ( 1. + sinphi ), .5 * eccentricity );
330 }
331
332 /**
333 * This method calculates the innerpart of the conformal latitude's definition (Snyder p.15 3-1). This formula is
334 * almost equal to the calculation of the half colatitude from the conformal latitude (Snyder p.108 15-9). They only
335 * differ a sign in the first term.
336 *
337 * @param phi
338 * to calculate the conformal latitude from
339 * @param sinphi
340 * the sinus of the phi.
341 * @param eccentricity
342 * of the ellipsoid to which the phi should be made conformal to.
343 * @return the value of the innerpart of the conformal latitude formula. i.e. tan( pi/4 <b>+</b>
344 * phi/2)*[(1-e*sin(phi))/1+e*sin(phi))]^e/2.
345 * @deprecated Use {@link #conformalLatitudeInnerPart(double,double,double)} instead
346 */
347 @Deprecated
348 public static double ssfn( double phi, double sinphi, double eccentricity ) {
349 return conformalLatitudeInnerPart( phi, sinphi, eccentricity );
350 }
351
352 /**
353 * This method calculates the tangens of the half colatitude from the conformal latitude (Snyder p.108 15-9).
354 *
355 * @param phi
356 * to calculate the half of the co latitude of the conformal latitude from
357 * @param sinphi
358 * the sinus of the phi.
359 * @param eccentricity
360 * of the ellipsoid to which the phi should be made conformal to.
361 * @return the value of the tangens of half of the conformal latitude formula. i.e. tan( pi/4 <b>-</b> phi/2)<b>/</b>[(1-e*sin(phi))/1+e*sin(phi))]^e/2.
362 */
363 public static double tanHalfCoLatitude( double phi, double sinphi, double eccentricity ) {
364 sinphi *= eccentricity;
365 return ( Math.tan( .5 * ( HALFPI - phi ) ) ) / Math.pow( ( 1. - sinphi ) / ( 1. + sinphi ), .5 * eccentricity );
366 }
367
368 /**
369 * This method calculates the tangens of the half colatitude from the conformal latitude (Snyder p.108 15-9). This
370 * formula is almost equal to the calculation of the innerpart of the conformal latitude's definition (Snyder p.15
371 * 3-1). They only differ a sign in the first term.
372 *
373 * @param phi
374 * to calculate the half of the co latitude of the conformal latitude from
375 * @param sinphi
376 * the sinus of the phi.
377 * @param eccentricity
378 * of the ellipsoid to which the phi should be made conformal to.
379 * @return the value of the innerpart of the conformal latitude formula (given sign + or -). i.e. tan( pi/4 (+-)
380 * phi/2)*[(1-e*sin(phi))/1+e*sin(phi))]^e/2.
381 * @deprecated Use {@link #tanHalfCoLatitude(double,double,double)} instead
382 */
383 @Deprecated
384 public static double tsfn( double phi, double sinphi, double eccentricity ) {
385 return tanHalfCoLatitude( phi, sinphi, eccentricity );
386 }
387
388 /**
389 * This method can be used to calculate the value of a variable called 'm' by Snyder (Snyder p.101 14-15).
390 *
391 * @param sinphi
392 * the sinus of the phi
393 * @param cosphi
394 * the cosinus of the phi
395 * @param eccentricitySquared
396 * the value eccentricity * eccentricity.
397 * @return cos( phi) / Math.sqrt( 1 - eccentricity*eccentricity*sin(phi)*sin(phi) ).
398 * @deprecated Use {@link #calcMFromSnyder(double,double,double)} instead
399 */
400 @Deprecated
401 public static double msfn( double sinphi, double cosphi, double eccentricitySquared ) {
402 return calcMFromSnyder( sinphi, cosphi, eccentricitySquared );
403 }
404
405 /**
406 * This method can be used to calculate the value of a variable called 'm' by Snyder (Snyder p.101 14-15).
407 *
408 * @param sinphi
409 * the sinus of the phi
410 * @param cosphi
411 * the cosinus of the phi
412 * @param eccentricitySquared
413 * the value eccentricity * eccentricity.
414 * @return cos( phi) / Math.sqrt( 1 - eccentricity*eccentricity*sin(phi)*sin(phi) ).
415 */
416 public static double calcMFromSnyder( double sinphi, double cosphi, double eccentricitySquared ) {
417 return cosphi / Math.sqrt( 1.0 - eccentricitySquared * sinphi * sinphi );
418 }
419
420 /**
421 * Copied these value from proj4, I think they are reformed to fit some rule... but I don't know which rule that is
422 * :-(
423 */
424 private final static double C00 = 1; /* 1 :-) */
425
426 private final static double C02 = .25; /* 1/4 */
427
428 private final static double C04 = .046875;/* 3/64 */
429
430 private final static double C06 = .01953125;/* 5/256 */
431
432 private final static double C08 = .01068115234375;/* 175 / 16384 */
433
434 private final static double C22 = .75;
435
436 private final static double C44 = .46875;
437
438 private final static double C46 = .01302083333333333333;
439
440 private final static double C48 = .00712076822916666666;
441
442 private final static double C66 = .36458333333333333333;
443
444 private final static double C68 = .00569661458333333333;
445
446 private final static double C88 = .3076171875;
447
448 /**
449 * Pre Calculates the values for the series to calculate for a given ellipsoid with given eccentricity the distance
450 * along the meridian from the equator to a given latitude
451 * {@link #getDistanceAlongMeridian(double, double, double, double[])}.
452 *
453 * @param es
454 * the squared eccentricity of the underlying ellipsoid.
455 * @return the precalculated values for given ellipsoid.
456 * @deprecated Use {@link #getRectifiyingLatitudeValues(double)} instead
457 */
458 @Deprecated
459 public static double[] enfn( double es ) {
460 return getRectifiyingLatitudeValues( es );
461 }
462
463 /**
464 * Pre Calculates the values for the series to calculate for a given ellipsoid with given eccentricity the distance
465 * along the meridian from the equator to a given latitude
466 * {@link #getDistanceAlongMeridian(double, double, double, double[])}.
467 *
468 * @param es
469 * the squared eccentricity of the underlying ellipsoid.
470 * @return the precalculated values for given ellipsoid.
471 */
472 public static double[] getRectifiyingLatitudeValues( double es ) {
473 double[] en = new double[5];
474 en[0] = C00 - es * ( C02 + es * ( C04 + es * ( C06 + es * C08 ) ) );
475 en[1] = es * ( C22 - es * ( C04 + es * ( C06 + es * C08 ) ) );
476
477 double t = es * es;
478 en[2] = t * ( C44 - es * ( C46 + es * C48 ) );
479
480 t *= es;
481 en[3] = t * ( C66 - es * C68 );
482
483 en[4] = t * es * C88;
484
485 return en;
486 }
487
488 /**
489 * This method calcs for a a given ellispoid the distance along the meridian from the equator to latitude phi Snyder
490 * (p.17 3-21). It is used to calculate the rectifying latitude <i>mu</i>.
491 *
492 * @param phi
493 * the lattitude of the point in radians
494 * @param sphi
495 * the sinus of the latitude
496 * @param cphi
497 * the cosinus of the latitude
498 * @param en
499 * an array (of length 5) containing the precalculate values for this ellipsoid gotten from
500 * {@link #getRectifiyingLatitudeValues(double)}.
501 * @return the distance along the meridian from the equator to latitude phi.
502 * @deprecated Use {@link #getDistanceAlongMeridian(double,double,double,double[])} instead
503 */
504 @Deprecated
505 public static double mlfn( double phi, double sphi, double cphi, double[] en ) {
506 return getDistanceAlongMeridian( phi, sphi, cphi, en );
507 }
508
509 /**
510 * This method calcs the distance along the meridian from the equator to latitude phi for a a given ellispoid Snyder
511 * (p.17 3-21). It is used to calculate the rectifying latitude <i>mu</i>.
512 *
513 * @param phi
514 * the lattitude of the point in radians
515 * @param sphi
516 * the sinus of the latitude
517 * @param cphi
518 * the cosinus of the latitude
519 * @param en
520 * an array (of length 5) containing the precalculate values for this ellipsoid gotten from
521 * {@link #getRectifiyingLatitudeValues(double)}.
522 * @return the distance along the meridian from the equator to latitude phi.
523 */
524 public static double getDistanceAlongMeridian( double phi, double sphi, double cphi, double[] en ) {
525 cphi *= sphi;
526 sphi *= sphi;
527 return ( en[0] * phi ) - ( cphi * ( en[1] + sphi * ( en[2] + sphi * ( en[3] + sphi * en[4] ) ) ) );
528 }
529
530 /**
531 * This method calcs lattitude phi from a given distance along the meridian to the equator for a a given ellispoid
532 * and is therefore the inverse of the {@link #getDistanceAlongMeridian(double, double, double, double[])}. Phi is
533 * determined to EPS (1e-11) radians, which is about 1e-6 seconds.
534 *
535 * @param initialValue
536 * to calculate phi from, a good starting value is using the (distance along the meridian / y*scale) e.g.
537 * the scaled y value on the meridian.
538 * @param squaredEccentricity
539 * the squared eccentricity of the ellipsoid.
540 * @param en
541 * an array (of length 5) containing the precalculate values for this ellipsoid gotten from
542 * {@link #getRectifiyingLatitudeValues(double)}.
543 * @return the lattitude phi.
544 * @deprecated Use {@link #calcPhiFromMeridianDistance(double,double,double[])} instead
545 */
546 @Deprecated
547 public static double inv_mlfn( double initialValue, double squaredEccentricity, double[] en ) {
548 return calcPhiFromMeridianDistance( initialValue, squaredEccentricity, en );
549 }
550
551 /**
552 * This method calcs lattitude phi from a given distance along the meridian to the equator for a a given ellispoid
553 * and is therefore the inverse of the {@link #getDistanceAlongMeridian(double, double, double, double[])}. Phi is
554 * determined to EPS (1e-11) radians, which is about 1e-6 seconds.
555 *
556 * @param initialValue
557 * to calculate phi from, a good starting value is using the (distance along the meridian / y*scale) e.g.
558 * the scaled y value on the meridian.
559 * @param squaredEccentricity
560 * the squared eccentricity of the ellipsoid.
561 * @param en
562 * an array (of length 5) containing the precalculate values for this ellipsoid gotten from
563 * {@link #getRectifiyingLatitudeValues(double)}.
564 * @return the lattitude phi or the best approximated value if no suitable convergence was found.
565 */
566 public static double calcPhiFromMeridianDistance( double initialValue, double squaredEccentricity, double[] en ) {
567 double k = 1. / ( 1. - squaredEccentricity );
568 double phi = initialValue;
569 /* (from proj4: ->) rarely goes over 2 iterations */
570 for ( int i = MAX_ITER; i != 0; i-- ) {
571 double s = Math.sin( phi );
572 double t = 1. - squaredEccentricity * s * s;
573 t = ( getDistanceAlongMeridian( phi, s, Math.cos( phi ), en ) - initialValue ) * ( t * Math.sqrt( t ) ) * k;
574 phi -= t;
575 if ( Math.abs( t ) < EPS11 ) {
576 return phi;
577 }
578 }
579 return phi;
580 }
581
582 /**
583 * A helper method, which returns the acos from value or if value < -1 pi or value>1 0.
584 *
585 * @param value
586 * (in radians) from which the acos must be calculated
587 * @return the acos from value or if value < -1 pi or if value > 1 0.
588 */
589 public static double acosScaled( double value ) {
590 return ( value < -1 ) ? Math.PI : ( value > 1 ) ? 0 : Math.acos( value );
591 }
592
593 /**
594 * A helper method, which returns the asin from value or if value < -1 (-pi/2) or value>1 (pi/2).
595 *
596 * @param value
597 * (in radians) from which the asin must be calculated
598 * @return the asin from value or if value < -1 (-pi/2) or value>1 (pi/2).
599 */
600 public static double asinScaled( double value ) {
601 return ( value < -1 ) ? -HALFPI : ( value > 1 ) ? HALFPI : Math.asin( value );
602 }
603
604 /**
605 * A helper method modulos (pi)the given angle (in radians) until the result fits betwee -HALFPI and HALF_PI.
606 *
607 * @param angle
608 * in radians
609 * @return the angle adjusted to -pi/2 + pi/2 or 0 if the angle is NaN or Infinite.
610 */
611 public static double normalizeLatitude( double angle ) {
612 if ( Double.isInfinite( angle ) || Double.isNaN( angle ) ) {
613 return 0;
614 }
615 while ( angle > HALFPI ) {
616 angle -= Math.PI;
617 }
618 while ( angle < -HALFPI ) {
619 angle += Math.PI;
620 }
621 return angle;
622 }
623
624 /**
625 * A helper method modulos (2*pi)the given angle (in radians) until the result fits betwee -PI and PI.
626 *
627 * @param angle
628 * to be normalized
629 * @return the angle adjusted to -2*pi + pi*2 or 0 if the angle is NaN or Infinite.
630 */
631 public static double normalizeLongitude( double angle ) {
632 if ( Double.isInfinite( angle ) || Double.isNaN( angle ) ) {
633 return 0;
634 }
635 while ( angle > Math.PI ) {
636 angle -= TWOPI;
637 }
638 while ( angle < -Math.PI ) {
639 angle += TWOPI;
640 }
641 return angle;
642 }
643
644 /**
645 * Converts a Deegree.MinSec value into it's radian equivalent. <code>
646 * for example 13.120637 dms -> 13.201769444444446° -> 0.23041434389473822 rd
647 * </code>
648 *
649 * @param inCoord
650 * to be converted to radians.
651 * @return the radian equivalent of the inCoord.
652 */
653 public static double DecMinSecToRadians( double inCoord ) {
654 // get decimal minutes
655 double remainder = getRemainder( inCoord ) * 100;
656 // add the decimal minutes to the decimal seconds
657 remainder = ( Math.floor( remainder ) * 60 ) + ( getRemainder( remainder ) * 100 );
658 return ( Math.floor( inCoord ) + ( remainder / 3600 ) ) * DTR;
659 }
660
661 /**
662 * Converts a radian to its Deegree.MinSec equivalent.<code>
663 * For example 0.23041434389473822 rd -> 13.201769444444446° -> 13.120637 dms
664 * </code>
665 *
666 * @param inCoord
667 * to be converted to degrees.minsec
668 * @return the radian equivalent of the inCoord.
669 */
670 public static double RadiansToDecMinSec( double inCoord ) {
671
672 double degrees = RTD * inCoord;
673 double remainder = getRemainder( degrees );
674 return Math.floor( degrees ) + ( Math.floor( remainder * 60 ) / 100 )
675 + ( ( remainder * .36 ) - ( Math.floor( remainder * 60 ) * .006 ) );
676 }
677
678 /**
679 * Retrieve the remainder of a given double value, e.g. value - Math.floor( value ).
680 *
681 * @param value
682 * to get the remainder from.
683 *
684 * @return the remainder of the given value.
685 */
686 private static double getRemainder( double value ) {
687 return value - Math.floor( value );
688 }
689 }