001/**
002 * Unit-API - Units of Measurement API for Java
003 * Copyright (c) 2014 Jean-Marie Dautelle, Werner Keil, V2COM
004 * All rights reserved.
005 *
006 * See LICENSE.txt for details.
007 */
008package javax.measure;
009
010import java.util.Map;
011
012/**
013 * Represents a determinate {@linkplain Quantity quantity} (as of
014 * length, time, heat, or value) adopted as a standard of measurement.
015 *
016 * <p>It is helpful to think of instances of this class as recording the history
017 * by which they are created. Thus, for example, the string {@code "g/kg"} (which
018 * is a dimensionless unit) would result from invoking the method {@link #toString()}
019 * on a unit that was created by dividing a gram unit by a kilogram unit.</p>
020 *
021 * <p>This interface supports the multiplication of offsets units. The result is
022 * usually a unit not convertible to its {@linkplain #getSystemUnit() system unit}.
023 * Such units may appear in derivative quantities. For example Celsius per meter is
024 * an unit of gradient, which is common in atmospheric and oceanographic research.</p>
025 *
026 * <p>Units raised at non-integral powers are not supported. For example,
027 * {@code LITRE.root(2)} raises an {@code ArithmeticException}, but
028 * {@code HECTARE.root(2)} returns {@code HECTOMETRE} (100 metres).</p>
029 *
030 * <p>Unit instances shall be immutable.</p>
031 *
032 * @param <Q> The type of the quantity measured by this unit.
033 *
034 * @author <a href="mailto:[email protected]">Jean-Marie Dautelle</a>
035 * @author <a href="mailto:[email protected]">Steve Emmerson</a>
036 * @author <a href="mailto:[email protected]">Martin Desruisseaux</a>
037 * @author <a href="mailto:[email protected]">Werner Keil</a>
038 * @version 0.16, December 8, 2014
039 *
040 * @see <a href="http://en.wikipedia.org/wiki/Units_of_measurement">Wikipedia: Units of measurement</a>
041 */
042public interface Unit<Q extends Quantity<Q>> {
043
044    /*******************/
045    /** Units Queries **/
046    /*******************/
047
048    /**
049     * Returns the symbol (if any) of this unit.
050     * This method returns {@code null} if this unit has no specific symbol associated with.
051     *
052     * @return this unit symbol, or {@code null} if this unit has not
053     *         specific symbol associated with (e.g. product of units).
054     *
055     * @see #toString()
056     * @see UnitFormat
057     */
058    String getSymbol();
059    
060    /**
061     * Returns the name (if any) of this unit.
062     * This method returns {@code null} if this unit has no specific name associated with.
063     *
064     * @return this unit name, or {@code null} if this unit has not
065     *         specific name associated with (e.g. product of units).
066     *
067     * @see #toString()
068     * @see UnitFormat
069     */
070    String getName();
071
072    /**
073     * Returns the dimension of this unit. Two units {@code u1} and {@code u2}
074     * are {@linkplain #isCompatible(Unit) compatible} if and only if
075     * {@code u1.getDimension().equals(u2.getDimension())}.
076     *
077     * @return the dimension of this unit.
078     *
079     * @see #isCompatible(Unit)
080     */
081    Dimension getDimension();
082
083    /**
084     * Returns the unscaled system unit from which this unit is derived.
085     * System units are either base units, {@linkplain #alternate(String)
086     * alternate} units or product of rational powers of system units.
087     *
088     * <p>Because the system unit is unique by quantity type, it can be
089     * be used to identify the quantity given the unit. For example:</p>
090     *
091     * [code]
092     *     static boolean isAngularSpeed(Unit<?> unit) {
093     *         return unit.getSystemUnit().equals(RADIAN.divide(SECOND));
094     *     }
095     *     assert isAngularSpeed(REVOLUTION.divide(MINUTE)); // Returns true.
096     * [/code]
097     *
098     * @return the system unit this unit is derived from,
099     *         or {@code this} if this unit is a system unit.
100     */
101    Unit<Q> getSystemUnit();
102
103    /**
104     * Returns the base units and their exponent whose product is this unit,
105     * or {@code null} if this unit is a base unit (not a product of existing units).
106     *
107     * @return the base units and their exponent making up this unit.
108     */
109    Map<? extends Unit<?>, Integer> getProductUnits();
110
111    /**
112     * Indicates if this unit is compatible with the unit specified.
113     * Units don't need to be equals to be compatible. For example
114     * (assuming {@code ONE} is a dimensionless unit):
115     *
116     * [code]
117     *     RADIAN.equals(ONE) == false
118     *     RADIAN.isCompatible(ONE) == true
119     * [/code]
120     *
121     * @param  that the other unit to compare for compatibility.
122     * @return {@code this.getDimension().equals(that.getDimension())}
123     *
124     * @see #getDimension()
125     */
126    boolean isCompatible(Unit<?> that);
127
128    /**
129     * Casts this unit to a parameterized unit of specified nature or throw a
130     * {@code ClassCastException} if the dimension of the specified quantity
131     * and this unit's dimension do not match. For example:
132     *
133     * [code]
134     *      Unit<Speed> C = METRE.times(299792458).divide(SECOND).asType(Speed.class);
135     * [/code]
136     *
137     * @param  <T> The type of the quantity measured by the unit.
138     * @param  type the quantity class identifying the nature of the unit.
139     * @return this unit parameterized with the specified type.
140     * @throws ClassCastException if the dimension of this unit is different
141     *         from the specified quantity dimension.
142     */
143    <T extends Quantity<T>> Unit<T> asType(Class<T> type) throws ClassCastException;
144
145    /**
146     * Returns a converter of numeric values from this unit to another unit of same type.
147     * This method performs the same work than {@link #getConverterToAny(Unit)} without
148     * raising checked exception.
149     *
150     * @param  that the unit of same type to which to convert the numeric values.
151     * @return the converter from this unit to {@code that} unit.
152     * @throws UnconvertibleException if a converter cannot be constructed.
153     *
154     * @see #getConverterToAny(Unit)
155     */
156    UnitConverter getConverterTo(Unit<Q> that) throws UnconvertibleException;
157
158    /**
159     * Returns a converter from this unit to the specified unit of type unknown.
160     * This method can be used when the quantity type of the specified unit
161     * is unknown at compile-time or when dimensional analysis allows for
162     * conversion between units of different type.
163     *
164     * <p>To convert to a unit having the same parameterized type,
165     * {@link #getConverterTo(Unit)} is preferred (no checked exception raised).</p>
166     *
167     * @param  that the unit to which to convert the numeric values.
168     * @return the converter from this unit to {@code that} unit.
169     * @throws IncommensurableException if this unit is not
170     *         {@linkplain #isCompatible(Unit) compatible} with {@code that}�unit.
171     * @throws UnconvertibleException if a converter cannot be constructed.
172     *
173     * @see #getConverterTo(Unit)
174     * @see #isCompatible(Unit)
175     */
176    UnitConverter getConverterToAny(Unit<?> that) throws IncommensurableException,
177            UnconvertibleException;
178
179    /**********************/
180    /** Units Operations **/
181    /**********************/
182
183    /**
184     * Returns a system unit equivalent to this unscaled standard unit but used
185     * in expressions to distinguish between quantities of a different nature
186     * but of the same dimensions.
187     *
188     * <p>Examples of alternate units:</p>
189     *
190     * [code]
191     *     Unit<Angle> RADIAN = ONE.alternate("rad").asType(Angle.class);
192     *     Unit<Force> NEWTON = METRE.times(KILOGRAM).divide(SECOND.pow(2)).alternate("N").asType(Force.class);
193     *     Unit<Pressure> PASCAL = NEWTON.divide(METRE.pow(2)).alternate("Pa").asType(Pressure.class);
194     * [/code]
195     *
196     * @param  symbol the new symbol for the alternate unit.
197     * @return the alternate unit.
198     * @throws UnsupportedOperationException if this unit is not an unscaled standard unit.
199     * @throws IllegalArgumentException if the specified symbol is already
200     *         associated to a different unit.
201     */
202    Unit<Q> alternate(String symbol);
203
204    /**
205     * Returns the result of setting the origin of the scale of measurement to the given value.
206     * The returned unit is convertible with all units that are convertible with this unit.
207     * For example the following code:
208     *
209     * [code]
210     *    CELSIUS = KELVIN.shift(273.15);
211     * [/code]
212     *
213     * creates a new unit where 0�C (the origin of the new unit) is equals to 273.15 K.
214     * Converting from the old unit to the new one is equivalent to <em>subtracting</em>
215     * the offset to the value in the old unit.
216     *
217     * @param  offset the offset added (expressed in this unit).
218     * @return this unit offset by the specified value.
219     */
220    Unit<Q> shift(double offset);
221
222    /**
223     * Returns the result of multiplying this unit by the specified factor.
224     * If the factor is an integer value, the multiplication is exact
225     * (recommended). For example:
226     *
227     * [code]
228     *    FOOT = METRE.multiply(3048).divide(10000); // Exact definition.
229     *    ELECTRON_MASS = KILOGRAM.multiply(9.10938188e-31); // Approximation.
230     * [/code]
231     *
232     * @param  multiplier the multiplier
233     * @return this unit scaled by the specified multiplier.
234     */
235    Unit<Q> multiply(double multiplier);
236
237    /**
238     * Returns the product of this unit with the one specified.
239     *
240     * @param  multiplier the unit multiplier.
241     * @return {@code this * multiplier}
242     */
243    Unit<?> multiply(Unit<?> multiplier);
244
245    /**
246     * Returns the inverse of this unit.
247     *
248     * @return {@code 1 / this}
249     */
250    Unit<?> inverse();
251
252    /**
253     * Returns the result of dividing this unit by an approximate divisor.
254     * If the factor is an integer value, the division is exact.
255     * For example:
256     *
257     * [code]
258     *    QUART = GALLON_LIQUID_US.divide(4); // Exact definition.
259     * [/code]
260     *
261     * @param  divisor the divisor value.
262     * @return this unit divided by the specified divisor.
263     */
264    Unit<Q> divide(double divisor);
265
266    /**
267     * Returns the quotient of this unit with the one specified.
268     *
269     * @param  divisor the unit divisor.
270     * @return {@code this / divisor}
271     */
272    Unit<?> divide(Unit<?> divisor);
273
274    /**
275     * Returns a unit equals to the given root of this unit.
276     *
277     * @param  n the root's order.
278     * @return the result of taking the given root of this unit.
279     * @throws ArithmeticException if {@code n == 0} or if this operation
280     *         would result in an unit with a fractional exponent.
281     */
282    Unit<?> root(int n);
283
284    /**
285     * Returns a unit equals to this unit raised to an exponent.
286     *
287     * @param  n the exponent.
288     * @return the result of raising this unit to the exponent.
289     */
290    Unit<?> pow(int n);
291
292    /**
293     * Returns a string representation of this unit. The string representation may
294     * be the unit {@linkplain #getSymbol() symbol}, or may be some representation
295     * of {@linkplain #getProductUnits() product units}, multiplication factor and
296     * offset if any. The string may be localized at implementation choice.
297     *
298     * @return the (eventually localized) string representation of this unit.
299     *
300     * @see #getSymbol()
301     */
302    @Override
303    String toString();
304
305        /**
306         * Returns the unit derived from this unit using the specified converter.
307         * The converter does not need to be linear. For example:<br>
308         * <code>
309         *     Unit<Dimensionless> DECIBEL = Unit.ONE.transform(
310         *         new LogConverter(10).inverse().concatenate(
311         *             new RationalConverter(1, 10)));
312         * </code>
313         *
314         * @param  operation the converter from the transformed unit to this unit.
315         * @return the unit after the specified transformation.
316         */
317        Unit<Q> transform(UnitConverter converter);
318}