001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_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 }