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