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