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 }