001 //$HeadURL: $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 This file is part of deegree. 004 Copyright (C) 2001-2008 by: 005 Department of Geography, University of Bonn 006 http://www.giub.uni-bonn.de/deegree/ 007 lat/lon GmbH 008 http://www.lat-lon.de 009 010 This library is free software; you can redistribute it and/or 011 modify it under the terms of the GNU Lesser General Public 012 License as published by the Free Software Foundation; either 013 version 2.1 of the License, or (at your option) any later version. 014 This library is distributed in the hope that it will be useful, 015 but WITHOUT ANY WARRANTY; without even the implied warranty of 016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 017 Lesser General Public License for more details. 018 You should have received a copy of the GNU Lesser General Public 019 License along with this library; if not, write to the Free Software 020 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 021 Contact: 022 023 Andreas Poth 024 lat/lon GmbH 025 Aennchenstr. 19 026 53177 Bonn 027 Germany 028 E-Mail: poth@lat-lon.de 029 030 Prof. Dr. Klaus Greve 031 Department of Geography 032 University of Bonn 033 Meckenheimer Allee 166 034 53115 Bonn 035 Germany 036 E-Mail: greve@giub.uni-bonn.de 037 ---------------------------------------------------------------------------*/ 038 039 package org.deegree.crs.components; 040 041 import org.deegree.crs.Identifiable; 042 import org.deegree.crs.projections.ProjectionUtils; 043 044 /** 045 * The <code>Ellipsoid</code> class hold all parameters which are necessary to define an Ellipsoid. Every Ellipsoid 046 * has a semi-major-axis and one of inverse_flattening, eccentricity or semi-minor-axis. 047 * 048 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a> 049 * 050 * @author last edited by: $Author:$ 051 * 052 * @version $Revision:$, $Date:$ 053 * 054 */ 055 056 public class Ellipsoid extends Identifiable { 057 058 /** 059 * WGS 1984 ellipsoid. This ellipsoid is used in the GPS system and is the "default" Ellipsoid. 060 */ 061 public static final Ellipsoid WGS84 = new Ellipsoid( 6378137.0, 062 Unit.METRE, 063 298.257223563, 064 "EPSG:7030", 065 "WGS84_Ellipsoid" ); 066 067 /** 068 * the larger one of the two (semi)axis of an ellipsoid 069 */ 070 private double semiMajorAxis; 071 072 /** 073 * the smaller one of the two (semi)axis of an ellipsoid 074 */ 075 private double semiMinorAxis; 076 077 /** 078 * the units of the axis 079 */ 080 private 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 double flattening; 086 087 /** 088 * Flattening f is normally given as 1/... value therefore an inverse is often given. 089 */ 090 private 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 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 double squaredEccentricity; 102 103 /** 104 * @param units 105 * @param semiMajorAxis 106 * @param semiMinorAxis 107 * @param identifiers 108 * @param names 109 * @param versions 110 * @param descriptions 111 * @param areasOfUse 112 */ 113 public Ellipsoid( Unit units, double semiMajorAxis, double semiMinorAxis, String[] identifiers, String[] names, 114 String[] versions, String[] descriptions, String[] areasOfUse ) { 115 super( identifiers, names, versions, descriptions, areasOfUse ); 116 this.units = units; 117 this.semiMajorAxis = semiMajorAxis; 118 this.semiMinorAxis = semiMinorAxis; 119 flattening = ( semiMajorAxis - semiMinorAxis ) / semiMajorAxis; 120 if ( Math.abs( flattening ) > 0.00001 ) { 121 inverseFlattening = 1. / flattening; 122 } else { 123 inverseFlattening = 0; 124 } 125 this.squaredEccentricity = calcSquaredEccentricity( flattening ); 126 this.eccentricity = Math.sqrt( squaredEccentricity ); 127 } 128 129 /** 130 * @param units 131 * @param semiMajorAxis 132 * @param semiMinorAxis 133 * @param identifier 134 * @param name 135 * @param version 136 * @param description 137 * @param areaOfUse 138 */ 139 public Ellipsoid( Unit units, double semiMajorAxis, double semiMinorAxis, String identifier, String name, 140 String version, String description, String areaOfUse ) { 141 this( units, 142 semiMajorAxis, 143 semiMinorAxis, 144 new String[] { identifier }, 145 new String[] { name }, 146 new String[] { version }, 147 new String[] { description }, 148 new String[] { areaOfUse } ); 149 } 150 151 /** 152 * @param units 153 * @param semiMajorAxis 154 * @param semiMinorAxis 155 * @param identifiers 156 */ 157 public Ellipsoid( Unit units, double semiMajorAxis, double semiMinorAxis, String[] identifiers ) { 158 this( units, semiMajorAxis, semiMinorAxis, identifiers, null, null, null, null ); 159 } 160 161 /** 162 * @param units 163 * @param semiMajorAxis 164 * @param semiMinorAxis 165 * @param identifier 166 * @param name 167 */ 168 public Ellipsoid( Unit units, double semiMajorAxis, double semiMinorAxis, String identifier, String name ) { 169 this( units, semiMajorAxis, semiMinorAxis, new String[] { identifier }, new String[] { name }, null, null, null ); 170 } 171 172 /** 173 * @param semiMajorAxis 174 * @param units 175 * @param inverseFlattening 176 * @param identifiers 177 * @param names 178 * @param versions 179 * @param descriptions 180 * @param areasOfUse 181 */ 182 public Ellipsoid( double semiMajorAxis, Unit units, double inverseFlattening, String[] identifiers, String[] names, 183 String[] versions, String[] descriptions, String[] areasOfUse ) { 184 super( identifiers, names, versions, descriptions, areasOfUse ); 185 this.units = units; 186 this.semiMajorAxis = semiMajorAxis; 187 this.inverseFlattening = inverseFlattening; 188 if ( Math.abs( this.inverseFlattening ) > 0.00001 ) { 189 flattening = 1. / this.inverseFlattening; 190 } else { 191 flattening = 0; 192 } 193 this.squaredEccentricity = calcSquaredEccentricity( this.flattening ); 194 eccentricity = Math.sqrt( squaredEccentricity ); 195 this.semiMinorAxis = this.semiMajorAxis - ( flattening * this.semiMajorAxis ); 196 } 197 198 /** 199 * @param semiMajorAxis 200 * @param units 201 * @param inverseFlattening 202 * @param identifier 203 * @param name 204 * @param version 205 * @param description 206 * @param areaOfUse 207 */ 208 public Ellipsoid( double semiMajorAxis, Unit units, double inverseFlattening, String identifier, String name, 209 String version, String description, String areaOfUse ) { 210 this( semiMajorAxis, 211 units, 212 inverseFlattening, 213 new String[] { identifier }, 214 new String[] { name }, 215 new String[] { version }, 216 new String[] { description }, 217 new String[] { areaOfUse } ); 218 } 219 220 /** 221 * @param semiMajorAxis 222 * @param units 223 * @param inverseFlattening 224 * @param identifiers 225 */ 226 public Ellipsoid( double semiMajorAxis, Unit units, double inverseFlattening, String[] identifiers ) { 227 this( semiMajorAxis, units, inverseFlattening, identifiers, null, null, null, null ); 228 } 229 230 /** 231 * @param semiMajorAxis 232 * @param units 233 * @param inverseFlattening 234 * @param identifier 235 * @param name 236 */ 237 public Ellipsoid( double semiMajorAxis, Unit units, double inverseFlattening, String identifier, String name ) { 238 this( semiMajorAxis, 239 units, 240 inverseFlattening, 241 new String[] { identifier }, 242 new String[] { name }, 243 null, 244 null, 245 null ); 246 } 247 248 /** 249 * @param semiMajorAxis 250 * @param eccentricity 251 * @param units 252 * @param identifiers 253 * @param names 254 * @param versions 255 * @param descriptions 256 * @param areasOfUse 257 */ 258 public Ellipsoid( double semiMajorAxis, double eccentricity, Unit units, String[] identifiers, String[] names, 259 String[] versions, String[] descriptions, String[] areasOfUse ) { 260 super( identifiers, names, versions, descriptions, areasOfUse ); 261 this.units = units; 262 this.semiMajorAxis = semiMajorAxis; 263 this.eccentricity = eccentricity; 264 this.squaredEccentricity = this.eccentricity * this.eccentricity; 265 this.flattening = calcFlattening( eccentricity ); 266 if ( Math.abs( flattening ) > 0.00001 ) { 267 this.inverseFlattening = 1d / flattening; 268 } else { 269 this.inverseFlattening = 0; 270 } 271 this.semiMinorAxis = this.semiMajorAxis - ( flattening * this.semiMajorAxis ); 272 } 273 274 /** 275 * @param semiMajorAxis 276 * @param eccentricity 277 * @param units 278 * @param identifier 279 * @param name 280 * @param version 281 * @param description 282 * @param areaOfUse 283 */ 284 public Ellipsoid( double semiMajorAxis, double eccentricity, Unit units, String identifier, String name, 285 String version, String description, String areaOfUse ) { 286 this( semiMajorAxis, 287 eccentricity, 288 units, 289 new String[] { identifier }, 290 new String[] { name }, 291 new String[] { version }, 292 new String[] { description }, 293 new String[] { areaOfUse } ); 294 } 295 296 /** 297 * @param semiMajorAxis 298 * @param eccentricity 299 * @param units 300 * @param identifiers 301 */ 302 public Ellipsoid( double semiMajorAxis, double eccentricity, Unit units, String[] identifiers ) { 303 this( semiMajorAxis, eccentricity, units, identifiers, null, null, null, null ); 304 } 305 306 /** 307 * @param semiMajorAxis 308 * @param eccentricity 309 * @param units 310 * @param identifier 311 * @param name 312 */ 313 public Ellipsoid( double semiMajorAxis, double eccentricity, Unit units, String identifier, String name ) { 314 this( semiMajorAxis, eccentricity, units, new String[] { identifier }, new String[] { name }, null, null, null ); 315 } 316 317 /** 318 * @return the eccentricity. 319 */ 320 public final double getEccentricity() { 321 return eccentricity; 322 } 323 324 /** 325 * @return the squared eccentricity of the ellipsoid- 326 */ 327 public final double getSquaredEccentricity() { 328 return squaredEccentricity; 329 } 330 331 /** 332 * @return the flattening. 333 */ 334 public final double getFlattening() { 335 return flattening; 336 } 337 338 /** 339 * @return the inverseFlattening. 340 */ 341 public final double getInverseFlattening() { 342 return inverseFlattening; 343 } 344 345 /** 346 * @return the semiMajorAxis. 347 */ 348 public final double getSemiMajorAxis() { 349 return semiMajorAxis; 350 } 351 352 /** 353 * @return the semiMinorAxis. 354 */ 355 public final double getSemiMinorAxis() { 356 return semiMinorAxis; 357 } 358 359 /** 360 * @return the units. 361 */ 362 public final Unit getUnits() { 363 return units; 364 } 365 366 /** 367 * @param other 368 * another ellipsoid 369 * @return true if the other ellipsoid != null and its units, seminminoraxis and eccentricity are the same. 370 */ 371 @Override 372 public boolean equals( Object other ) { 373 if ( other != null && other instanceof Ellipsoid ) { 374 final Ellipsoid that = (Ellipsoid) other; 375 return this.units.equals( that.units ) && ( Math.abs( this.semiMinorAxis - that.semiMinorAxis ) < ProjectionUtils.EPS11 ) 376 && ( Math.abs( this.eccentricity - that.eccentricity ) < ProjectionUtils.EPS11 ); 377 } 378 return false; 379 } 380 381 /** 382 * Calc the eccentricity from the flattening 383 * 384 * @param flattening 385 * given. 386 * @return the squared eccentricity which is given by e^2 = 2*f - f*f. 387 */ 388 private double calcSquaredEccentricity( double flattening ) { 389 return ( 2. * flattening ) - ( flattening * flattening ); 390 } 391 392 /** 393 * calcs the flattening of an ellispoid using the eccentricity. 394 * 395 * @param eccentricity 396 * given 397 * @return 1-sqrt( 1- e^2) or 0 if e^1 > 1 398 */ 399 private double calcFlattening( double eccentricity ) { 400 if ( eccentricity * eccentricity > 1 ) { 401 return 0; 402 } 403 return 1 - Math.sqrt( ( 1 - eccentricity * eccentricity ) ); 404 } 405 406 @Override 407 public String toString() { 408 StringBuilder sb = new StringBuilder( super.toString() ); 409 sb.append( ", - Units: " ).append( units ); 410 sb.append( ", - semi-major-axis(a): " ).append( semiMajorAxis ); 411 sb.append( ", - semi-minor-axis(b): " ).append( semiMinorAxis ); 412 sb.append( ", - inverse-flattening: " ).append( inverseFlattening ); 413 sb.append( ", - eccentricity: " ).append( eccentricity ); 414 return sb.toString(); 415 } 416 417 /** 418 * Implementation as proposed by Joshua Block in Effective Java (Addison-Wesley 2001), which supplies an even 419 * distribution and is relatively fast. It is created from field <b>f</b> as follows: 420 * <ul> 421 * <li>boolean -- code = (f ? 0 : 1)</li> 422 * <li>byte, char, short, int -- code = (int)f </li> 423 * <li>long -- code = (int)(f ^ (f >>>32))</li> 424 * <li>float -- code = Float.floatToIntBits(f);</li> 425 * <li>double -- long l = Double.doubleToLongBits(f); code = (int)(l ^ (l >>> 32))</li> 426 * <li>all Objects, (where equals( ) calls equals( ) for this field) -- code = f.hashCode( )</li> 427 * <li>Array -- Apply above rules to each element</li> 428 * </ul> 429 * <p> 430 * Combining the hash code(s) computed above: result = 37 * result + code; 431 * </p> 432 * 433 * @return (int) ( result >>> 32 ) ^ (int) result; 434 * 435 * @see java.lang.Object#hashCode() 436 */ 437 @Override 438 public int hashCode() { 439 // the 2nd millionth prime, :-) 440 long code = 32452843; 441 if ( units != null ) { 442 code = code * 37 + units.hashCode(); 443 } 444 long tmp = Double.doubleToLongBits( semiMinorAxis ); 445 code = code * 37 + (int) ( tmp ^ ( tmp >>> 32 ) ); 446 447 tmp = Double.doubleToLongBits( eccentricity ); 448 code = code * 37 + (int) ( tmp ^ ( tmp >>> 32 ) ); 449 450 return (int) ( code >>> 32 ) ^ (int) code; 451 } 452 }