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 }