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.coordinatesystems;
040
041 import org.deegree.crs.Identifiable;
042 import org.deegree.crs.components.Axis;
043 import org.deegree.crs.components.GeodeticDatum;
044 import org.deegree.crs.components.Unit;
045
046 /**
047 * Three kinds of <code>CoordinateSystem</code>s (in this class abbreviated with CRS) are supported in this lib.
048 * <ul>
049 * <li>Geographic CRS: A position (on the ellipsoid) is given in Lattitude / Longitude (Polar Cooridnates) given in
050 * rad° min''sec. The order of the position's coordinates are to be contrued to the axis order of the CRS. These lat/lon
051 * coordinates are to be tranformed to x,y,z values to define their location on the underlying datum.</li>
052 * <li>GeoCentric CRS: A position (on the ellipsoid) is given in x, y, z (cartesian) coordinates with the same units
053 * defined as the ones in the underlying datum. The order of the position's coordinates are to be contrued to the axis
054 * order of the datum.</li>
055 * <li>Projected CRS: The position (on the map) is given in a 2D-tuple in pre-defined units. The Axis of the CRS are
056 * defined (through a transformation) for an underlying Datum, which can have it's own axis with their own units. The
057 * order of the position's coordinates are to be contrued to the axis order of the CRS</li>
058 * </ul>
059 *
060 * Summarizing it can be said, that each CRS has following features
061 * <ul>
062 * <li>A reference code (an casesensitive String identifying this CRS, for example 'EPGS:4326' or
063 * 'urn:ogc:def:crs:OGC:2:84' or 'luref')</li>
064 * <li>An optional version.</li>
065 * <li>A humanly readable name.</li>
066 * <li>An optional description.</li>
067 * <li>An optional area of use, describing where this CRS is used.</li>
068 * <li>The order in which the axis of ther crs are defined.</li>
069 * <li>The underlying Datum</li>
070 *
071 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
072 *
073 * @author last edited by: $Author:$
074 *
075 * @version $Revision:$, $Date:$
076 *
077 */
078
079 public abstract class CoordinateSystem extends Identifiable {
080
081 private Axis[] axisOrder;
082
083 private GeodeticDatum usedDatum;
084
085 /**
086 * Defines this CRS as a GeoCentric one.
087 */
088 public static final int GEOCENTRIC_CRS = 0;
089
090 /**
091 * Defines this CRS as a Geographic one.
092 */
093 public static final int GEOGRAPHIC_CRS = 1;
094
095 /**
096 * Defines this CRS as a Projected one.
097 */
098 public static final int PROJECTED_CRS = 2;
099
100 /**
101 * @param datum
102 * of this coordinate system.
103 * @param axisOrder
104 * the axisorder of this coordinate system.
105 * @param identity
106 */
107 public CoordinateSystem( GeodeticDatum datum, Axis[] axisOrder, Identifiable identity ) {
108 super( identity );
109 this.axisOrder = axisOrder;
110 this.usedDatum = datum;
111 }
112
113 /**
114 * @param datum
115 * of this coordinate system.
116 * @param axisOrder
117 * the axisorder of this coordinate system.
118 * @param identifiers
119 * of this coordinate system.
120 * @param names
121 * @param versions
122 * @param descriptions
123 * @param areasOfUse
124 */
125 public CoordinateSystem( GeodeticDatum datum, Axis[] axisOrder, String[] identifiers, String[] names,
126 String[] versions, String[] descriptions, String[] areasOfUse ) {
127 super( identifiers, names, versions, descriptions, areasOfUse );
128 this.axisOrder = axisOrder;
129 this.usedDatum = datum;
130 }
131
132 /**
133 * @return (all) axis' in their defined order.
134 */
135 public final Axis[] getAxis() {
136 return axisOrder;
137 }
138
139 /**
140 * @return the usedDatum.
141 */
142 public final GeodeticDatum getGeodeticDatum() {
143 return usedDatum;
144 }
145
146 /**
147 * @return the units of the coordinatesystem.
148 */
149 public Unit getUnits() {
150 return axisOrder[0].getUnits();
151 }
152
153 /**
154 * @return the dimension of this CRS.
155 */
156 public abstract int getDimension();
157
158 /**
159 * @return one of the *_CRS types defined in this class.
160 */
161 public abstract int getType();
162
163 /**
164 * Helper function to get the typename as a String.
165 *
166 * @return either the type as a name or 'Unknown' if the tpye is not known.
167 */
168 protected String getTypeName() {
169 switch ( getType() ) {
170 case GEOCENTRIC_CRS:
171 return "Geocentric CRS";
172 case PROJECTED_CRS:
173 return "Projected CRS";
174 case GEOGRAPHIC_CRS:
175 return "Geographic CRS";
176 default:
177 return "Unknown CRS";
178 }
179 }
180
181 @Override
182 public boolean equals( Object other ) {
183 if ( other != null && other instanceof CoordinateSystem ) {
184 final CoordinateSystem that = (CoordinateSystem) other;
185 return that.getType() == this.getType() && that.getDimension() == this.getDimension()
186 && matchAxis( that.getAxis() )
187 && that.getGeodeticDatum().equals( this.getGeodeticDatum() );
188 }
189 return false;
190 }
191
192 /**
193 * Checks if the given axis match this.axisOrder[] in length and order.
194 *
195 * @param otherAxis
196 * the axis to check
197 * @return true if the given axis match this.axisOrder[] false otherwise.
198 */
199 private boolean matchAxis( Axis[] otherAxis ) {
200 if ( otherAxis.length != axisOrder.length ) {
201 return false;
202 }
203 for ( int i = 0; i < axisOrder.length; ++i ) {
204 Axis a = axisOrder[i];
205 Axis b = otherAxis[i];
206 if ( !a.equals( b ) ) {
207 return false;
208 }
209 }
210 return true;
211 }
212
213 /**
214 * Implementation as proposed by Joshua Block in Effective Java (Addison-Wesley 2001), which supplies an even
215 * distribution and is relatively fast. It is created from field <b>f</b> as follows:
216 * <ul>
217 * <li>boolean -- code = (f ? 0 : 1)</li>
218 * <li>byte, char, short, int -- code = (int)f </li>
219 * <li>long -- code = (int)(f ^ (f >>>32))</li>
220 * <li>float -- code = Float.floatToIntBits(f);</li>
221 * <li>double -- long l = Double.doubleToLongBits(f); code = (int)(l ^ (l >>> 32))</li>
222 * <li>all Objects, (where equals( ) calls equals( ) for this field) -- code = f.hashCode( )</li>
223 * <li>Array -- Apply above rules to each element</li>
224 * </ul>
225 * <p>
226 * Combining the hash code(s) computed above: result = 37 * result + code;
227 * </p>
228 *
229 * @return (int) ( result >>> 32 ) ^ (int) result;
230 *
231 * @see java.lang.Object#hashCode()
232 */
233 @Override
234 public int hashCode() {
235 // the 2.nd million th. prime, :-)
236 long code = 32452843;
237 if ( axisOrder != null ) {
238 for ( Axis ax : axisOrder ) {
239 code = code * 37 + ax.hashCode();
240 }
241 }
242 if ( usedDatum != null ) {
243 code = code * 37 + usedDatum.hashCode();
244 }
245 code = code * 37 + getType();
246 code = code * 37 + getDimension();
247 return (int) ( code >>> 32 ) ^ (int) code;
248 }
249
250 @Override
251 public String toString() {
252 StringBuilder sb = new StringBuilder( super.toString() );
253 sb.append( "\n - type: " ).append( getTypeName() );
254 sb.append( "\n - datum: " ).append( usedDatum );
255 sb.append( "\n - dimension: " ).append( getDimension() );
256 for ( Axis a : axisOrder ) {
257 sb.append( "\n - axis: " ).append( a.toString() );
258 }
259 return sb.toString();
260
261 }
262
263 }