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