001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/crs/src/org/deegree/model/csct/units/Unit.java $
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 package org.deegree.crs.components;
039
040 import org.deegree.crs.projections.ProjectionUtils;
041
042 /**
043 * The <code>Unit</code> class defines a mechanism to convert between different measurements units, such as
044 * british_yard and meter.
045 *
046 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
047 *
048 * @author last edited by: $Author:$
049 *
050 * @version $Revision:$, $Date:$
051 *
052 */
053
054 public final class Unit {
055
056 /**
057 * Unit of angle.
058 */
059 public static final Unit RADIAN = new Unit( "rad", "Radian" );
060
061 /**
062 * Unit of angle.
063 */
064 public static final Unit DEGREE = new Unit( "°", "Degree", ProjectionUtils.DTR, RADIAN );
065
066 /**
067 * Unit of angle, which is defined to be 1/3600 of a degree, or PI/(180*3600) Radian.
068 */
069 public static final Unit ARC_SEC = new Unit( "\"", "Arcsecond", ProjectionUtils.DTR*(1./3600), RADIAN );
070
071 /**
072 * Base unit of length.
073 */
074 public static final Unit METRE = new Unit( "m", "Metre" );
075
076 /**
077 * British yard; unit of length.
078 */
079 public static final Unit BRITISHYARD = new Unit( "y", "britishyard", 0.9144, METRE );
080
081 /**
082 * US foot; unit of length, with base unit of 0.304 meter.
083 */
084 public static final Unit USFOOT = new Unit( "ft", "", 0.3048006096012192, METRE );
085
086 /**
087 * Base unit of time.
088 */
089 public static final Unit SECOND = new Unit( "s", "Second" );
090
091 /**
092 * Unit of time.
093 */
094 public static final Unit MILLISECOND = new Unit( "ms", "milli second", 0.001, SECOND );
095
096 /**
097 * Unit of time.
098 */
099 public static final Unit DAY = new Unit( "day", "day", 24 * 60 * 60, SECOND );
100
101 /**
102 * The unit's symbol.
103 */
104 private final String symbol;
105
106 /**
107 * The scale factor.
108 */
109 private final double scale;
110
111 /**
112 * Base unit, or <code>this</code> if none.
113 */
114 private final Unit baseType;
115
116 /**
117 * the human readable name of the unit, e.g. metre
118 */
119 private String name;
120
121 /**
122 * Unit constructor.
123 *
124 * @param symbol
125 * @param name
126 * of the unit, e.g. metre
127 */
128 public Unit( final String symbol, final String name ) {
129 this.name = name;
130 this.symbol = symbol;
131 this.scale = 1;
132 this.baseType = this;
133 }
134
135 /**
136 * Will create a unit from the given String. If no appropriate unit was found <code>null<code> will be returned.
137 * @param unit to convert to an actual unit.
138 * @return a unit or <code>null</code>
139 */
140 public static Unit createUnitFromString( final String unit ) {
141 if ( unit != null && !"".equals( unit.trim() ) ) {
142 String t = unit.trim().toUpperCase();
143 if ( "METRE".equals( t ) || "METER".equals( t ) || "M".equals( t ) ) {
144 return METRE;
145 } else if ( "BRITISHYARD".equals( t ) || "Y".equals( t ) ) {
146 return BRITISHYARD;
147 } else if ( "USFOOT".equals( t ) || "FT".equals( t ) ) {
148 return USFOOT;
149 } else if ( "DEGREE".equals( t ) || "°".equals( t ) ) {
150 return DEGREE;
151 } else if ( "RADIAN".equals( t ) || "rad".equals( t ) ) {
152 return RADIAN;
153 } else if ( "SECOND".equals( t ) || "S".equals( t ) ) {
154 return SECOND;
155 } else if ( "MILLISECOND".equals( t ) || "MS".equals( t ) ) {
156 return MILLISECOND;
157 } else if ( "DAY".equals( t ) || "D".equals( t ) ) {
158 return DAY;
159 }
160
161 }
162 return null;
163 }
164
165 /**
166 * Unit constructor.
167 *
168 * @param symbol
169 * of the units, e.g. 'm'
170 * @param name
171 * human readable name, e.g. metre
172 * @param scale
173 * to convert to the base type.
174 * @param baseType
175 * the baseType
176 */
177 public Unit( final String symbol, String name, final double scale, final Unit baseType ) {
178 this.symbol = symbol;
179 this.name = name;
180 this.scale = scale;
181 this.baseType = baseType;
182 }
183
184 /**
185 * Check if amount of the specified unit can be converted into amount of this unit.
186 *
187 * @param other
188 * @return true if canconvert
189 */
190 public boolean canConvert( final Unit other ) {
191 return ( baseType == other.baseType ) || ( baseType != null && baseType.equals( other.baseType ) );
192 }
193
194 /**
195 * Convert a value from one unit to an other.
196 *
197 * @param value
198 * to be converted
199 * @param unit
200 * to convert to
201 * @return the converted value or the same value if this unit equals given unit.
202 * @throws IllegalArgumentException
203 * if no conversion can be applied.
204 */
205 public final double convert( final double value, final Unit unit ) {
206 if ( this.equals( unit ) ) {
207 return value;
208 }
209 if ( canConvert( unit ) ) {
210 return value * unit.scale / scale;
211 }
212 throw new IllegalArgumentException( "Can't convert from \"" + this + "\" to \"" + unit + "\"." );
213 }
214
215 /**
216 * @return the human readable name.
217 */
218 public final String getName() {
219 return ( name != null ) ? name.toLowerCase() : null;
220 }
221
222 /**
223 * @return the symbol of this unit.
224 */
225 @Override
226 public String toString() {
227 return symbol;
228 }
229
230 /**
231 * Compare this unit symbol with the specified object for equality. Only symbols are compared; other parameters are
232 * ignored.
233 */
234 @Override
235 public boolean equals( final Object object ) {
236 if ( object != null && object instanceof Unit ) {
237 final Unit that = (Unit) object;
238 return symbol.equals( that.symbol ) && (Math.abs( this.scale - that.scale ) < 1E-10);
239 }
240 return false;
241 }
242
243 /**
244 * Implementation as proposed by Joshua Block in Effective Java (Addison-Wesley 2001), which supplies an even
245 * distribution and is relatively fast. It is created from field <b>f</b> as follows:
246 * <ul>
247 * <li>boolean -- code = (f ? 0 : 1)</li>
248 * <li>byte, char, short, int -- code = (int)f </li>
249 * <li>long -- code = (int)(f ^ (f >>>32))</li>
250 * <li>float -- code = Float.floatToIntBits(f);</li>
251 * <li>double -- long l = Double.doubleToLongBits(f); code = (int)(l ^ (l >>> 32))</li>
252 * <li>all Objects, (where equals( ) calls equals( ) for this field) -- code = f.hashCode( )</li>
253 * <li>Array -- Apply above rules to each element</li>
254 * </ul>
255 * <p>
256 * Combining the hash code(s) computed above: result = 37 * result + code;
257 * </p>
258 *
259 * @return (int) ( result >>> 32 ) ^ (int) result;
260 *
261 * @see java.lang.Object#hashCode()
262 */
263 @Override
264 public int hashCode() {
265 // the 2nd millionth prime, :-)
266 long code = 32452843;
267 code = code * 37 + symbol.hashCode();
268 long ll = Double.doubleToLongBits( scale );
269 code = code * 37 + (int)( ll ^ (ll >>> 32 ));
270 return (int) ( code >>> 32 ) ^ (int) code;
271 }
272
273 }