001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/model/csct/ct/MercatorProjection.java $
002 /*---------------- FILE HEADER ------------------------------------------
003
004 This file is part of deegree.
005 Copyright (C) 2001 by:
006 EXSE, Department of Geography, University of Bonn
007 http://www.giub.uni-bonn.de/exse/
008 lat/lon GmbH
009 http://www.lat-lon.de
010
011 It has been implemented within SEAGIS - An OpenSource implementation of OpenGIS specification
012 (C) 2001, Institut de Recherche pour le D�veloppement (http://sourceforge.net/projects/seagis/)
013 SEAGIS Contacts: Surveillance de l'Environnement Assist�e par Satellite
014 Institut de Recherche pour le D�veloppement / US-Espace
015 mailto:seasnet@teledetection.fr
016
017
018 This library is free software; you can redistribute it and/or
019 modify it under the terms of the GNU Lesser General Public
020 License as published by the Free Software Foundation; either
021 version 2.1 of the License, or (at your option) any later version.
022
023 This library is distributed in the hope that it will be useful,
024 but WITHOUT ANY WARRANTY; without even the implied warranty of
025 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
026 Lesser General Public License for more details.
027
028 You should have received a copy of the GNU Lesser General Public
029 License along with this library; if not, write to the Free Software
030 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
031
032 Contact:
033
034 Andreas Poth
035 lat/lon GmbH
036 Aennchenstr. 19
037 53115 Bonn
038 Germany
039 E-Mail: poth@lat-lon.de
040
041 Klaus Greve
042 Department of Geography
043 University of Bonn
044 Meckenheimer Allee 166
045 53115 Bonn
046 Germany
047 E-Mail: klaus.greve@uni-bonn.de
048
049
050 ---------------------------------------------------------------------------*/
051 package org.deegree.model.csct.ct;
052
053 // OpenGIS (SEAS) dependencies
054 import java.awt.geom.Point2D;
055
056 import org.deegree.model.csct.cs.Projection;
057 import org.deegree.model.csct.pt.Latitude;
058 import org.deegree.model.csct.resources.css.ResourceKeys;
059 import org.deegree.model.csct.resources.css.Resources;
060
061
062 /**
063 * Projection cylindrique de Mercator. Les parall�les et les m�ridients apparaissent
064 * comme des lignes droites et se croisent � angles droits; cette projection produit
065 * donc des cartes rectangulaires. L'�chelle est vrai le long de l'�quateur (par d�faut)
066 * ou le long de deux parall�les �quidistants de l'�quateur. Cette projection est utilis�e
067 * pour repr�senter des r�gions pr�s de l'�quateur. Elle est aussi souvent utilis�e pour la
068 * navigation maritime parce que toutes les lignes droites sur la carte sont des lignes
069 * <em>loxodromiques</em>, c'est-�-dire qu'un navire suivant cette ligne garderait un azimuth
070 * constant sur son compas.
071 * <br><br>
072 *
073 * R�f�rence: John P. Snyder (Map Projections - A Working Manual,
074 * U.S. Geological Survey Professional Paper 1395, 1987)
075 *
076 * @version 1.0
077 * @author Andr� Gosselin
078 * @author Martin Desruisseaux
079 */
080 final class MercatorProjection extends CylindricalProjection
081 {
082 /**
083 * Global scale factor. Value <code>ak0</code>
084 * is equals to <code>{@link #a}*k0</code>.
085 */
086 private final double ak0;
087
088 /**
089 * Construct a new map projection from the suplied parameters.
090 *
091 * @param parameters The parameter values in standard units.
092 * @throws MissingParameterException if a mandatory parameter is missing.
093 */
094 protected MercatorProjection(final Projection parameters) throws MissingParameterException
095 {
096 //////////////////////////
097 // Fetch parameters //
098 //////////////////////////
099 super(parameters);
100 centralLatitude = latitudeToRadians(parameters.getValue("latitude_of_origin", 0), false);
101 final double latitudeTrueScale = Math.abs(centralLatitude);
102
103 //////////////////////////
104 // Compute constants //
105 //////////////////////////
106 if (isSpherical)
107 {
108 ak0 = a*Math.cos(latitudeTrueScale);
109 }
110 else
111 {
112 ak0 = a*msfn(Math.sin(latitudeTrueScale), Math.cos(latitudeTrueScale));
113 }
114 }
115
116 /**
117 * Returns a human readable name localized for the specified locale.
118 */
119 public String getName()
120 {return Resources.getResources(null).getString(ResourceKeys.CYLINDRICAL_MERCATOR_PROJECTION);}
121
122 /**
123 * Transforms the specified (<var>x</var>,<var>y</var>) coordinate
124 * and stores the result in <code>ptDst</code>.
125 */
126 protected Point2D transform(double x, double y, final Point2D ptDst) throws TransformException
127 {
128 if (Math.abs(y) > (Math.PI/2 - EPS))
129 {
130 throw new TransformException(Resources.format(ResourceKeys.ERROR_POLE_PROJECTION_$1, new Latitude(Math.toDegrees(y))));
131 }
132 x = (x-centralMeridian)*ak0;
133 if (isSpherical)
134 {
135 y = ak0*Math.log(Math.tan((Math.PI/4.0) + 0.5*y));
136 }
137 else
138 {
139 y = -ak0*Math.log(tsfn(y, Math.sin(y)));
140 }
141 if (ptDst!=null)
142 {
143 ptDst.setLocation(x,y);
144 return ptDst;
145 }
146 return new Point2D.Double(x,y);
147 }
148
149 /**
150 * Transforms the specified (<var>x</var>,<var>y</var>) coordinate
151 * and stores the result in <code>ptDst</code>.
152 */
153 protected Point2D inverseTransform(double x, double y, final Point2D ptDst) throws TransformException
154 {
155 x = x/ak0 + centralMeridian;
156 y = Math.exp(-y/ak0);
157 if (isSpherical)
158 {
159 y = (Math.PI/2.0) - 2.0*Math.atan(y);
160 }
161 else
162 {
163 y = cphi2(y);
164 }
165 if (ptDst!=null)
166 {
167 ptDst.setLocation(x,y);
168 return ptDst;
169 }
170 return new Point2D.Double(x,y);
171 }
172
173 /**
174 * Returns a hash value for this projection.
175 */
176 public int hashCode()
177 {
178 final long code = Double.doubleToLongBits(ak0);
179 return ((int)code ^ (int)(code >>> 32)) + 37*super.hashCode();
180 }
181
182 /**
183 * Compares the specified object with
184 * this map projection for equality.
185 */
186 public boolean equals(final Object object)
187 {
188 if (object==this) return true; // Slight optimization
189 if (super.equals(object))
190 {
191 final MercatorProjection that = (MercatorProjection) object;
192 return Double.doubleToLongBits(this.ak0) == Double.doubleToLongBits(that.ak0);
193 }
194 return false;
195 }
196
197 /**
198 * Informations about a {@link MercatorProjection}.
199 *
200 * @version 1.0
201 * @author Martin Desruisseaux
202 */
203 static final class Provider extends MapProjection.Provider
204 {
205 /**
206 * Construct a new provider.
207 */
208 public Provider()
209 {super("Mercator_1SP", ResourceKeys.CYLINDRICAL_MERCATOR_PROJECTION);}
210
211 /**
212 * Create a new map projection.
213 */
214 protected Object create(final Projection parameters)
215 {return new MercatorProjection(parameters);}
216 }
217 }