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