001/*
002 * Units of Measurement Implementation for Java SE
003 * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM.
004 *
005 * All rights reserved.
006 *
007 * Redistribution and use in source and binary forms, with or without modification,
008 * are permitted provided that the following conditions are met:
009 *
010 * 1. Redistributions of source code must retain the above copyright notice,
011 *    this list of conditions and the following disclaimer.
012 *
013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
014 *    and the following disclaimer in the documentation and/or other materials provided with the distribution.
015 *
016 * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products
017 *    derived from this software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package tec.uom.se;
031
032import java.math.BigDecimal;
033import java.math.MathContext;
034import java.util.Comparator;
035import java.util.Objects;
036
037import javax.measure.Quantity;
038import javax.measure.Unit;
039import javax.measure.UnitConverter;
040import javax.measure.quantity.Dimensionless;
041
042import tec.uom.lib.common.function.UnitSupplier;
043import tec.uom.lib.common.function.ValueSupplier;
044import tec.uom.se.format.QuantityFormat;
045import tec.uom.se.function.NaturalOrder;
046import tec.uom.se.quantity.Quantities;
047
048/**
049 * <p>
050 * This class represents the immutable result of a scalar measurement stated in a known unit.
051 * </p>
052 *
053 * <p>
054 * To avoid any lost of precision, known exact measure (e.g. physical constants) should not be created from <code>double</code> constants but from
055 * their decimal representation.<br/>
056 * <code>
057 *         public static final Quantity<Velocity> C = AbstractQuantity.parse("299792458 m/s").asType(Velocity.class);
058 *         // Speed of Light (exact).
059 *    </code>
060 * </p>
061 *
062 * <p>
063 * Measures can be converted to different units, the conversion precision is determined by the specified {@link MathContext}.<br/>
064 * <code>
065 *         Quantity<Number, Velocity> milesPerHour = C.to(MILES_PER_HOUR, MathContext.DECIMAL128); // Use BigDecimal implementation.
066 *         System.out.println(milesPerHour);
067 * 
068 *         > 670616629.3843951324266284896206156 [mi_i]/h
069 *     </code> If no precision is specified <code>double</code> precision is assumed.<code>
070 *         Quantity<Double, Velocity> milesPerHour = C.to(MILES_PER_HOUR); // Use double implementation (fast).
071 *         System.out.println(milesPerHour);
072 * 
073 *         > 670616629.3843951 [mi_i]/h
074 *     </code>
075 * </p>
076 *
077 * <p>
078 * Applications may sub-class {@link AbstractQuantity} for particular quantity types.<br/>
079 * <code>
080 *         // Quantity of type Mass based on <code>double</code> primitive types. public class MassAmount extends AbstractQuantity<Mass> { private
081 * final double _kilograms; // Internal SI representation. private Mass(double kilograms) { _kilograms = kilograms; } public static Mass of(double
082 * value, Unit<Mass> unit) { return new Mass(unit.getConverterTo(Units.KILOGRAM).convert(value)); } public Unit<Mass> getUnit() { return
083 * Units.KILOGRAM; } public Double getValue() { return _kilograms; } ... }
084 *
085 * // Complex numbers quantities. public class ComplexQuantity
086 * <Q extends Quantity>extends AbstractQuantity
087 * <Q>{ public Complex getValue() { ... } // Assuming Complex is a Number. ... }
088 *
089 * // Specializations of complex numbers quantities. public class Current extends ComplexQuantity<ElectricCurrent> {...} public class Tension extends
090 * ComplexQuantity<ElectricPotential> {...} </code>
091 * </p>
092 *
093 * <p>
094 * All instances of this class shall be immutable.
095 * </p>
096 *
097 * @author <a href="mailto:werner@uom.technology">Werner Keil</a>
098 * @version 1.0.1, October 10, 2016
099 * @since 1.0
100 */
101@SuppressWarnings("unchecked")
102public abstract class AbstractQuantity<Q extends Quantity<Q>> implements ComparableQuantity<Q>, UnitSupplier<Q>, ValueSupplier<Number> {
103
104  /**
105         * 
106         */
107  private static final long serialVersionUID = 293852425369811882L;
108
109  private final Unit<Q> unit;
110
111  /**
112   * Holds a dimensionless quantity of none (exact).
113   */
114  public static final Quantity<Dimensionless> NONE = Quantities.getQuantity(0, AbstractUnit.ONE);
115
116  /**
117   * Holds a dimensionless quantity of one (exact).
118   */
119  public static final Quantity<Dimensionless> ONE = Quantities.getQuantity(1, AbstractUnit.ONE);
120
121  /**
122   * constructor.
123   */
124  protected AbstractQuantity(Unit<Q> unit) {
125    this.unit = unit;
126  }
127
128  /**
129   * Returns the numeric value of the quantity.
130   *
131   * @return the quantity value.
132   */
133  @Override
134  public abstract Number getValue();
135
136  /**
137   * Returns the measurement unit.
138   *
139   * @return the measurement unit.
140   */
141  @Override
142  public Unit<Q> getUnit() {
143    return unit;
144  }
145
146  /**
147   * Convenient method equivalent to {@link #to(javax.measure.unit.Unit) to(this.getUnit().toSI())}.
148   *
149   * @return this measure or a new measure equivalent to this measure but stated in SI units.
150   * @throws ArithmeticException
151   *           if the result is inexact and the quotient has a non-terminating decimal expansion.
152   */
153  public Quantity<Q> toSI() {
154    return to(this.getUnit().getSystemUnit());
155  }
156
157  /**
158   * Returns this measure after conversion to specified unit. The default implementation returns <code>Measure.valueOf(doubleValue(unit), unit)</code>
159   * . If this measure is already stated in the specified unit, then this measure is returned and no conversion is performed.
160   *
161   * @param unit
162   *          the unit in which the returned measure is stated.
163   * @return this measure or a new measure equivalent to this measure but stated in the specified unit.
164   * @throws ArithmeticException
165   *           if the result is inexact and the quotient has a non-terminating decimal expansion.
166   */
167  @Override
168  public ComparableQuantity<Q> to(Unit<Q> unit) {
169    if (unit.equals(this.getUnit())) {
170      return this;
171    }
172    UnitConverter t = getUnit().getConverterTo(unit);
173    Number convertedValue = t.convert(getValue());
174    return Quantities.getQuantity(convertedValue, unit);
175  }
176
177  /**
178   * Returns this measure after conversion to specified unit. The default implementation returns
179   * <code>Measure.valueOf(decimalValue(unit, ctx), unit)</code>. If this measure is already stated in the specified unit, then this measure is
180   * returned and no conversion is performed.
181   *
182   * @param unit
183   *          the unit in which the returned measure is stated.
184   * @param ctx
185   *          the math context to use for conversion.
186   * @return this measure or a new measure equivalent to this measure but stated in the specified unit.
187   * @throws ArithmeticException
188   *           if the result is inexact but the rounding mode is <code>UNNECESSARY</code> or <code>mathContext.precision == 0</code> and the quotient
189   *           has a non-terminating decimal expansion.
190   */
191  public Quantity<Q> to(Unit<Q> unit, MathContext ctx) {
192    if (unit.equals(this.getUnit())) {
193      return this;
194    }
195    return Quantities.getQuantity(decimalValue(unit, ctx), unit);
196  }
197
198  @Override
199  public boolean isGreaterThan(Quantity<Q> that) {
200    return this.compareTo(that) > 0;
201  }
202
203  @Override
204  public boolean isGreaterThanOrEqualTo(Quantity<Q> that) {
205    return this.compareTo(that) >= 0;
206  }
207
208  @Override
209  public boolean isLessThan(Quantity<Q> that) {
210    return this.compareTo(that) < 0;
211  }
212
213  @Override
214  public boolean isLessThanOrEqualTo(Quantity<Q> that) {
215    return this.compareTo(that) <= 0;
216  }
217
218  @Override
219  public boolean isEquivalentTo(Quantity<Q> that) {
220    return this.compareTo(that) == 0;
221  }
222
223  /**
224   * Compares this measure to the specified Measurement quantity. The default implementation compares the {@link AbstractQuantity#doubleValue(Unit)}
225   * of both this measure and the specified Measurement stated in the same unit (this measure's {@link #getUnit() unit}).
226   *
227   * @return a negative integer, zero, or a positive integer as this measure is less than, equal to, or greater than the specified Measurement
228   *         quantity.
229   * @see {@link NaturalOrder}
230   */
231  @Override
232  public int compareTo(Quantity<Q> that) {
233    final Comparator<Quantity<Q>> comparator = new NaturalOrder<>();
234    return comparator.compare(this, that);
235  }
236
237  /**
238   * Compares this measure against the specified object for <b>strict</b> equality (same unit and same amount).
239   *
240   * <p>
241   * Similarly to the {@link BigDecimal#equals} method which consider 2.0 and 2.00 as different objects because of different internal scales,
242   * quantities such as <code>Quantities.getQuantity(3.0, KILOGRAM)</code> <code>Quantities.getQuantity(3, KILOGRAM)</code> and
243   * <code>Quantities.getQuantity("3 kg")</code> might not be considered equals because of possible differences in their implementations.
244   * </p>
245   *
246   * <p>
247   * To compare measures stated using different units or using different amount implementations the {@link #compareTo compareTo} or
248   * {@link #equals(javax.measure.Quantity, double, javax.measure.unit.Unit) equals(Quantity, epsilon, epsilonUnit)} methods should be used.
249   * </p>
250   *
251   * @param obj
252   *          the object to compare with.
253   * @return <code>this.getUnit.equals(obj.getUnit())
254   *         && this.getValue().equals(obj.getValue())</code>
255   */
256  @Override
257  public boolean equals(Object obj) {
258    if (this == obj) {
259      return true;
260    }
261    if (obj instanceof AbstractQuantity<?>) {
262      AbstractQuantity<?> that = (AbstractQuantity<?>) obj;
263      return Objects.equals(getUnit(), that.getUnit()) && Objects.equals(getValue(), that.getValue());
264    }
265    return false;
266  }
267
268  /**
269   * Compares this measure and the specified Measurement to the given accuracy. Measurements are considered approximately equals if their absolute
270   * differences when stated in the same specified unit is less than the specified epsilon.
271   *
272   * @param that
273   *          the Measurement to compare with.
274   * @param epsilon
275   *          the absolute error stated in epsilonUnit.
276   * @param epsilonUnit
277   *          the epsilon unit.
278   * @return <code>abs(this.doubleValue(epsilonUnit) - that.doubleValue(epsilonUnit)) &lt;= epsilon</code>
279   */
280  public boolean equals(AbstractQuantity<Q> that, double epsilon, Unit<Q> epsilonUnit) {
281    return Math.abs(this.doubleValue(epsilonUnit) - that.doubleValue(epsilonUnit)) <= epsilon;
282  }
283
284  /**
285   * Returns the hash code for this measure.
286   *
287   * @return the hash code value.
288   */
289  @Override
290  public int hashCode() {
291    return Objects.hash(getUnit(), getValue());
292  }
293
294  public abstract boolean isBig();
295
296  /**
297   * Returns the <code>String</code> representation of this measure. The string produced for a given measure is always the same; it is not affected by
298   * locale. This means that it can be used as a canonical string representation for exchanging measure, or as a key for a Hashtable, etc.
299   * Locale-sensitive measure formatting and parsing is handled by the {@link MeasurementFormat} class and its subclasses.
300   *
301   * @return <code>UnitFormat.getInternational().format(this)</code>
302   */
303  @Override
304  public String toString() {
305    return String.valueOf(getValue()) + " " + String.valueOf(getUnit());
306  }
307
308  public abstract BigDecimal decimalValue(Unit<Q> unit, MathContext ctx) throws ArithmeticException;
309
310  public abstract double doubleValue(Unit<Q> unit) throws ArithmeticException;
311
312  public final int intValue(Unit<Q> unit) throws ArithmeticException {
313    long longValue = longValue(unit);
314    if ((longValue < Integer.MIN_VALUE) || (longValue > Integer.MAX_VALUE)) {
315      throw new ArithmeticException("Cannot convert " + longValue + " to int (overflow)");
316    }
317    return (int) longValue;
318  }
319
320  protected long longValue(Unit<Q> unit) throws ArithmeticException {
321    double result = doubleValue(unit);
322    if ((result < Long.MIN_VALUE) || (result > Long.MAX_VALUE)) {
323      throw new ArithmeticException("Overflow (" + result + ")");
324    }
325    return (long) result;
326  }
327
328  protected final float floatValue(Unit<Q> unit) {
329    return (float) doubleValue(unit);
330  }
331
332  @Override
333  public <T extends Quantity<T>, E extends Quantity<E>> ComparableQuantity<E> divide(Quantity<T> that, Class<E> asTypeQuantity) {
334
335    return divide(Objects.requireNonNull(that)).asType(Objects.requireNonNull(asTypeQuantity));
336
337  }
338
339  @Override
340  public <T extends Quantity<T>, E extends Quantity<E>> ComparableQuantity<E> multiply(Quantity<T> that, Class<E> asTypeQuantity) {
341    return multiply(Objects.requireNonNull(that)).asType(Objects.requireNonNull(asTypeQuantity));
342  }
343
344  @Override
345  public <T extends Quantity<T>> ComparableQuantity<T> inverse(Class<T> quantityClass) {
346    return inverse().asType(quantityClass);
347  }
348
349  /**
350   * Casts this quantity to a parameterized quantity of specified nature or throw a <code>ClassCastException</code> if the dimension of the specified
351   * quantity and its unit's dimension do not match. For example:<br/>
352   * <code>
353   *     Quantity<Length> length = AbstractQuantity.parse("2 km").asType(Length.class);
354   * </code>
355   *
356   * @param type
357   *          the quantity class identifying the nature of the measure.
358   * @return this measure parameterized with the specified type.
359   * @throws ClassCastException
360   *           if the dimension of this unit is different from the specified quantity dimension.
361   * @throws UnsupportedOperationException
362   *           if the specified quantity class does not have a public static field named "UNIT" holding the SI unit for the quantity.
363   * @see Unit#asType(Class)
364   */
365  public final <T extends Quantity<T>> ComparableQuantity<T> asType(Class<T> type) throws ClassCastException {
366    this.getUnit().asType(type); // Raises ClassCastException if dimension
367    // mismatches.
368    return (ComparableQuantity<T>) this;
369  }
370
371  /**
372   * Returns the quantity of unknown type corresponding to the specified representation. This method can be used to parse dimensionless quantities.<br/>
373   * <code>
374   *     Quatity<Dimensionless> proportion = AbstractQuantity.parse("0.234").asType(Dimensionless.class);
375   * </code>
376   *
377   * <p>
378   * Note: This method handles only {@link SimpleUnitFormat#getStandard standard} unit format. Locale-sensitive quantity parsing is currently not
379   * supported.
380   * </p>
381   *
382   * @param csq
383   *          the decimal value and its unit (if any) separated by space(s).
384   * @return <code>QuantityFormat.getInstance().parse(csq)</code>
385   */
386  public static Quantity<?> parse(CharSequence csq) {
387    return QuantityFormat.getInstance().parse(csq);
388  }
389}