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 &gt;&gt;&gt;32))</li>
250         * <li>float -- code = Float.floatToIntBits(f);</li>
251         * <li>double -- long l = Double.doubleToLongBits(f); code = (int)(l ^ (l &gt;&gt;&gt; 32))</li>
252         * <li>all Objects, (where equals(&nbsp;) calls equals(&nbsp;) for this field) -- code = f.hashCode(&nbsp;)</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    }