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 }