001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/crs/components/Unit.java $ 002 /*---------------------------------------------------------------------------- 003 This file is part of deegree, http://deegree.org/ 004 Copyright (C) 2001-2009 by: 005 Department of Geography, University of Bonn 006 and 007 lat/lon GmbH 008 009 This library is free software; you can redistribute it and/or modify it under 010 the terms of the GNU Lesser General Public License as published by the Free 011 Software Foundation; either version 2.1 of the License, or (at your option) 012 any later version. 013 This library is distributed in the hope that it will be useful, but WITHOUT 014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 016 details. 017 You should have received a copy of the GNU Lesser General Public License 018 along with this library; if not, write to the Free Software Foundation, Inc., 019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 020 021 Contact information: 022 023 lat/lon GmbH 024 Aennchenstr. 19, 53177 Bonn 025 Germany 026 http://lat-lon.de/ 027 028 Department of Geography, University of Bonn 029 Prof. Dr. Klaus Greve 030 Postfach 1147, 53001 Bonn 031 Germany 032 http://www.geographie.uni-bonn.de/deegree/ 033 034 e-mail: info@deegree.org 035 ----------------------------------------------------------------------------*/ 036 package org.deegree.crs.components; 037 038 import static org.deegree.crs.projections.ProjectionUtils.DTR; 039 import static org.deegree.crs.utilities.MappingUtils.matchEPSGString; 040 041 import java.io.Serializable; 042 043 import org.deegree.crs.Identifiable; 044 045 /** 046 * The <code>Unit</code> class defines a mechanism to convert between different measurements units, such as british_yard 047 * and meter. 048 * 049 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a> 050 * 051 * @author last edited by: $Author: apoth $ 052 * 053 * @version $Revision: 22735 $, $Date: 2010-02-24 15:46:50 +0100 (Mi, 24 Feb 2010) $ 054 * 055 */ 056 057 public final class Unit extends Identifiable implements Serializable { 058 059 private static final long serialVersionUID = 4176657042228182638L; 060 061 /** 062 * Unit of angle. 063 */ 064 public static final Unit RADIAN = new Unit( "rad", "Radian" ); 065 066 /** 067 * Unit of angle. 068 */ 069 public static final Unit DEGREE = new Unit( "°", "Degree", DTR, RADIAN ); 070 071 /** 072 * Unit of angle, which is defined to be 1/3600 of a degree, or PI/(180*3600) Radian. 073 */ 074 public static final Unit ARC_SEC = new Unit( "\"", "Arcsecond", DTR * ( 1. / 3600 ), RADIAN ); 075 076 /** 077 * Base unit of length. 078 */ 079 public static final Unit METRE = new Unit( "m", "Metre" ); 080 081 /** 082 * British yard; unit of length. 083 */ 084 public static final Unit BRITISHYARD = new Unit( "y", "britishyard", 0.9144, METRE ); 085 086 /** 087 * US foot; unit of length, with base unit of 0.304 meter. 088 */ 089 public static final Unit USFOOT = new Unit( "ft", "usfoot", 0.3048006096012192, METRE ); 090 091 /** 092 * Base unit of time. 093 */ 094 public static final Unit SECOND = new Unit( "s", "Second" ); 095 096 /** 097 * Unit of time. 098 */ 099 public static final Unit MILLISECOND = new Unit( "ms", "milli second", 0.001, SECOND ); 100 101 /** 102 * Unit of time. 103 */ 104 public static final Unit DAY = new Unit( "day", "day", 24 * 60 * 60, SECOND ); 105 106 /** 107 * The unit's symbol. 108 */ 109 private final String symbol; 110 111 /** 112 * The scale factor. 113 */ 114 private final double scale; 115 116 /** 117 * Base unit, or <code>this</code> if none. 118 */ 119 private final Unit baseType; 120 121 /** 122 * Unit constructor. 123 * 124 * @param symbol 125 * @param name 126 * of the unit, e.g. metre 127 * @param id 128 * of the unit 129 */ 130 public Unit( final String symbol, final String name, final String id ) { 131 super( new Identifiable( new String[] { id }, new String[] { name }, null, null, null ) ); 132 this.symbol = symbol; 133 this.scale = 1; 134 this.baseType = this; 135 } 136 137 /** 138 * Unit constructor. 139 * 140 * @param symbol 141 * @param name 142 * of the unit, e.g. metre 143 */ 144 public Unit( final String symbol, final String name ) { 145 this( symbol, name, name ); 146 } 147 148 /** 149 * Unit constructor, which uses the name as the id. 150 * 151 * @param symbol 152 * of the units, e.g. 'm' 153 * @param name 154 * human readable name, e.g. metre 155 * @param scale 156 * to convert to the base type. 157 * @param baseType 158 * the baseType 159 */ 160 public Unit( final String symbol, String name, final double scale, final Unit baseType ) { 161 this( symbol, name, name, scale, baseType ); 162 } 163 164 /** 165 * Unit constructor. 166 * 167 * @param symbol 168 * of the units, e.g. 'm' 169 * @param name 170 * human readable name, e.g. metre 171 * @param id 172 * of the unit. 173 * @param scale 174 * to convert to the base type. 175 * @param baseType 176 * the baseType 177 */ 178 public Unit( final String symbol, String name, String id, final double scale, final Unit baseType ) { 179 super( new Identifiable( new String[] { id }, new String[] { name }, null, null, null ) ); 180 this.symbol = symbol; 181 this.scale = scale; 182 this.baseType = baseType; 183 } 184 185 /** 186 * Will create a unit from the given String. If no appropriate unit was found <code>null<code> will be returned. 187 * 188 * @param unit 189 * to convert to an actual unit. 190 * @return a unit or <code>null</code> 191 */ 192 public static Unit createUnitFromString( final String unit ) { 193 if ( unit != null && !"".equals( unit.trim() ) ) { 194 String t = unit.trim().toUpperCase(); 195 if ( "METRE".equals( t ) || "METER".equals( t ) || "M".equals( t ) || matchEPSGString( unit, "uom", "9001" ) ) { 196 return METRE; 197 } else if ( "BRITISHYARD".equals( t ) || "Y".equals( t ) || matchEPSGString( unit, "uom", "9060" ) ) { 198 return BRITISHYARD; 199 } else if ( "USFOOT".equals( t ) || "FT".equals( t ) || matchEPSGString( unit, "uom", "9003" ) ) { 200 return USFOOT; 201 } else if ( "DEGREE".equals( t ) || "°".equals( t ) || matchEPSGString( unit, "uom", "9102" ) ) { 202 return DEGREE; 203 } else if ( "RADIAN".equals( t ) || "rad".equals( t ) || matchEPSGString( unit, "uom", "9101" ) ) { 204 return RADIAN; 205 } else if ( "SECOND".equals( t ) || "S".equals( t ) ) { 206 return SECOND; 207 } else if ( "MILLISECOND".equals( t ) || "MS".equals( t ) ) { 208 return MILLISECOND; 209 } else if ( "DAY".equals( t ) || "D".equals( t ) ) { 210 return DAY; 211 } else if ( "Arcsecond".equalsIgnoreCase( t ) || matchEPSGString( unit, "uom", "9104" ) ) { 212 return ARC_SEC; 213 } 214 215 } 216 return null; 217 } 218 219 /** 220 * Check if amount of the specified unit can be converted into amount of this unit. 221 * 222 * @param other 223 * @return true if this unit can be converted into the other unit 224 */ 225 public boolean canConvert( final Unit other ) { 226 return ( baseType == other.baseType ) || ( baseType != null && baseType.equals( other.baseType ) ); 227 } 228 229 /** 230 * Convert a value in this unit to the given unit if possible. 231 * 232 * @param value 233 * to be converted 234 * @param targetUnit 235 * to convert to 236 * @return the converted value or the same value if this unit equals given unit. 237 * @throws IllegalArgumentException 238 * if no conversion can be applied. 239 */ 240 public final double convert( final double value, final Unit targetUnit ) { 241 if ( this.equals( targetUnit ) ) { 242 return value; 243 } 244 if ( canConvert( targetUnit ) ) { 245 return ( value * scale ) / targetUnit.scale; 246 } 247 throw new IllegalArgumentException( "Can't convert from \"" + this + "\" to \"" + targetUnit + "\"." ); 248 } 249 250 /** 251 * Convert a value in this unit to the base unit, e.g. degree->radians 252 * 253 * @param value 254 * to be converted 255 * @return the converted value or the same value if this unit is a base unit. 256 */ 257 public final double toBaseUnits( final double value ) { 258 if ( isBaseType() ) { 259 return value; 260 } 261 return value * scale; 262 } 263 264 /** 265 * @return the symbol of this unit. 266 */ 267 @Override 268 public String toString() { 269 return symbol; 270 } 271 272 /** 273 * Compare this unit symbol with the specified object for equality. Only symbols are compared; other parameters are 274 * ignored. 275 */ 276 @Override 277 public boolean equals( final Object object ) { 278 if ( object != null && object instanceof Unit ) { 279 final Unit that = (Unit) object; 280 return symbol.equals( that.symbol ) && ( Math.abs( this.scale - that.scale ) < 1E-10 ); 281 } 282 return false; 283 } 284 285 /** 286 * Implementation as proposed by Joshua Block in Effective Java (Addison-Wesley 2001), which supplies an even 287 * distribution and is relatively fast. It is created from field <b>f</b> as follows: 288 * <ul> 289 * <li>boolean -- code = (f ? 0 : 1)</li> 290 * <li>byte, char, short, int -- code = (int)f</li> 291 * <li>long -- code = (int)(f ^ (f >>>32))</li> 292 * <li>float -- code = Float.floatToIntBits(f);</li> 293 * <li>double -- long l = Double.doubleToLongBits(f); code = (int)(l ^ (l >>> 32))</li> 294 * <li>all Objects, (where equals( ) calls equals( ) for this field) -- code = f.hashCode( )</li> 295 * <li>Array -- Apply above rules to each element</li> 296 * </ul> 297 * <p> 298 * Combining the hash code(s) computed above: result = 37 * result + code; 299 * </p> 300 * 301 * @return (int) ( result >>> 32 ) ^ (int) result; 302 * 303 * @see java.lang.Object#hashCode() 304 */ 305 @Override 306 public int hashCode() { 307 // the 2nd millionth prime, :-) 308 long code = 32452843; 309 code = code * 37 + symbol.hashCode(); 310 long ll = Double.doubleToLongBits( scale ); 311 code = code * 37 + (int) ( ll ^ ( ll >>> 32 ) ); 312 return (int) ( code >>> 32 ) ^ (int) code; 313 } 314 315 /** 316 * @return the scale to convert to the base unit. 317 */ 318 public final double getScale() { 319 return scale; 320 } 321 322 /** 323 * @return true if this is a base type 324 */ 325 public final boolean isBaseType() { 326 return this.equals( this.baseType ); 327 } 328 329 /** 330 * 331 * @return symbol (short string) for a Unit 332 */ 333 public String getSymbol() { 334 return this.symbol; 335 } 336 }