001/*
002 * Units of Measurement Reference Implementation
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.units.ri;
031
032import java.util.Map;
033
034import javax.measure.Dimension;
035import javax.measure.Quantity;
036import javax.measure.Unit;
037import javax.measure.IncommensurableException;
038import javax.measure.UnconvertibleException;
039import javax.measure.UnitConverter;
040import javax.measure.quantity.Dimensionless;
041
042import tec.units.ri.format.SimpleUnitFormat;
043import tec.units.ri.function.AddConverter;
044import tec.units.ri.function.MultiplyConverter;
045import tec.units.ri.function.RationalConverter;
046import tec.units.ri.quantity.QuantityDimension;
047import tec.units.ri.spi.DimensionalModel;
048import tec.units.ri.unit.AlternateUnit;
049import tec.units.ri.unit.AnnotatedUnit;
050import tec.units.ri.unit.ProductUnit;
051import tec.units.ri.unit.TransformedUnit;
052import tec.units.ri.unit.Units;
053
054/**
055 * <p>
056 * The class represents units founded on the seven SI base units for seven base quantities assumed to be mutually independent.
057 * </p>
058 *
059 * <p>
060 * For all physics units, units conversions are symmetrical: <code>u1.getConverterTo(u2).equals(u2.getConverterTo(u1).inverse())</code>. Non-physical
061 * units (e.g. currency units) for which conversion is not symmetrical should have their own separate class hierarchy and are considered distinct
062 * (e.g. financial units), although they can always be combined with physics units (e.g. "€/Kg", "$/h").
063 * </p>
064 *
065 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
066 * @author <a href="mailto:units@catmedia.us">Werner Keil</a>
067 * @version 1.0.4, June 7, 2017
068 * @since 1.0
069 */
070public abstract class AbstractUnit<Q extends Quantity<Q>> implements Unit<Q>, Comparable<Unit<Q>> {
071
072  /**
073   * 
074   */
075  // private static final long serialVersionUID = -4344589505537030204L;
076
077  /**
078   * Holds the dimensionless unit <code>ONE</code>.
079   * 
080   * @see <a href="https://en.wikipedia.org/wiki/Natural_units#Choosing_constants_to_normalize"> Wikipedia: Natural Units - Choosing constants to
081   *      normalize</a>
082   * @see <a href= "http://www.av8n.com/physics/dimensionless-units.htm">Units of Dimension One</a>
083   */
084  public static final Unit<Dimensionless> ONE = new ProductUnit<Dimensionless>();
085
086  /**
087   * Holds the name.
088   */
089  protected String name;
090
091  /**
092   * Holds the symbol.
093   */
094  private String symbol;
095
096  /**
097   * Default constructor.
098   */
099  protected AbstractUnit() {
100  }
101
102  /**
103   * Compares this unit to the specified unit. The default implementation compares the name and symbol of both this unit and the specified unit.
104   *
105   * @return a negative integer, zero, or a positive integer as this unit is less than, equal to, or greater than the specified unit.
106   */
107  public int compareTo(Unit<Q> that) {
108    if (name != null && getSymbol() != null) {
109      return name.compareTo(that.getName()) + getSymbol().compareTo(that.getSymbol());
110    } else if (name == null) {
111      if (getSymbol() != null && that.getSymbol() != null) {
112        return getSymbol().compareTo(that.getSymbol());
113      } else {
114        return -1;
115      }
116    } else if (getSymbol() == null) {
117      if (name != null) {
118        return name.compareTo(that.getName());
119      } else {
120        return -1;
121      }
122    } else {
123      return -1;
124    }
125  }
126
127  /**
128   * Indicates if this unit belongs to the set of coherent SI units (unscaled SI units).
129   * 
130   * The base and coherent derived units of the SI form a coherent set, designated the set of coherent SI units. The word coherent is used here in the
131   * following sense: when coherent units are used, equations between the numerical values of quantities take exactly the same form as the equations
132   * between the quantities themselves. Thus if only units from a coherent set are used, conversion factors between units are never required.
133   * 
134   * @return <code>equals(toSystemUnit())</code>
135   */
136  public boolean isSystemUnit() {
137    AbstractUnit<Q> si = this.toSystemUnit();
138    return (this == si) || this.equals(si);
139  }
140
141  /**
142   * Returns the unscaled standard (SI) unit from which this unit is derived.
143   * 
144   * The SI unit can be be used to identify a quantity given the unit. For example:
145   * <code> static boolean isAngularVelocity(AbstractUnit&lt;?&gt; unit) {
146   * return unit.toSystemUnit().equals(RADIAN.divide(SECOND)); }
147   * assert(REVOLUTION.divide(MINUTE).isAngularVelocity()); // Returns true.
148   * </code>
149   *
150   * @return the unscaled metric unit from which this unit is derived.
151   */
152  protected abstract AbstractUnit<Q> toSystemUnit();
153
154  /**
155   * Returns the converter from this unit to its unscaled {@link #toSystemUnit standard} unit.
156   *
157   * @return <code>getConverterTo(this.toSystemUnit())</code>
158   * @see #toSystemUnit
159   */
160  public abstract UnitConverter getSystemConverter();
161
162  /**
163   * Annotates the specified unit. Annotation does not change the unit semantic. Annotations are often written between curly braces behind units. For
164   * example: <code> Unit&lt;Volume&gt; PERCENT_VOL =
165   * Units.PERCENT.annotate("vol"); // "%{vol}" AbstractUnit&lt;Mass&gt; KG_TOTAL =
166   * Units.KILOGRAM.annotate("total"); // "kg{total}" AbstractUnit&lt;Dimensionless&gt;
167   * RED_BLOOD_CELLS = ONE.annotate("RBC"); // "{RBC}" </code>
168   *
169   * Note: Annotations of system units are not considered themselves as system units.
170   *
171   * @param annotation
172   *          the unit annotation.
173   * @return the annotated unit.
174   */
175  public AnnotatedUnit<Q> annotate(String annotation) {
176    return new AnnotatedUnit<Q>(this, annotation);
177  }
178
179  /**
180   * Returns the physics unit represented by the specified characters.
181   *
182   * Locale-sensitive unit parsing may be handled using the OSGi {@link javax.measure.spi.UnitFormatService} or for non-OSGi applications instances of
183   * {@link SimpleUnitFormat}.
184   *
185   * <p>
186   * Note: The standard format supports dimensionless units.<code> AbstractUnit&lt;Dimensionless&gt; PERCENT =
187   * AbstractUnit.parse("100").inverse().asType(Dimensionless.class); </code>
188   * </p>
189   *
190   * @param charSequence
191   *          the character sequence to parse.
192   * @return <code>SimpleUnitFormat.getInstance().parse(csq)</code>
193   * @throws ParserException
194   *           if the specified character sequence cannot be parsed correctly.
195   */
196  public static Unit<?> parse(CharSequence charSequence) {
197    return SimpleUnitFormat.getInstance().parse(charSequence);
198  }
199
200  /**
201   * Returns the standard {@link String} representation of this unit. The string produced for a given unit is always the same; it is not affected by
202   * the locale. It can be used as a canonical string representation for exchanging units, or as a key for a Map, Hashtable, etc.
203   *
204   * Locale-sensitive unit parsing should be handled using the OSGi {@link tec.units.ri.SimpleUnitFormat.service.UnitFormat} service (or
205   * {@link SimpleUnitFormat} for non-OSGi applications).
206   *
207   * @return <code>SimpleUnitFormat.getInstance().format(this)</code>
208   */
209  @Override
210  public String toString() {
211    return SimpleUnitFormat.getInstance().format(this);
212    /*
213     * final Appendable tmp = new StringBuilder(); try { return
214     * SimpleUnitFormat.getInstance().format(this, tmp).toString(); } catch
215     * (IOException ioException) { throw new Error(ioException); // Should
216     * never happen. } finally { // if (tmp!=null) tmp.clear(); }
217     */
218  }
219
220  // ///////////////////////////////////////////////////////
221  // Implements org.unitsofmeasurement.Unit<Q> interface //
222  // ///////////////////////////////////////////////////////
223
224  /**
225   * Returns the system unit (unscaled SI unit) from which this unit is derived. They can be be used to identify a quantity given the unit. For
226   * example:[code] static boolean isAngularVelocity(AbstractUnit&lt;?&gt; unit) { return unit.getSystemUnit().equals(RADIAN.divide(SECOND)); }
227   * assert(REVOLUTION.divide(MINUTE).isAngularVelocity()); // Returns true. [/code]
228   *
229   * @return the unscaled metric unit from which this unit is derived.
230   */
231  public final AbstractUnit<Q> getSystemUnit() {
232    return toSystemUnit();
233  }
234
235  /**
236   * Indicates if this unit is compatible with the unit specified. To be compatible both units must be physics units having the same fundamental
237   * dimension.
238   *
239   * @param that
240   *          the other unit.
241   * @return <code>true</code> if this unit and that unit have equals fundamental dimension according to the current physics model; <code>false</code>
242   *         otherwise.
243   */
244  public final boolean isCompatible(Unit<?> that) {
245    if ((this == that) || this.equals(that))
246      return true;
247    if (!(that instanceof AbstractUnit))
248      return false;
249    Dimension thisDimension = this.getDimension();
250    Dimension thatDimension = that.getDimension();
251    if (thisDimension.equals(thatDimension))
252      return true;
253    DimensionalModel model = DimensionalModel.current(); // Use
254    // dimensional
255    // analysis
256    // model.
257    return model.getFundamentalDimension(thisDimension).equals(model.getFundamentalDimension(thatDimension));
258  }
259
260  /**
261   * Casts this unit to a parameterized unit of specified nature or throw a ClassCastException if the dimension of the specified quantity and this
262   * unit's dimension do not match (regardless whether or not the dimensions are independent or not).
263   *
264   * @param type
265   *          the quantity class identifying the nature of the unit.
266   * @throws ClassCastException
267   *           if the dimension of this unit is different from the SI dimension of the specified type.
268   * @see Units#getUnit(Class)
269   */
270  @SuppressWarnings("unchecked")
271  public final <T extends Quantity<T>> Unit<T> asType(Class<T> type) {
272    Dimension typeDimension = QuantityDimension.of(type);
273    if ((typeDimension != null) && (!typeDimension.equals(this.getDimension())))
274      throw new ClassCastException("The unit: " + this + " is not compatible with quantities of type " + type);
275    return (Unit<T>) this;
276  }
277
278  public abstract Map<? extends Unit<?>, Integer> getBaseUnits();
279
280  public abstract Dimension getDimension();
281
282  protected void setName(String name) {
283    this.name = name;
284  }
285
286  public String getName() {
287    return name;
288  }
289
290  public String getSymbol() {
291    return symbol;
292  }
293
294  protected void setSymbol(String s) {
295    this.symbol = s;
296  }
297
298  public final UnitConverter getConverterTo(Unit<Q> that) throws UnconvertibleException {
299    if ((this == that) || this.equals(that))
300      return AbstractConverter.IDENTITY; // Shortcut.
301    Unit<Q> thisSystemUnit = this.getSystemUnit();
302    Unit<Q> thatSystemUnit = that.getSystemUnit();
303    if (!thisSystemUnit.equals(thatSystemUnit))
304      try {
305        return getConverterToAny(that);
306      } catch (IncommensurableException e) {
307        throw new UnconvertibleException(e);
308      }
309    UnitConverter thisToSI = this.getSystemConverter();
310    UnitConverter thatToSI = that.getConverterTo(thatSystemUnit);
311    return thatToSI.inverse().concatenate(thisToSI);
312  }
313
314  @SuppressWarnings("rawtypes")
315  public final UnitConverter getConverterToAny(Unit<?> that) throws IncommensurableException, UnconvertibleException {
316    if (!isCompatible(that))
317      throw new IncommensurableException(this + " is not compatible with " + that);
318    AbstractUnit thatAbstr = (AbstractUnit) that; // Since both units are
319    // compatible they must
320    // be both abstract
321    // units.
322    DimensionalModel model = DimensionalModel.current();
323    AbstractUnit thisSystemUnit = this.getSystemUnit();
324    UnitConverter thisToDimension = model.getDimensionalTransform(thisSystemUnit.getDimension()).concatenate(this.getSystemConverter());
325    AbstractUnit thatSystemUnit = thatAbstr.getSystemUnit();
326    UnitConverter thatToDimension = model.getDimensionalTransform(thatSystemUnit.getDimension()).concatenate(thatAbstr.getSystemConverter());
327    return thatToDimension.inverse().concatenate(thisToDimension);
328  }
329
330  @Override
331  public final Unit<Q> alternate(String symbol) {
332    return new AlternateUnit<Q>(this, symbol);
333  }
334
335  @Override
336  public final Unit<Q> transform(UnitConverter operation) {
337    Unit<Q> systemUnit = this.getSystemUnit();
338    UnitConverter cvtr;
339    if (this.isSystemUnit()) {
340      cvtr = this.getSystemConverter().concatenate(operation);
341    } else {
342      cvtr = operation;
343    }
344    if (cvtr.equals(AbstractConverter.IDENTITY)) {
345      return systemUnit;
346    } else {
347      return new TransformedUnit<>(null, this, systemUnit, cvtr);
348    }
349  }
350
351  @Override
352  public final Unit<Q> shift(double offset) {
353    if (offset == 0)
354      return this;
355    return transform(new AddConverter(offset));
356  }
357
358  @Override
359  public final Unit<Q> multiply(double factor) {
360    if (factor == 1)
361      return this;
362    if (isLongValue(factor))
363      return transform(new RationalConverter((long) factor, 1));
364    return transform(new MultiplyConverter(factor));
365  }
366
367  private static boolean isLongValue(double value) {
368    return !((value < Long.MIN_VALUE) || (value > Long.MAX_VALUE)) && Math.floor(value) == value;
369  }
370
371  /**
372   * Returns the product of this unit with the one specified.
373   *
374   * <p>
375   * Note: If the specified unit (that) is not a physical unit, then <code>that.multiply(this)</code> is returned.
376   * </p>
377   *
378   * @param that
379   *          the unit multiplicand.
380   * @return <code>this * that</code>
381   */
382  public final Unit<?> multiply(Unit<?> that) {
383    if (that instanceof AbstractUnit)
384      return multiply((AbstractUnit<?>) that);
385    return that.multiply(this); // Commutatif.
386  }
387
388  /**
389   * Returns the product of this physical unit with the one specified.
390   *
391   * @param that
392   *          the physical unit multiplicand.
393   * @return <code>this * that</code>
394   */
395  public final Unit<?> multiply(AbstractUnit<?> that) {
396    if (this.equals(ONE))
397      return that;
398    if (that.equals(ONE))
399      return this;
400    return ProductUnit.getProductInstance(this, that);
401  }
402
403  /**
404   * Returns the inverse of this physical unit.
405   *
406   * @return <code>1 / this</code>
407   */
408  public final Unit<?> inverse() {
409    if (this.equals(ONE))
410      return this;
411    return ProductUnit.getQuotientInstance(ONE, this);
412  }
413
414  /**
415   * Returns the result of dividing this unit by the specifified divisor. If the factor is an integer value, the division is exact. For example:
416   * 
417   * <pre>
418   * <code>
419   *    QUART = GALLON_LIQUID_US.divide(4); // Exact definition.
420   * </code>
421   * </pre>
422   * 
423   * @param divisor
424   *          the divisor value.
425   * @return this unit divided by the specified divisor.
426   */
427  public final Unit<Q> divide(double divisor) {
428    if (divisor == 1)
429      return this;
430    if (isLongValue(divisor))
431      return transform(new RationalConverter(1, (long) divisor));
432    return transform(new MultiplyConverter(1.0 / divisor));
433  }
434
435  /**
436   * Returns the quotient of this unit with the one specified.
437   *
438   * @param that
439   *          the unit divisor.
440   * @return <code>this.multiply(that.inverse())</code>
441   */
442  public final Unit<?> divide(Unit<?> that) {
443    return this.multiply(that.inverse());
444  }
445
446  /**
447   * Returns a unit equals to the given root of this unit.
448   *
449   * @param n
450   *          the root's order.
451   * @return the result of taking the given root of this unit.
452   * @throws ArithmeticException
453   *           if <code>n == 0</code> or if this operation would result in an unit with a fractional exponent.
454   */
455  public final Unit<?> root(int n) {
456    if (n > 0)
457      return ProductUnit.getRootInstance(this, n);
458    else if (n == 0)
459      throw new ArithmeticException("Root's order of zero");
460    else
461      // n < 0
462      return ONE.divide(this.root(-n));
463  }
464
465  /**
466   * Returns a unit equals to this unit raised to an exponent.
467   *
468   * @param n
469   *          the exponent.
470   * @return the result of raising this unit to the exponent.
471   */
472  public final Unit<?> pow(int n) {
473    if (n > 0)
474      return this.multiply(this.pow(n - 1));
475    else if (n == 0)
476      return ONE;
477    else
478      // n < 0
479      return ONE.divide(this.pow(-n));
480  }
481
482  // //////////////////////////////////////////////////////////////
483  // Ensures that sub-classes implements hashCode/equals method.
484  // //////////////////////////////////////////////////////////////
485
486  @Override
487  public abstract int hashCode();
488
489  @Override
490  public abstract boolean equals(Object that);
491}