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.quantity;
031
032import tec.units.ri.AbstractUnit;
033import tec.units.ri.unit.BaseUnit;
034import tec.units.ri.unit.Units;
035
036import javax.measure.Dimension;
037import javax.measure.Quantity;
038import javax.measure.Unit;
039
040import java.util.HashMap;
041import java.util.Map;
042import java.util.logging.Level;
043import java.util.logging.Logger;
044
045/**
046 * <p>
047 * This class represents a quantity dimension (dimension of a physical quantity).
048 * </p>
049 *
050 * <p>
051 * The dimension associated to any given quantity are given by the published {@link DimensionService} instances. For convenience, a static method
052 * {@link QuantityDimension#of(Class)} aggregating the results of all {@link DimensionService} instances is provided.<br>
053 * <br>
054 * <code>
055 * Dimension speedDimension = QuantityDimension.of(Speed.class);
056 * </code>
057 * </p>
058 *
059 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
060 * @author <a href="mailto:units@catmedia.us">Werner Keil</a>
061 * @version 1.0.2, $Date: 2016-10-18 $
062 * @since 1.0
063 */
064public final class QuantityDimension implements Dimension {
065  private static final Logger logger = Logger.getLogger(QuantityDimension.class.getName());
066
067  /**
068         * 
069         */
070  // private static final long serialVersionUID = 123289037718650030L;
071
072  /**
073   * Holds dimensionless.
074   */
075  public static final Dimension NONE = new QuantityDimension(AbstractUnit.ONE);
076
077  /**
078   * Holds length dimension (L).
079   */
080  public static final Dimension LENGTH = new QuantityDimension('L');
081
082  /**
083   * Holds mass dimension (M).
084   */
085  public static final Dimension MASS = new QuantityDimension('M');
086
087  /**
088   * Holds time dimension (T).
089   */
090  public static final Dimension TIME = new QuantityDimension('T');
091
092  /**
093   * Holds electric current dimension (I).
094   */
095  public static final Dimension ELECTRIC_CURRENT = new QuantityDimension('I');
096
097  /**
098   * Holds temperature dimension (?).
099   */
100  public static final Dimension TEMPERATURE = new QuantityDimension('\u0398');
101
102  /**
103   * Holds amount of substance dimension (N).
104   */
105  public static final Dimension AMOUNT_OF_SUBSTANCE = new QuantityDimension('N');
106
107  /**
108   * Holds luminous intensity dimension (J).
109   */
110  public static final Dimension LUMINOUS_INTENSITY = new QuantityDimension('J');
111
112  /**
113   * Holds the pseudo unit associated to this dimension.
114   */
115  private final Unit<?> pseudoUnit;
116
117  /**
118   * Returns the physical dimension having the specified symbol.
119   *
120   * @param symbol
121   *          the associated symbol.
122   */
123  @SuppressWarnings("rawtypes")
124  QuantityDimension(char symbol) {
125    pseudoUnit = new BaseUnit("[" + symbol + ']', NONE);
126  }
127
128  /**
129   * Returns the dimension for the specified symbol.
130   *
131   * @param sambol
132   *          the quantity symbol.
133   * @return the dimension for the given symbol.
134   * @since 1.0
135   * @deprecated Use parse() instead
136   */
137  public static QuantityDimension getInstance(char symbol) {
138    return new QuantityDimension(symbol);
139  }
140
141  /**
142   * Returns the dimension for the specified quantity type by aggregating the results of {@link DimensionService} or <code>null</code> if the
143   * specified quantity is unknown.
144   *
145   * @param quantityType
146   *          the quantity type.
147   * @return the dimension for the quantity type or <code>null</code>.
148   * @since 1.0
149   * @deprecated use of()
150   */
151  public static <Q extends Quantity<Q>> Dimension getInstance(Class<Q> quantityType) {
152    return of(quantityType);
153  }
154
155  /**
156   * Returns the dimension for the specified symbol.
157   *
158   * @param sambol
159   *          the quantity symbol.
160   * @return the dimension for the given symbol.
161   * @since 1.0.2
162   */
163  public static Dimension parse(char symbol) {
164    return new QuantityDimension(symbol);
165  }
166
167  /**
168   * Returns the dimension for the specified quantity type by aggregating the results of {@link DimensionService} or <code>null</code> if the
169   * specified quantity is unknown.
170   *
171   * @param quantityType
172   *          the quantity type.
173   * @return the dimension for the quantity type or <code>null</code>.
174   * @since 1.0.2
175   */
176  public static <Q extends Quantity<Q>> Dimension of(Class<Q> quantityType) {
177    // TODO: Track services and aggregate results (register custom
178    // types)
179    Unit<Q> siUnit = Units.getInstance().getUnit(quantityType);
180    if (siUnit == null)
181      logger.log(Level.FINER, "Quantity type: " + quantityType + " unknown"); // we're logging but probably FINER is
182    // enough?
183    return (siUnit != null) ? siUnit.getDimension() : null;
184  }
185
186  /**
187   * Constructor from pseudo-unit (not visible).
188   *
189   * @param pseudoUnit
190   *          the pseudo-unit.
191   */
192  private QuantityDimension(Unit<?> pseudoUnit) {
193    this.pseudoUnit = pseudoUnit;
194  }
195
196  /**
197   * Returns the product of this dimension with the one specified. If the specified dimension is not a physics dimension, then
198   * <code>that.multiply(this)</code> is returned.
199   *
200   * @param that
201   *          the dimension multiplicand.
202   * @return <code>this * that</code>
203   * @since 1.0
204   */
205  public Dimension multiply(Dimension that) {
206    return (that instanceof QuantityDimension) ? this.multiply((QuantityDimension) that) : this.multiply(that);
207  }
208
209  /**
210   * Returns the product of this dimension with the one specified.
211   *
212   * @param that
213   *          the dimension multiplicand.
214   * @return <code>this * that</code>
215   * @since 1.0
216   */
217  public QuantityDimension multiply(QuantityDimension that) {
218    return new QuantityDimension(this.pseudoUnit.multiply(that.pseudoUnit));
219  }
220
221  /**
222   * Returns the quotient of this dimension with the one specified.
223   *
224   * @param that
225   *          the dimension divisor.
226   * @return <code>this.multiply(that.pow(-1))</code>
227   * @since 1.0
228   */
229  public Dimension divide(Dimension that) {
230    return this.multiply(that.pow(-1));
231  }
232
233  /**
234   * Returns the quotient of this dimension with the one specified.
235   *
236   * @param that
237   *          the dimension divisor.
238   * @return <code>this.multiply(that.pow(-1))</code>
239   * @since 1.0
240   */
241  public QuantityDimension divide(QuantityDimension that) {
242    return this.multiply(that.pow(-1));
243  }
244
245  /**
246   * Returns this dimension raised to an exponent.
247   *
248   * @param n
249   *          the exponent.
250   * @return the result of raising this dimension to the exponent.
251   * @since 1.0
252   */
253  public final QuantityDimension pow(int n) {
254    return new QuantityDimension(this.pseudoUnit.pow(n));
255  }
256
257  /**
258   * Returns the given root of this dimension.
259   *
260   * @param n
261   *          the root's order.
262   * @return the result of taking the given root of this dimension.
263   * @throws ArithmeticException
264   *           if <code>n == 0</code>.
265   * @since 1.0
266   */
267  public final QuantityDimension root(int n) {
268    return new QuantityDimension(this.pseudoUnit.root(n));
269  }
270
271  /**
272   * Returns the fundamental (base) dimensions and their exponent whose product is this dimension or <code>null</code> if this dimension is a
273   * fundamental dimension.
274   *
275   * @return the mapping between the base dimensions and their exponent.
276   * @since 1.0
277   */
278  @SuppressWarnings("rawtypes")
279  public Map<? extends Dimension, Integer> getBaseDimensions() {
280    Map<? extends Unit, Integer> pseudoUnits = pseudoUnit.getBaseUnits();
281    if (pseudoUnits == null)
282      return null;
283    final Map<QuantityDimension, Integer> baseDimensions = new HashMap<QuantityDimension, Integer>();
284    for (Map.Entry<? extends Unit, Integer> entry : pseudoUnits.entrySet()) {
285      baseDimensions.put(new QuantityDimension(entry.getKey()), entry.getValue());
286    }
287    return baseDimensions;
288  }
289
290  @Override
291  public String toString() {
292    return pseudoUnit.toString();
293  }
294
295  @Override
296  public boolean equals(Object obj) {
297    if (this == obj) {
298      return true;
299    }
300    if (obj instanceof QuantityDimension) {
301      QuantityDimension other = (QuantityDimension) obj;
302      return (pseudoUnit == other.pseudoUnit) || (pseudoUnit != null && pseudoUnit.equals(other.pseudoUnit));
303    }
304    return false;
305  }
306
307  @Override
308  public int hashCode() {
309    return pseudoUnit == null ? 0 : pseudoUnit.hashCode();
310  }
311}