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