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.projections.conic;
040    
041    import javax.vecmath.Point2d;
042    
043    import org.deegree.crs.components.Unit;
044    import org.deegree.crs.coordinatesystems.GeographicCRS;
045    import org.deegree.crs.projections.ProjectionUtils;
046    import org.deegree.crs.projections.Projection;
047    
048    /**
049     * The <code>ConicProjection</code> is a super class for all conic projections.
050     * <p>
051     * <q>(From Snyder p.97)</q>
052     * </p>
053     * <p>
054     * To show a region for which the greatest extent is from east to west in the temperate zones, conic projections are
055     * usually preferable to cylindrical projections.
056     * </p>
057     * <p>
058     * Normal conic projections are distinguished by the use of arcs of concentric circles for parallesl of latitude and
059     * equally spaced straight radii of these circles for meridians. The angles between the meridians on the map are smaller
060     * than the actual differences in longitude. The circular arcs may or may not be equally spaced, depending on the
061     * projections. The polyconic projections and the oblique conic projections have characteristcs different from these.
062     * </p>
063     * <p>
064     * There are three important classes of conic projections:
065     * <ul>
066     * <li>The equidistant</li>
067     * <li>the conformal</li>
068     * <li>the equal area</li>
069     * </ul>
070     * </p>
071     * 
072     * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
073     * 
074     * @author last edited by: $Author:$
075     * 
076     * @version $Revision:$, $Date:$
077     * 
078     */
079    
080    public abstract class ConicProjection extends Projection {
081        private double firstParallelLatitude;
082    
083        private double secondParallelLatitude;
084    
085        /**
086         * @param firstParallelLatitude
087         *            the latitude (in radians) of the first parallel. (Snyder phi_1).
088         * @param secondParallelLatitude
089         *            the latitude (in radians) of the second parallel. (Snyder phi_2).
090         * @param geographicCRS
091         * @param falseNorthing
092         * @param falseEasting
093         * @param naturalOrigin
094         * @param units
095         * @param scale
096         * @param conformal
097         * @param equalArea
098         * @param identifiers
099         * @param names
100         * @param versions
101         * @param descriptions
102         * @param areasOfUse
103         */
104        public ConicProjection( double firstParallelLatitude, double secondParallelLatitude, GeographicCRS geographicCRS,
105                                double falseNorthing, double falseEasting, Point2d naturalOrigin, Unit units, double scale,
106                                boolean conformal, boolean equalArea, String[] identifiers, String[] names,
107                                String[] versions, String[] descriptions, String[] areasOfUse ) {
108            super( geographicCRS,
109                   falseNorthing,
110                   falseEasting,
111                   naturalOrigin,
112                   units,
113                   scale,
114                   conformal,
115                   equalArea,
116                   identifiers,
117                   names,
118                   versions,
119                   descriptions,
120                   areasOfUse );
121    
122            if ( Double.isNaN( firstParallelLatitude ) || firstParallelLatitude == 0
123                 || Math.abs( firstParallelLatitude ) < ProjectionUtils.EPS10
124                 || firstParallelLatitude < ProjectionUtils.WORLD_BOUNDS_RAD.getMinY()
125                 || firstParallelLatitude > ProjectionUtils.WORLD_BOUNDS_RAD.getMaxY() ) {
126                this.firstParallelLatitude = getProjectionLatitude();
127                this.secondParallelLatitude = getProjectionLatitude();
128            } else {
129                this.firstParallelLatitude = firstParallelLatitude;
130                this.secondParallelLatitude = secondParallelLatitude;
131                if ( this.secondParallelLatitude < ProjectionUtils.WORLD_BOUNDS_RAD.getMinY() || this.secondParallelLatitude > ProjectionUtils.WORLD_BOUNDS_RAD.getMaxY() ) {
132                    // System.out.println( "setting to nan");
133                    this.secondParallelLatitude = Double.NaN;
134                }
135                // System.out.println( "given latitude and longitude: " + Math.toDegrees( this.firstParallelLatitude ) + "
136                // and " + Math.toDegrees( this.secondParallelLatitude ));
137            }
138        }
139    
140        /**
141         * @return the latitude of the first parallel which is the intersection of the earth with the cone or the
142         *         projectionLatitude if the cone is tangential with earth (e.g. one standard parallel).
143         */
144        public final double getFirstParallelLatitude() {
145            return firstParallelLatitude;
146        }
147    
148        /**
149         * @return the latitude of the first parallel which is the intersection of the earth with the cone or the
150         *         projectionLatitude if the cone is tangential with earth (e.g. one standard parallel).
151         */
152        public final double getSecondParallelLatitude() {
153            return secondParallelLatitude;
154        }
155    
156        @Override
157        public boolean equals( Object other ) {
158            if ( other != null && other instanceof ConicProjection ) {
159                final ConicProjection that = (ConicProjection) other;
160                return super.equals( other ) && Math.abs( this.firstParallelLatitude - that.firstParallelLatitude ) < ProjectionUtils.EPS11
161                       && Math.abs( this.secondParallelLatitude - that.secondParallelLatitude ) < ProjectionUtils.EPS11;
162            }
163            return false;
164        }
165    
166        /**
167         * Implementation as proposed by Joshua Block in Effective Java (Addison-Wesley 2001), which supplies an even
168         * distribution and is relatively fast. It is created from field <b>f</b> as follows:
169         * <ul>
170         * <li>boolean -- code = (f ? 0 : 1)</li>
171         * <li>byte, char, short, int -- code = (int)f </li>
172         * <li>long -- code = (int)(f ^ (f &gt;&gt;&gt;32))</li>
173         * <li>float -- code = Float.floatToIntBits(f);</li>
174         * <li>double -- long l = Double.doubleToLongBits(f); code = (int)(l ^ (l &gt;&gt;&gt; 32))</li>
175         * <li>all Objects, (where equals(&nbsp;) calls equals(&nbsp;) for this field) -- code = f.hashCode(&nbsp;)</li>
176         * <li>Array -- Apply above rules to each element</li>
177         * </ul>
178         * <p>
179         * Combining the hash code(s) computed above: result = 37 * result + code;
180         * </p>
181         * 
182         * @return (int) ( result >>> 32 ) ^ (int) result;
183         * 
184         * @see java.lang.Object#hashCode()
185         */
186        @Override
187        public int hashCode() {
188            // the 2nd millionth prime, :-)
189            long code = 32452843;
190            code = code * 37 + super.hashCode();
191    
192            long tmp = Double.doubleToLongBits( firstParallelLatitude );
193            code = code * 37 + (int) ( tmp ^ ( tmp >>> 32 ) );
194    
195            tmp = Double.doubleToLongBits( secondParallelLatitude );
196            code = code * 37 + (int) ( tmp ^ ( tmp >>> 32 ) );
197    
198            return (int) ( code >>> 32 ) ^ (int) code;
199        }
200    }