001/* 002 * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences. 003 * Copyright (C) 2006 - JScience (http://jscience.org/) 004 * All rights reserved. 005 * 006 * Permission to use, copy, modify, and distribute this software is 007 * freely granted, provided that this notice is preserved. 008 */ 009package javax.measure.unit; 010 011import java.io.Serializable; 012 013import javax.measure.converter.RationalConverter; 014import javax.measure.converter.UnitConverter; 015import javax.measure.quantity.Dimensionless; 016 017/** 018 * <p> This class represents the dimension of an unit. Two units <code>u1</code> 019 * and <code>u2</code> are {@link Unit#isCompatible compatible} if and 020 * only if <code>(u1.getDimension().equals(u2.getDimension())))</code> 021 * </p> 022 * 023 * <p> Instances of this class are immutable.</p> 024 * 025 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> 026 * @version 3.1, April 22, 2006 027 * @see <a href="http://en.wikipedia.org/wiki/Dimensional_analysis"> 028 * Wikipedia: Dimensional Analysis</a> 029 */ 030public final class Dimension implements Serializable { 031 032 /** 033 * Holds the current physical model. 034 */ 035 private static Model CurrentModel = Model.STANDARD; 036 037 /** 038 * Holds dimensionless. 039 */ 040 public static final Dimension NONE = new Dimension(Unit.ONE); 041 042 /** 043 * Holds length dimension (L). 044 */ 045 public static final Dimension LENGTH = new Dimension('L'); 046 047 /** 048 * Holds mass dimension (M). 049 */ 050 public static final Dimension MASS = new Dimension('M'); 051 052 /** 053 * Holds time dimension (T). 054 */ 055 public static final Dimension TIME = new Dimension('T'); 056 057 /** 058 * Holds electric current dimension (I). 059 */ 060 public static final Dimension ELECTRIC_CURRENT = new Dimension('I'); 061 062 /** 063 * Holds temperature dimension (θ). 064 */ 065 public static final Dimension TEMPERATURE = new Dimension('θ'); 066 067 /** 068 * Holds amount of substance dimension (N). 069 */ 070 public static final Dimension AMOUNT_OF_SUBSTANCE = new Dimension('N'); 071 072 /** 073 * Holds the pseudo unit associated to this dimension. 074 */ 075 private final Unit<?> _pseudoUnit; 076 077 /** 078 * Creates a new dimension associated to the specified symbol. 079 * 080 * @param symbol the associated symbol. 081 */ 082 public Dimension(char symbol) { 083 _pseudoUnit = new BaseUnit<Dimensionless>("[" + symbol + "]"); 084 } 085 086 /** 087 * Creates a dimension having the specified pseudo-unit 088 * (base unit or product of base unit). 089 * 090 * @param pseudoUnit the pseudo-unit identifying this dimension. 091 */ 092 private Dimension(Unit<?> pseudoUnit) { 093 _pseudoUnit = pseudoUnit; 094 } 095 096 /** 097 * Returns the product of this dimension with the one specified. 098 * 099 * @param that the dimension multiplicand. 100 * @return <code>this * that</code> 101 */ 102 public final Dimension times(Dimension that) { 103 return new Dimension(this._pseudoUnit.times(that._pseudoUnit)); 104 } 105 106 /** 107 * Returns the quotient of this dimension with the one specified. 108 * 109 * @param that the dimension divisor. 110 * @return <code>this / that</code> 111 */ 112 public final Dimension divide(Dimension that) { 113 return new Dimension(this._pseudoUnit.divide(that._pseudoUnit)); 114 } 115 116 /** 117 * Returns this dimension raised to an exponent. 118 * 119 * @param n the exponent. 120 * @return the result of raising this dimension to the exponent. 121 */ 122 public final Dimension pow(int n) { 123 return new Dimension(this._pseudoUnit.pow(n)); 124 } 125 126 /** 127 * Returns the given root of this dimension. 128 * 129 * @param n the root's order. 130 * @return the result of taking the given root of this dimension. 131 * @throws ArithmeticException if <code>n == 0</code>. 132 */ 133 public final Dimension root(int n) { 134 return new Dimension(this._pseudoUnit.root(n)); 135 } 136 137 /** 138 * Returns the representation of this dimension. 139 * 140 * @return the representation of this dimension. 141 */ 142 public String toString() { 143 return _pseudoUnit.toString(); 144 } 145 146 /** 147 * Indicates if the specified dimension is equals to the one specified. 148 * 149 * @param that the object to compare to. 150 * @return <code>true</code> if this dimension is equals to that dimension; 151 * <code>false</code> otherwise. 152 */ 153 public boolean equals(Object that) { 154 if (this == that) 155 return true; 156 return (that instanceof Dimension) 157 && _pseudoUnit.equals(((Dimension) that)._pseudoUnit); 158 } 159 160 /** 161 * Returns the hash code for this dimension. 162 * 163 * @return this dimension hashcode value. 164 */ 165 public int hashCode() { 166 return _pseudoUnit.hashCode(); 167 } 168 169 /** 170 * Sets the model used to determinate the units dimensions. 171 * 172 * @param model the new model to be used when calculating unit dimensions. 173 */ 174 public static void setModel(Model model) { 175 Dimension.CurrentModel = model; 176 } 177 178 /** 179 * Returns the model used to determinate the units dimensions 180 * (default {@link Model#STANDARD STANDARD}). 181 * 182 * @return the model used when calculating unit dimensions. 183 */ 184 public static Model getModel() { 185 return Dimension.CurrentModel; 186 } 187 188 /** 189 * This interface represents the mapping between {@link BaseUnit base units} 190 * and {@link Dimension dimensions}. Custom models may allow 191 * conversions not possible using the {@link #STANDARD standard} model. 192 * For example:[code] 193 * public static void main(String[] args) { 194 * Dimension.Model relativistic = new Dimension.Model() { 195 * RationalConverter meterToSecond = new RationalConverter(1, 299792458); // 1/c 196 * 197 * public Dimension getDimension(BaseUnit unit) { 198 * if (unit.equals(SI.METER)) return Dimension.TIME; 199 * return Dimension.Model.STANDARD.getDimension(unit); 200 * } 201 * 202 * public UnitConverter getTransform(BaseUnit unit) { 203 * if (unit.equals(SI.METER)) return meterToSecond; 204 * return Dimension.Model.STANDARD.getTransform(unit); 205 * }}; 206 * Dimension.setModel(relativistic); 207 * 208 * // Converts 1.0 GeV (energy) to kg (mass). 209 * System.out.println(Unit.valueOf("GeV").getConverterTo(KILOGRAM).convert(1.0)); 210 * } 211 * 212 * > 1.7826617302520883E-27[/code] 213 */ 214 public interface Model { 215 216 /** 217 * Holds the standard model (default). 218 */ 219 public Model STANDARD = new Model() { 220 221 public Dimension getDimension(BaseUnit<?> unit) { 222 if (unit.equals(SI.METRE)) return Dimension.LENGTH; 223 if (unit.equals(SI.KILOGRAM)) return Dimension.MASS; 224 if (unit.equals(SI.KELVIN)) return Dimension.TEMPERATURE; 225 if (unit.equals(SI.SECOND)) return Dimension.TIME; 226 if (unit.equals(SI.AMPERE)) return Dimension.ELECTRIC_CURRENT; 227 if (unit.equals(SI.MOLE)) return Dimension.AMOUNT_OF_SUBSTANCE; 228 if (unit.equals(SI.CANDELA)) return SI.WATT.getDimension(); 229 return new Dimension(new BaseUnit<Dimensionless>("[" + unit.getSymbol() + "]")); 230 } 231 232 public UnitConverter getTransform(BaseUnit<?> unit) { 233 if (unit.equals(SI.CANDELA)) return new RationalConverter(1, 683); 234 return UnitConverter.IDENTITY; 235 } 236 }; 237 238 /** 239 * Returns the dimension of the specified base unit (a dimension 240 * particular to the base unit if the base unit is not recognized). 241 * 242 * @param unit the base unit for which the dimension is returned. 243 * @return the dimension of the specified unit. 244 */ 245 Dimension getDimension(BaseUnit<?> unit); 246 247 /** 248 * Returns the normalization transform of the specified base unit 249 * ({@link UnitConverter#IDENTITY IDENTITY} if the base unit is 250 * not recognized). 251 * 252 * @param unit the base unit for which the transform is returned. 253 * @return the normalization transform. 254 */ 255 UnitConverter getTransform(BaseUnit<?> unit); 256 } 257 258 private static final long serialVersionUID = 1L; 259}