KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > measure > units > Unit


1 /*
2  * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
3  * Copyright (C) 2006 - JScience (http://jscience.org/)
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software is
7  * freely granted, provided that this notice is preserved.
8  */

9 package javax.measure.units;
10
11 import java.io.Serializable JavaDoc;
12 import java.text.ParsePosition JavaDoc;
13 import java.util.HashMap JavaDoc;
14
15 import javax.measure.converters.AddConverter;
16 import javax.measure.converters.ConversionException;
17 import javax.measure.converters.MultiplyConverter;
18 import javax.measure.converters.RationalConverter;
19 import javax.measure.converters.UnitConverter;
20 import javax.measure.quantities.Dimensionless;
21 import javax.measure.quantities.Quantity;
22
23 /**
24  * <p> This class represents a determinate {@link javax.measure.quantities.Quantity
25  * quantity} (as of length, time, heat, or value) adopted as a standard
26  * of measurement.</p>
27  *
28  * <p> It is helpful to think of instances of this class as recording the
29  * history by which they are created. Thus, for example, the string
30  * "g/kg" (which is a dimensionless unit) would result from invoking
31  * the method toString() on a unit that was created by dividing a
32  * gram unit by a kilogram unit. Yet, "kg" divided by "kg" returns
33  * {@link #ONE} and not "kg/kg" due to automatic unit factorization.</p>
34  *
35  * <p> This class supports the multiplication of offsets units. The result is
36  * usually a unit not convertible to its {@link #getSystemUnit system unit}.
37  * Such units may appear in derivative quantities. For example °C/m is an
38  * unit of gradient, which is common in atmospheric and oceanographic
39  * research.</p>
40  *
41  * <p> Units raised at rational powers are also supported. For example
42  * the cubic root of "liter" is a unit compatible with meter.</p>
43  *
44  * <p> Instances of this class are immutable.</p>
45  *
46  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
47  * @author <a HREF="mailto:steve@unidata.ucar.edu">Steve Emmerson</a>
48  * @author Martin Desruisseaux
49  * @version 3.2, August 28, 2006
50  * @see <a HREF="http://en.wikipedia.org/wiki/Units_of_measurement">
51  * Wikipedia: Units of measurement</a>
52  */

53 public abstract class Unit<Q extends Quantity> implements Serializable JavaDoc {
54
55     /**
56      * Holds the dimensionless unit <code>ONE</code>.
57      */

58     public static final Unit<Dimensionless> ONE = new ProductUnit<Dimensionless>();
59
60     /**
61      * Holds the unique symbols collection (base unit or alternate units).
62      */

63     static final HashMap JavaDoc<String JavaDoc, Unit> SYMBOL_TO_UNIT = new HashMap JavaDoc<String JavaDoc, Unit>();
64
65     /**
66      * Default constructor (applications should sub-class either
67      * {@link BaseUnit} or {@link DerivedUnit} but not {@link Unit}).
68      */

69     Unit() {
70     }
71
72     //////////////////////////////////////////////////////
73
// Contract methods (for sub-classes to implement). //
74
//////////////////////////////////////////////////////
75

76     /**
77      * Returns the {@link BaseUnit base unit}, {@link AlternateUnit alternate
78      * unit} or product of base units and alternate units this unit is derived
79      * from. The system unit identifies the "type" of
80      * {@link javax.measure.quantities.Quantity quantity} for which this unit is employed.
81      * For example:[code]
82      * boolean isAngularVelocity(Unit<?> u) {
83      * return u.getSystemUnit().equals(RADIAN.divide(SECOND));
84      * }
85      * assert(REVOLUTION.divide(MINUTE).isAngularVelocity());
86      * [/code]
87      *
88      * <p><i> Note: Having the same system unit is not sufficient to ensure
89      * that a converter exists between the two units
90      * (e.g. °C/m and K/m).</i></p>
91      * @return the system unit this unit is derived from.
92      */

93     public abstract Unit<? super Q> getSystemUnit();
94
95     /**
96      * Returns the converter from this unit to its system unit.
97      *
98      * @return <code>this.getConverterTo(this.getSystemUnit())</code>
99      */

100     public abstract UnitConverter toSystemUnit();
101
102     /**
103      * Returns the hash code for this unit.
104      *
105      * @return this unit hashcode value.
106      */

107     public abstract int hashCode();
108
109     /**
110      * Indicates if the specified unit can be considered equals to
111      * the one specified.
112      *
113      * @param that the object to compare to.
114      * @return <code>true</code> if this unit is considered equal to
115      * that unit; <code>false</code> otherwise.
116      */

117     public abstract boolean equals(Object JavaDoc that);
118
119     /**
120      * Indicates if this unit is compatible with the unit specified.
121      * Units don't need to be equals to be compatible. For example:[code]
122      * RADIAN.equals(ONE) == false
123      * RADIAN.isCompatible(ONE) == true
124      * [/code]
125      * @param that the other unit.
126      * @return <code>this.getDimension().equals(that.getDimension())</code>
127      * @see #getDimension()
128      */

129     public final boolean isCompatible(Unit that) {
130         return (this == that)
131                 || this.getSystemUnit().equals(that.getSystemUnit())
132                 || this.getDimension().equals(that.getDimension());
133     }
134
135     /**
136      * Sets this unit's parameterized type from the specified unit.
137      * For example:[code]
138      * Unit<Length> LIGHT_YEAR = NonSI.C.times(NonSI.YEAR).sameTypeAs(SI.METER);
139      * [/code]
140      * If this unit is not compatible with the one specified a conversion
141      * exception is raised.
142      *
143      * @param that the other compatible unit.
144      * @return this unit with the parameterized type of <code>that</code> unit.
145      * @throws ConversionException if <code>this.isCompatible(that)</code>
146      */

147     @SuppressWarnings JavaDoc("unchecked")
148     public final <T extends Quantity> Unit<T> sameTypeAs(Unit<T> that) {
149         if (!isCompatible(that)) throw new ConversionException(this + " and " +
150                 that + " are not compatible units");
151         return (Unit<T>)this;
152     }
153
154     /**
155      * Returns the dimension of this unit (depends upon the current
156      * dimensional {@link Dimension.Model model}).
157      *
158      * @return the dimension of this unit for the current model.
159      */

160     public final Dimension getDimension() {
161         Unit systemUnit = this.getSystemUnit();
162         if (systemUnit instanceof BaseUnit)
163             return Dimension.getModel().getDimension((BaseUnit) systemUnit);
164         if (systemUnit instanceof AlternateUnit)
165             return ((AlternateUnit) systemUnit).getParent().getDimension();
166         // Product of units.
167
ProductUnit productUnit = (ProductUnit) systemUnit;
168         Dimension dimension = Dimension.NONE;
169         for (int i = 0; i < productUnit.getUnitCount(); i++) {
170             Unit unit = productUnit.getUnit(i);
171             Dimension d = unit.getDimension().pow(productUnit.getUnitPow(i))
172                     .root(productUnit.getUnitRoot(i));
173             dimension = dimension.times(d);
174         }
175         return dimension;
176     }
177
178     /**
179      * Returns a converter of numeric values from this unit to another unit.
180      *
181      * @param that the unit to which to convert the numeric values.
182      * @return the converter from this unit to <code>that</code> unit.
183      * @throws ConversionException if the conveter cannot be constructed
184      * (e.g. <code>!this.isCompatible(that)</code>).
185      */

186     public final UnitConverter getConverterTo(Unit that)
187             throws ConversionException {
188         if (this.equals(that))
189             return UnitConverter.IDENTITY;
190         Unit thisSystemUnit = this.getSystemUnit();
191         Unit thatSystemUnit = that.getSystemUnit();
192         if (thisSystemUnit.equals(thatSystemUnit))
193             return that.toSystemUnit().inverse().concatenate(
194                     this.toSystemUnit());
195         // Use dimensional transforms.
196
if (!thisSystemUnit.getDimension()
197                 .equals(thatSystemUnit.getDimension()))
198             throw new ConversionException(this + " is not compatible with "
199                     + that);
200         // Transform between SystemUnit and BaseUnits is Identity.
201
UnitConverter thisTransform = this.toSystemUnit().concatenate(
202                 transformOf(this.getBaseUnits()));
203         UnitConverter thatTransform = that.toSystemUnit().concatenate(
204                 transformOf(that.getBaseUnits()));
205         return thatTransform.inverse().concatenate(thisTransform);
206     }
207
208     private Unit getBaseUnits() {
209         Unit systemUnit = this.getSystemUnit();
210         if (systemUnit instanceof BaseUnit) return systemUnit;
211         if (systemUnit instanceof AlternateUnit)
212             return ((AlternateUnit)systemUnit).getParent().getBaseUnits();
213         if (systemUnit instanceof ProductUnit) {
214             ProductUnit productUnit = (ProductUnit)systemUnit;
215             Unit baseUnits = ONE;
216             for (int i = 0; i < productUnit.getUnitCount(); i++) {
217                 Unit unit = productUnit.getUnit(i).getBaseUnits();
218                 unit = unit.pow(productUnit.getUnitPow(i));
219                 unit = unit.root(productUnit.getUnitRoot(i));
220                 baseUnits = baseUnits.times(unit);
221             }
222             return baseUnits;
223         } else {
224             throw new InternalError JavaDoc(
225                     "System Unit cannot be an instance of " + this.getClass());
226         }
227     }
228     private static UnitConverter transformOf(Unit baseUnits) {
229         if (baseUnits instanceof BaseUnit)
230             return Dimension.getModel().getTransform((BaseUnit) baseUnits);
231         // Product of units.
232
ProductUnit productUnit = (ProductUnit) baseUnits;
233         UnitConverter converter = UnitConverter.IDENTITY;
234         for (int i = 0; i < productUnit.getUnitCount(); i++) {
235             Unit unit = productUnit.getUnit(i);
236             UnitConverter cvtr = transformOf(unit);
237             if (!cvtr.isLinear())
238                 throw new ConversionException(baseUnits
239                         + " is non-linear, cannot convert");
240             if (productUnit.getUnitRoot(i) != 1)
241                 throw new ConversionException(productUnit
242                         + " holds a base unit with fractional exponent");
243             int pow = productUnit.getUnitPow(i);
244             if (pow < 0) { // Negative power.
245
pow = -pow;
246                 cvtr = cvtr.inverse();
247             }
248             for (int j = 0; j < pow; j++) {
249                 converter = converter.concatenate(cvtr);
250             }
251         }
252         return converter;
253     }
254
255     /**
256      * Returns the combination of this unit with the specified sub-unit.
257      * Compound units are typically used for formatting purpose.
258      * Examples of compound units:[code]
259      * HOUR_MINUTE = NonSI.HOUR.compound(NonSI.MINUTE);
260      * DEGREE_MINUTE_SECOND_ANGLE = NonSI.DEGREE_ANGLE.compound(
261      * NonSI.DEGREE_MINUTE).compound(NonSI.SECOND_ANGLE);
262      * [/code]
263      *
264      * @param subunit the sub-unit to combine with this unit.
265      * @return the corresponding compound unit.
266      */

267     public final CompoundUnit<Q> compound(Unit<Q> subunit) {
268         return new CompoundUnit<Q>(this, subunit);
269     }
270
271     /**
272      * Returns the unit derived from this unit using the specified converter.
273      * The converter does not need to be linear. For example:[code]
274      * Unit<Dimensionless> DECIBEL = Unit.ONE.transform(
275      * new LogConverter(10).inverse().concatenate(
276      * new RationalConverter(1, 10)));[/code]
277      *
278      * @param operation the converter from the transformed unit to this unit.
279      * @return the unit after the specified transformation.
280      */

281     public final Unit<Q> transform(UnitConverter operation) {
282         if (this instanceof TransformedUnit) {
283             TransformedUnit<Q> tf = (TransformedUnit<Q>) this;
284             Unit<Q> parent = tf.getParentUnit();
285             UnitConverter toParent = tf.toParentUnit().concatenate(operation);
286             if (toParent == UnitConverter.IDENTITY)
287                 return parent;
288             return new TransformedUnit<Q>(parent, toParent);
289         }
290         if (operation == UnitConverter.IDENTITY)
291             return this;
292         return new TransformedUnit<Q>(this, operation);
293     }
294
295     /**
296      * Returns the result of adding an offset to this unit. The returned unit
297      * is convertible with all units that are convertible with this unit.
298      *
299      * @param offset the offset added (expressed in this unit,
300      * e.g. <code>CELSIUS = KELVIN.plus(273.15)</code>).
301      * @return <code>this.transform(new AddConverter(offset))</code>
302      */

303     public final Unit<Q> plus(double offset) {
304         return transform(new AddConverter(offset));
305     }
306
307     /**
308      * Returns the result of multiplying this unit by an exact factor.
309      *
310      * @param factor the exact scale factor
311      * (e.g. <code>KILOMETER = METER.multiply(1000)</code>).
312      * @return <code>this.transform(new RationalConverter(factor, 1))</code>
313      */

314     public final Unit<Q> times(long factor) {
315         return transform(new RationalConverter(factor, 1));
316     }
317
318     /**
319      * Returns the result of multiplying this unit by a an approximate factor
320      *
321      * @param factor the approximate factor (e.g.
322      * <code>ELECTRON_MASS = KILOGRAM.times(9.10938188e-31)</code>).
323      * @return <code>this.transform(new MultiplyConverter(factor))</code>
324      */

325     public final Unit<Q> times(double factor) {
326         return transform(new MultiplyConverter(factor));
327     }
328
329     /**
330      * Returns the product of this unit with the one specified.
331      *
332      * @param that the unit multiplicand.
333      * @return <code>this * that</code>
334      */

335     public final Unit<? extends Quantity> times(Unit that) {
336         return ProductUnit.getProductInstance(this, that);
337     }
338
339     /**
340      * Returns the inverse of this unit.
341      *
342      * @return <code>1 / this</code>
343      */

344     public final Unit<? extends Quantity> inverse() {
345         return ProductUnit.getQuotientInstance(ONE, this);
346     }
347
348     /**
349      * Returns the result of dividing this unit by an exact divisor.
350      *
351      * @param divisor the exact divisor.
352      * (e.g. <code>QUART = GALLON_LIQUID_US.divide(4)</code>).
353      * @return <code>this.transform(new RationalConverter(1 , divisor))</code>
354      */

355     public final Unit<Q> divide(long divisor) {
356         return transform(new RationalConverter(1, divisor));
357     }
358
359     /**
360      * Returns the result of dividing this unit by an approximate divisor.
361      *
362      * @param divisor the approximate divisor.
363      * @return <code>this.transform(new MultiplyConverter(1.0 / divisor))</code>
364      */

365     public final Unit<Q> divide(double divisor) {
366         return transform(new MultiplyConverter(1.0 / divisor));
367     }
368
369     /**
370      * Returns the quotient of this unit with the one specified.
371      *
372      * @param that the unit divisor.
373      * @return <code>this / that</code>
374      */

375     public final Unit<? extends Quantity> divide(Unit that) {
376         return this.times(that.inverse());
377     }
378
379     /**
380      * Returns a unit equals to the given root of this unit.
381      *
382      * @param n the root's order.
383      * @return the result of taking the given root of this unit.
384      * @throws ArithmeticException if <code>n == 0</code>.
385      */

386     public final Unit<? extends Quantity> root(int n) {
387         if (n > 0) {
388             return ProductUnit.getRootInstance(this, n);
389         } else if (n == 0) {
390             throw new ArithmeticException JavaDoc("Root's order of zero");
391         } else { // n < 0
392
return ONE.divide(this.root(-n));
393         }
394     }
395
396     /**
397      * Returns a unit equals to this unit raised to an exponent.
398      *
399      * @param n the exponent.
400      * @return the result of raising this unit to the exponent.
401      */

402     public final Unit<? extends Quantity> pow(int n) {
403         if (n > 0) {
404             return this.times(this.pow(n - 1));
405         } else if (n == 0) {
406             return ONE;
407         } else { // n < 0
408
return ONE.divide(this.pow(-n));
409         }
410     }
411
412     /**
413      * Returns a unit instance that is defined from the specified
414      * character sequence using the {@link UnitFormat#getStandardInstance()
415      * standard unit format}.
416      * <p> Examples of valid entries (all for meters per second squared) are:
417      * <code><ul>
418      * <li>m*s-2</li>
419      * <li>m/s²</li>
420      * <li>m·s-²</li>
421      * <li>m*s**-2</li>
422      * <li>m^+1 s^-2</li>
423      * </ul></code></p>
424      *
425      * @param csq the character sequence to parse.
426      * @return <code>UnitFormat.getStandardInstance().parse(csq, new ParsePosition(0))</code>
427      * @throws IllegalArgumentException if the specified character sequence
428      * cannot be correctly parsed (e.g. symbol unknown).
429      */

430     public static Unit<? extends Quantity> valueOf(CharSequence JavaDoc csq) {
431         return UnitFormat.getStandardInstance()
432                 .parse(csq, new ParsePosition JavaDoc(0));
433     }
434
435     //////////////////////
436
// GENERAL CONTRACT //
437
//////////////////////
438

439     /**
440      * Returns the standard <code>String</code> representation of this unit.
441      *
442      * @return <code>UnitFormat.getStandardInstance().format(this)</code>
443      */

444     public final String JavaDoc toString() {
445         return UnitFormat.getStandardInstance().format(this);
446     }
447 }
Popular Tags