    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 &gt;&gt;&gt;32))</li>
    436         * <li>float -- code = Float.floatToIntBits(f);</li>
    437         * <li>double -- long l = Double.doubleToLongBits(f); code = (int)(l ^ (l &gt;&gt;&gt; 32))</li>
    438         * <li>all Objects, (where equals(&nbsp;) calls equals(&nbsp;) for this field) -- code = f.hashCode(&nbsp;)</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    }