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