001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/crs/components/Ellipsoid.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.components; 038 039 import static org.deegree.crs.projections.ProjectionUtils.EPS11; 040 041 import java.io.Serializable; 042 043 import org.deegree.crs.Identifiable; 044 045 /** 046 * The <code>Ellipsoid</code> class hold all parameters which are necessary to define an Ellipsoid. Every Ellipsoid has 047 * a semi-major-axis and one of inverse_flattening, eccentricity or semi-minor-axis. 048 * 049 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a> 050 * 051 * @author last edited by: $Author: rbezema $ 052 * 053 * @version $Revision: 19653 $, $Date: 2009-09-15 14:56:30 +0200 (Di, 15 Sep 2009) $ 054 * 055 */ 056 057 public class Ellipsoid extends Identifiable implements Serializable { 058 059 private static final long serialVersionUID = -2734558237905436138L; 060 061 /** 062 * WGS 1984 ellipsoid. This ellipsoid is used in the GPS system and is the "default" Ellipsoid. 063 */ 064 public static final Ellipsoid WGS84 = new Ellipsoid( 6378137.0, Unit.METRE, 298.257223563, "EPSG:7030", 065 "WGS84_Ellipsoid" ); 066 067 /** 068 * the larger one of the two (semi)axis of an ellipsoid 069 */ 070 private final double semiMajorAxis; 071 072 /** 073 * the smaller one of the two (semi)axis of an ellipsoid 074 */ 075 private final double semiMinorAxis; 076 077 /** 078 * the units of the axis 079 */ 080 private final Unit units; 081 082 /** 083 * Flattening f is dependent on both the semi-major axis a and the semi-minor axis b. f = (a - b) / a 084 */ 085 private final double flattening; 086 087 /** 088 * Flattening f is normally given as 1/... value therefore an inverse is often given. 089 */ 090 private final double inverseFlattening; 091 092 /** 093 * The ellipsoid may also be defined by its semi-major axis a and eccentricity e, which is given by: e*e = 2f - f*f 094 */ 095 private final double eccentricity; 096 097 /** 098 * The ellipsoid may also be defined by its semi-major axis a and eccentricity e, which is given by: e*e = 2f - f*f, 099 * this is it's squared value. 100 */ 101 private final double squaredEccentricity; 102 103 /** 104 * @param units 105 * @param semiMajorAxis 106 * @param semiMinorAxis 107 * @param id 108 * containing the relevant information 109 */ 110 public Ellipsoid( Unit units, double semiMajorAxis, double semiMinorAxis, Identifiable id ) { 111 super( id ); 112 this.units = units; 113 this.semiMajorAxis = semiMajorAxis; 114 this.semiMinorAxis = semiMinorAxis; 115 flattening = ( semiMajorAxis - semiMinorAxis ) / semiMajorAxis; 116 if ( Math.abs( flattening ) > 0.00001 ) { 117 inverseFlattening = 1. / flattening; 118 } else { 119 inverseFlattening = 0; 120 } 121 this.squaredEccentricity = calcSquaredEccentricity( flattening ); 122 this.eccentricity = Math.sqrt( squaredEccentricity ); 123 } 124 125 /** 126 * @param units 127 * @param semiMajorAxis 128 * @param semiMinorAxis 129 * @param identifiers 130 * @param names 131 * @param versions 132 * @param descriptions 133 * @param areasOfUse 134 */ 135 public Ellipsoid( Unit units, double semiMajorAxis, double semiMinorAxis, String[] identifiers, String[] names, 136 String[] versions, String[] descriptions, String[] areasOfUse ) { 137 this( units, semiMajorAxis, semiMinorAxis, new Identifiable( identifiers, names, versions, descriptions, 138 areasOfUse ) ); 139 } 140 141 /** 142 * @param units 143 * @param semiMajorAxis 144 * @param semiMinorAxis 145 * @param identifier 146 * @param name 147 * @param version 148 * @param description 149 * @param areaOfUse 150 */ 151 public Ellipsoid( Unit units, double semiMajorAxis, double semiMinorAxis, String identifier, String name, 152 String version, String description, String areaOfUse ) { 153 this( units, semiMajorAxis, semiMinorAxis, new String[] { identifier }, new String[] { name }, 154 new String[] { version }, new String[] { description }, new String[] { areaOfUse } ); 155 } 156 157 /** 158 * @param units 159 * @param semiMajorAxis 160 * @param semiMinorAxis 161 * @param identifiers 162 */ 163 public Ellipsoid( Unit units, double semiMajorAxis, double semiMinorAxis, String[] identifiers ) { 164 this( units, semiMajorAxis, semiMinorAxis, identifiers, null, null, null, null ); 165 } 166 167 /** 168 * @param units 169 * @param semiMajorAxis 170 * @param semiMinorAxis 171 * @param identifier 172 * @param name 173 */ 174 public Ellipsoid( Unit units, double semiMajorAxis, double semiMinorAxis, String identifier, String name ) { 175 this( units, semiMajorAxis, semiMinorAxis, new String[] { identifier }, new String[] { name }, null, null, null ); 176 } 177 178 /** 179 * @param semiMajorAxis 180 * @param units 181 * @param inverseFlattening 182 * @param id 183 * containing all id relevant data. 184 */ 185 public Ellipsoid( double semiMajorAxis, Unit units, double inverseFlattening, Identifiable id ) { 186 super( id ); 187 this.units = units; 188 this.semiMajorAxis = semiMajorAxis; 189 this.inverseFlattening = inverseFlattening; 190 if ( Math.abs( this.inverseFlattening ) > 0.00001 ) { 191 flattening = 1. / this.inverseFlattening; 192 } else { 193 flattening = 0; 194 } 195 this.squaredEccentricity = calcSquaredEccentricity( this.flattening ); 196 eccentricity = Math.sqrt( squaredEccentricity ); 197 this.semiMinorAxis = this.semiMajorAxis - ( flattening * this.semiMajorAxis ); 198 } 199 200 /** 201 * @param semiMajorAxis 202 * @param units 203 * @param inverseFlattening 204 * @param identifiers 205 * @param names 206 * @param versions 207 * @param descriptions 208 * @param areasOfUse 209 */ 210 public Ellipsoid( double semiMajorAxis, Unit units, double inverseFlattening, String[] identifiers, String[] names, 211 String[] versions, String[] descriptions, String[] areasOfUse ) { 212 this( semiMajorAxis, units, inverseFlattening, new Identifiable( identifiers, names, versions, descriptions, 213 areasOfUse ) ); 214 } 215 216 /** 217 * @param semiMajorAxis 218 * @param units 219 * @param inverseFlattening 220 * @param identifier 221 * @param name 222 * @param version 223 * @param description 224 * @param areaOfUse 225 */ 226 public Ellipsoid( double semiMajorAxis, Unit units, double inverseFlattening, String identifier, String name, 227 String version, String description, String areaOfUse ) { 228 this( semiMajorAxis, units, inverseFlattening, new String[] { identifier }, new String[] { name }, 229 new String[] { version }, new String[] { description }, new String[] { areaOfUse } ); 230 } 231 232 /** 233 * @param semiMajorAxis 234 * @param units 235 * @param inverseFlattening 236 * @param identifiers 237 */ 238 public Ellipsoid( double semiMajorAxis, Unit units, double inverseFlattening, String[] identifiers ) { 239 this( semiMajorAxis, units, inverseFlattening, identifiers, null, null, null, null ); 240 } 241 242 /** 243 * @param semiMajorAxis 244 * @param units 245 * @param inverseFlattening 246 * @param identifier 247 * @param name 248 */ 249 public Ellipsoid( double semiMajorAxis, Unit units, double inverseFlattening, String identifier, String name ) { 250 this( semiMajorAxis, units, inverseFlattening, new String[] { identifier }, new String[] { name }, null, null, 251 null ); 252 } 253 254 /** 255 * @param semiMajorAxis 256 * @param eccentricity 257 * @param units 258 * @param id 259 * containing all id relevant data. 260 */ 261 public Ellipsoid( double semiMajorAxis, double eccentricity, Unit units, Identifiable id ) { 262 super( id ); 263 this.units = units; 264 this.semiMajorAxis = semiMajorAxis; 265 this.eccentricity = eccentricity; 266 this.squaredEccentricity = this.eccentricity * this.eccentricity; 267 this.flattening = calcFlattening( eccentricity ); 268 if ( Math.abs( flattening ) > 0.00001 ) { 269 this.inverseFlattening = 1d / flattening; 270 } else { 271 this.inverseFlattening = 0; 272 } 273 this.semiMinorAxis = this.semiMajorAxis - ( flattening * this.semiMajorAxis ); 274 } 275 276 /** 277 * @param semiMajorAxis 278 * @param eccentricity 279 * @param units 280 * @param identifiers 281 * @param names 282 * @param versions 283 * @param descriptions 284 * @param areasOfUse 285 */ 286 public Ellipsoid( double semiMajorAxis, double eccentricity, Unit units, String[] identifiers, String[] names, 287 String[] versions, String[] descriptions, String[] areasOfUse ) { 288 this( semiMajorAxis, eccentricity, units, new Identifiable( identifiers, names, versions, descriptions, 289 areasOfUse ) ); 290 } 291 292 /** 293 * @param semiMajorAxis 294 * @param eccentricity 295 * @param units 296 * @param identifier 297 * @param name 298 * @param version 299 * @param description 300 * @param areaOfUse 301 */ 302 public Ellipsoid( double semiMajorAxis, double eccentricity, Unit units, String identifier, String name, 303 String version, String description, String areaOfUse ) { 304 this( semiMajorAxis, eccentricity, units, new String[] { identifier }, new String[] { name }, 305 new String[] { version }, new String[] { description }, new String[] { areaOfUse } ); 306 } 307 308 /** 309 * @param semiMajorAxis 310 * @param eccentricity 311 * @param units 312 * @param identifiers 313 */ 314 public Ellipsoid( double semiMajorAxis, double eccentricity, Unit units, String[] identifiers ) { 315 this( semiMajorAxis, eccentricity, units, identifiers, null, null, null, null ); 316 } 317 318 /** 319 * @param semiMajorAxis 320 * @param eccentricity 321 * @param units 322 * @param identifier 323 * @param name 324 */ 325 public Ellipsoid( double semiMajorAxis, double eccentricity, Unit units, String identifier, String name ) { 326 this( semiMajorAxis, eccentricity, units, new String[] { identifier }, new String[] { name }, null, null, null ); 327 } 328 329 /** 330 * @return the eccentricity. 331 */ 332 public final double getEccentricity() { 333 return eccentricity; 334 } 335 336 /** 337 * @return the squared eccentricity of the ellipsoid- 338 */ 339 public final double getSquaredEccentricity() { 340 return squaredEccentricity; 341 } 342 343 /** 344 * @return the flattening. 345 */ 346 public final double getFlattening() { 347 return flattening; 348 } 349 350 /** 351 * @return the inverseFlattening. 352 */ 353 public final double getInverseFlattening() { 354 return inverseFlattening; 355 } 356 357 /** 358 * @return the semiMajorAxis. 359 */ 360 public final double getSemiMajorAxis() { 361 return semiMajorAxis; 362 } 363 364 /** 365 * @return the semiMinorAxis. 366 */ 367 public final double getSemiMinorAxis() { 368 return semiMinorAxis; 369 } 370 371 /** 372 * @return the units. 373 */ 374 public final Unit getUnits() { 375 return units; 376 } 377 378 /** 379 * @param other 380 * another ellipsoid 381 * @return true if the other ellipsoid != null and its units, semi-major-axis and eccentricity are the same. 382 */ 383 @Override 384 public boolean equals( Object other ) { 385 if ( other != null && other instanceof Ellipsoid ) { 386 final Ellipsoid that = (Ellipsoid) other; 387 return this.units.equals( that.units ) && ( Math.abs( this.semiMajorAxis - that.semiMajorAxis ) < EPS11 ) 388 && ( Math.abs( this.eccentricity - that.eccentricity ) < EPS11 ) && super.equals( that ); 389 } 390 return false; 391 } 392 393 /** 394 * Calc the eccentricity from the flattening 395 * 396 * @param flattening 397 * given. 398 * @return the squared eccentricity which is given by e^2 = 2*f - f*f. 399 */ 400 private double calcSquaredEccentricity( double flattening ) { 401 return ( 2. * flattening ) - ( flattening * flattening ); 402 } 403 404 /** 405 * calcs the flattening of an ellispoid using the eccentricity. 406 * 407 * @param eccentricity 408 * given 409 * @return 1-sqrt( 1- e^2) or 0 if e^1 > 1 410 */ 411 private double calcFlattening( double eccentricity ) { 412 if ( eccentricity * eccentricity > 1 ) { 413 return 0; 414 } 415 return 1 - Math.sqrt( ( 1 - eccentricity * eccentricity ) ); 416 } 417 418 @Override 419 public String toString() { 420 StringBuilder sb = new StringBuilder( super.toString() ); 421 sb.append( ", - Units: " ).append( units ); 422 sb.append( ", - semi-major-axis(a): " ).append( semiMajorAxis ); 423 sb.append( ", - semi-minor-axis(b): " ).append( semiMinorAxis ); 424 sb.append( ", - inverse-flattening: " ).append( inverseFlattening ); 425 sb.append( ", - eccentricity: " ).append( eccentricity ); 426 return sb.toString(); 427 } 428 429 /** 430 * Implementation as proposed by Joshua Block in Effective Java (Addison-Wesley 2001), which supplies an even 431 * distribution and is relatively fast. It is created from field <b>f</b> as follows: 432 * <ul> 433 * <li>boolean -- code = (f ? 0 : 1)</li> 434 * <li>byte, char, short, int -- code = (int)f</li> 435 * <li>long -- code = (int)(f ^ (f >>>32))</li> 436 * <li>float -- code = Float.floatToIntBits(f);</li> 437 * <li>double -- long l = Double.doubleToLongBits(f); code = (int)(l ^ (l >>> 32))</li> 438 * <li>all Objects, (where equals( ) calls equals( ) for this field) -- code = f.hashCode( )</li> 439 * <li>Array -- Apply above rules to each element</li> 440 * </ul> 441 * <p> 442 * Combining the hash code(s) computed above: result = 37 * result + code; 443 * </p> 444 * 445 * @return (int) ( result >>> 32 ) ^ (int) result; 446 * 447 * @see java.lang.Object#hashCode() 448 */ 449 @Override 450 public int hashCode() { 451 // the 2nd millionth prime, :-) 452 long code = 32452843; 453 if ( units != null ) { 454 code = code * 37 + units.hashCode(); 455 } 456 long tmp = Double.doubleToLongBits( semiMajorAxis ); 457 code = code * 37 + (int) ( tmp ^ ( tmp >>> 32 ) ); 458 459 tmp = Double.doubleToLongBits( eccentricity ); 460 code = code * 37 + (int) ( tmp ^ ( tmp >>> 32 ) ); 461 462 return (int) ( code >>> 32 ) ^ (int) code; 463 } 464 465 /** 466 * @return true if this ellipsoid has no eccentricity. 467 */ 468 public boolean isSphere() { 469 return eccentricity == 0; 470 } 471 }