| /* |
| * $Header: /cvshome/build/org.osgi.util.measurement/src/org/osgi/util/measurement/Unit.java,v 1.15 2006/06/16 16:31:34 hargrave Exp $ |
| * |
| * Copyright (c) OSGi Alliance (2002, 2006). All Rights Reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.osgi.util.measurement; |
| |
| import java.util.Hashtable; |
| |
| /** |
| * A unit system for measurements. |
| * |
| * This class contains definitions of the most common SI units. |
| * <p> |
| * |
| * <p> |
| * This class only support exponents for the base SI units in the range -64 to |
| * +63. Any operation which produces an exponent outside of this range will |
| * result in a <code>Unit</code> object with undefined exponents. |
| * |
| * @version $Revision: 1.15 $ |
| */ |
| /* |
| * This local class maintains the information about units. It can calculate new |
| * units when two values are multiplied, divided, added or subtracted. <p> The |
| * unit works with the 7 basic SI types + rad + up to 2^6 custom types. For each |
| * type, the unit keeps a bit mask with the exponents of the basic types. Eg. |
| * m/s is m = 1, s = -1. Multiplying one unit with another means that the bit |
| * masks are added, dividing means that the bit masks are subtracted. <p> This |
| * class can handle any reasonable combination of SI units. However, it will |
| * always try to coerce results back into the basic set. E.g. when you do V*A |
| * you should get W and not m2.kg/s3 . Only when the existing types do not match |
| * does the unit fallback to the expanded form. <p> This class uses offset |
| * arithmetic. This means that the exponents are stored in an long. The special |
| * field is used for units that should not be arithmetically divided or |
| * multiplied, like longitude and lattitude. These special units can however, be |
| * divided and multiplied by the basic 7 constants of the SI, e.g. deg/s. |
| */ |
| public class Unit { |
| private final static long UNITY = createType(0, 0, 0, 0, 0, 0, 0, |
| 0, 0); |
| private final static long ZERO = 0x40L; |
| private final static long MASK = 0x7fL; |
| private final static int m_SHIFT = 0; |
| private final static int s_SHIFT = 7; |
| private final static int kg_SHIFT = 14; |
| private final static int K_SHIFT = 21; |
| private final static int A_SHIFT = 28; |
| private final static int mol_SHIFT = 35; |
| private final static int cd_SHIFT = 42; |
| private final static int rad_SHIFT = 49; |
| private final static int x_SHIFT = 56; |
| private final static long x_MASK = MASK << x_SHIFT; |
| /** No Unit (Unity) */ |
| public final static Unit unity = new Unit("", UNITY); // Unity |
| /* SI Base Units */ |
| /** The length unit meter (m) */ |
| public final static Unit m = new Unit("m", createType(0, 0, 0, |
| 0, 0, 0, 0, 0, 1)); // Distance |
| // meter |
| /** The time unit second (s) */ |
| public final static Unit s = new Unit("s", createType(0, 0, 0, |
| 0, 0, 0, 0, 1, 0)); // Time |
| // Seconds |
| // s |
| /** The mass unit kilogram (kg) */ |
| public final static Unit kg = new Unit("kg", createType(0, 0, |
| 0, 0, 0, 0, 1, 0, 0)); // Mass |
| // kilogram |
| // kg |
| /** The temperature unit kelvin (K) */ |
| public final static Unit K = new Unit("K", createType(0, 0, 0, |
| 0, 0, 1, 0, 0, 0)); // Temperature |
| // kelvin |
| // K |
| /** The electric current unit ampere (A) */ |
| public final static Unit A = new Unit("A", createType(0, 0, 0, |
| 0, 1, 0, 0, 0, 0)); // Current |
| // ampere |
| // A |
| /** The amount of substance unit mole (mol) */ |
| public final static Unit mol = new Unit("mol", createType(0, 0, |
| 0, 1, 0, 0, 0, 0, 0)); // Substance |
| // mole |
| // mol |
| /** The luminous intensity unit candela (cd) */ |
| public final static Unit cd = new Unit("cd", createType(0, 0, |
| 1, 0, 0, 0, 0, 0, 0)); // Light |
| // candela |
| // cd |
| /* SI Derived Units */ |
| /** The speed unit meter per second (m/s) */ |
| public final static Unit m_s = new Unit("m/s", createType(0, 0, |
| 0, 0, 0, 0, 0, -1, 1)); // Speed |
| // m/s |
| /** The acceleration unit meter per second squared (m/s <sup>2 </sup>) */ |
| public final static Unit m_s2 = new Unit("m/s2", createType(0, 0, |
| 0, 0, 0, 0, 0, -2, 1)); // Acceleration |
| // m/s^2 |
| /** The area unit square meter(m <sup>2 </sup>) */ |
| public final static Unit m2 = new Unit("m2", createType(0, 0, |
| 0, 0, 0, 0, 0, 0, 2)); // Surface |
| // m^2 |
| /** The volume unit cubic meter (m <sup>3 </sup>) */ |
| public final static Unit m3 = new Unit("m3", createType(0, 0, |
| 0, 0, 0, 0, 0, 0, 3)); // Volume |
| // m^3 |
| /** |
| * The frequency unit hertz (Hz). |
| * <p> |
| * hertz is expressed in SI units as 1/s |
| */ |
| public final static Unit Hz = new Unit("Hz", createType(0, 0, |
| 0, 0, 0, 0, 0, -1, 0)); // Frequency |
| // 1/s |
| /** |
| * The force unit newton (N). |
| * <p> |
| * N is expressed in SI units as m·kg/s <sup>2 </sup> |
| */ |
| public final static Unit N = new Unit("N", createType(0, 0, 0, |
| 0, 0, 0, 1, -2, 1)); // Force |
| // newton |
| // (m*kg)/s^2 |
| /** |
| * The pressure unit pascal (Pa). |
| * <p> |
| * Pa is equal to N/m <sup>2 </sup> or is expressed in SI units as |
| * kg/m·s <sup>2 </sup> |
| */ |
| public final static Unit Pa = new Unit("Pa", createType(0, 0, |
| 0, 0, 0, 0, 1, -2, -1)); // Pressure |
| // pascal |
| // kg/(m*s^2) |
| /** |
| * The energy unit joule (J). |
| * <p> |
| * joule is equal to N·m or is expressed in SI units as m <sup>2 |
| * </sup>·kg/s <sup>2 |
| */ |
| public final static Unit J = new Unit("J", createType(0, 0, 0, |
| 0, 0, 0, 1, -2, 2)); // Energy |
| // joule |
| // (m^2*kg)/s^2 |
| /** |
| * The power unit watt (W). |
| * <p> |
| * watt is equal to J/s or is expressed in SI units as m <sup>2 |
| * </sup>·kg/s <sup>3 </sup> |
| */ |
| public final static Unit W = new Unit("W", createType(0, 0, 0, |
| 0, 0, 0, 1, -3, 2)); // Power |
| // watt |
| // (m^2*kg)/s^3 |
| /** |
| * The electric charge unit coulomb (C). |
| * <p> |
| * coulomb is expressed in SI units as s·A |
| */ |
| public final static Unit C = new Unit("C", createType(0, 0, 0, |
| 0, 1, 0, 0, 1, 0)); // Charge |
| // coulumb |
| // s*A |
| /** |
| * The electric potential difference unit volt (V). |
| * <p> |
| * volt is equal to W/A or is expressed in SI units as m <sup>2 |
| * </sup>·kg/s <sup>3 </sup>·A |
| */ |
| public final static Unit V = new Unit("V", createType(0, 0, 0, |
| 0, -1, 0, 1, -3, 2)); // El. |
| // Potent. |
| // volt |
| // (m^2*kg)/(s^3*A) |
| /** |
| * The capacitance unit farad (F). |
| * <p> |
| * farad is equal to C/V or is expressed in SI units as s <sup>4 |
| * </sup>·A <sup>2 </sup>/m <sup>2 </sup>·kg |
| */ |
| public final static Unit F = new Unit("F", createType(0, 0, 0, |
| 0, 2, 0, -1, 4, -2)); // Capacitance |
| // farad |
| // (s^4*A^2)/(m^2*kg) |
| /** |
| * The electric resistance unit ohm. |
| * <p> |
| * ohm is equal to V/A or is expressed in SI units as m <sup>2 |
| * </sup>·kg/s <sup>3 </sup>·A <sup>2 </sup> |
| */ |
| public final static Unit Ohm = new Unit("Ohm", createType(0, 0, |
| 0, 0, -2, 0, 1, -3, 2)); // Resistance |
| // ohm |
| // (m^2*kg)/(s^3*A^2) |
| /** |
| * The electric conductance unit siemens (S). |
| * <p> |
| * siemens is equal to A/V or is expressed in SI units as s <sup>3 |
| * </sup>·A <sup>2 </sup>/m <sup>2 </sup>·kg |
| */ |
| public final static Unit S = new Unit("S", createType(0, 0, 0, |
| 0, 2, 0, -1, 3, -2)); // Conductance |
| // siemens |
| // (s^3*A^2)/(m^2*kg) |
| /** |
| * The magnetic flux unit weber (Wb). |
| * <p> |
| * weber is equal to V·s or is expressed in SI units as m <sup>2 |
| * </sup>·kg/s <sup>2 </sup>·A |
| */ |
| public final static Unit Wb = new Unit("Wb", createType(0, 0, |
| 0, 0, -1, 0, 1, -2, 2)); // Magn. |
| // Flux |
| // weber |
| // (m^2*kg)/(s^2*A) |
| /** |
| * The magnetic flux density unit tesla (T). |
| * <p> |
| * tesla is equal to Wb/m <sup>2 </sup> or is expressed in SI units as kg/s |
| * <sup>2 </sup>·A |
| */ |
| public final static Unit T = new Unit("T", createType(0, 0, 0, |
| 0, -1, 0, 1, -2, 0)); // Magn. |
| // Flux |
| // Dens. |
| // tesla |
| // kg/(s^2*A) |
| /** |
| * The illuminance unit lux (lx). |
| * <p> |
| * lux is expressed in SI units as cd/m <sup>2 </sup> |
| */ |
| public final static Unit lx = new Unit("lx", createType(0, 0, |
| 1, 0, 0, 0, 0, 0, -2)); // Illuminace |
| // lux |
| // cd/m^2 |
| /** |
| * The absorbed dose unit gray (Gy). |
| * <p> |
| * Gy is equal to J/kg or is expressed in SI units as m <sup>2 </sup>/s |
| * <sup>2 </sup> |
| */ |
| public final static Unit Gy = new Unit("Gy", createType(0, 0, |
| 0, 0, 0, 0, 0, -2, 2)); // Absorbed |
| // dose |
| // gray |
| // m^2/s^2 |
| /** |
| * The catalytic activity unit katal (kat). |
| * <p> |
| * katal is expressed in SI units as mol/s |
| */ |
| public final static Unit kat = new Unit("kat", createType(0, 0, |
| 0, 1, 0, 0, 0, -1, 0)); // Catalytic |
| // Act. |
| // katal |
| // mol/s |
| /** The angle unit radians (rad) */ |
| public final static Unit rad = new Unit("rad", createType(0, 1, |
| 0, 0, 0, 0, 0, 0, 0)); // Angle |
| // radians |
| // rad |
| /** |
| * An array containing all units defined. The first seven items must be m, |
| * s, kg, K, A, mol, cd, rad in this order! |
| */ |
| private final static Unit[] allUnits = new Unit[] {m, s, kg, K, A, mol, |
| cd, rad, m_s, m_s2, m2, m3, Hz, N, Pa, J, W, C, V, F, Ohm, S, Wb, |
| T, lx, Gy, kat, unity }; |
| private static Hashtable base; |
| private String name; |
| private long type; |
| |
| /** |
| * Creates a new <code>Unit</code> instance. |
| * |
| * @param name the name of the <code>Unit</code> |
| * @param type the type of the <code>Unit</code> |
| */ |
| private Unit(String name, long type) { |
| this.name = name; |
| this.type = type; |
| //System.out.println( name + " " + Long.toHexString( type ) ); |
| } |
| |
| /** |
| * Create a type field from the base SI unit exponent values. |
| * |
| */ |
| private static long createType(int x, int rad, int cd, int mol, int A, |
| int K, int kg, int s, int m) { |
| return (((ZERO + m) & MASK) << m_SHIFT) |
| | (((ZERO + s) & MASK) << s_SHIFT) |
| | (((ZERO + kg) & MASK) << kg_SHIFT) |
| | (((ZERO + K) & MASK) << K_SHIFT) |
| | (((ZERO + A) & MASK) << A_SHIFT) |
| | (((ZERO + mol) & MASK) << mol_SHIFT) |
| | (((ZERO + cd) & MASK) << cd_SHIFT) |
| | (((ZERO + rad) & MASK) << rad_SHIFT) |
| | (((long) x) << x_SHIFT); |
| } |
| |
| /** |
| * Checks whether this <code>Unit</code> object is equal to the specified |
| * <code>Unit</code> object. The <code>Unit</code> objects are considered equal |
| * if their exponents are equal. |
| * |
| * @param obj the <code>Unit</code> object that should be checked for equality |
| * |
| * @return true if the specified <code>Unit</code> object is equal to this |
| * <code>Unit</code> object. |
| */ |
| public boolean equals(Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (!(obj instanceof Unit)) { |
| return false; |
| } |
| return ((Unit) obj).type == type; |
| } |
| |
| /** |
| * Returns the hash code for this object. |
| * |
| * @return This object's hash code. |
| */ |
| public int hashCode() { |
| return (int) ((type >>> 32) ^ type); |
| } |
| |
| /** |
| * Returns a new <code>Unit</code> that is the multiplication of this |
| * <code>Unit</code> and the <code>Unit</code> specified |
| * |
| * @param that the <code>Unit</code> that will be multiplied with this |
| * <code>Unit</code> |
| * |
| * @return a new <code>Unit</code> that is the multiplication of this |
| * <code>Unit</code> and the <code>Unit</code> specified |
| * |
| * @throws RuntimeException if both <code>Unit</code> s are special |
| * |
| * @see Unit#isSpecial |
| */ |
| Unit mul(Unit that) { |
| if (this.isSpecial() && that.isSpecial()) { |
| throw new ArithmeticException("Cannot multiply " + this + " with " |
| + that); |
| } |
| return find(this.type - UNITY + that.type); |
| } |
| |
| /** |
| * Returns a new <code>Unit</code> that is the division of this <code>Unit</code> |
| * and the <code>Unit</code> specified |
| * |
| * @param that the <code>Unit</code> that this <code>Unit</code> will be divided |
| * with |
| * @return a new <code>Unit</code> that is the division of this <code>Unit</code> |
| * and the <code>Unit</code> specified |
| * |
| * @throws RuntimeException if both <code>Unit</code> s are special |
| * |
| * @see Unit#isSpecial |
| */ |
| Unit div(Unit that) { |
| if (this.isSpecial() && that.isSpecial()) { |
| if (this.type == that.type) { |
| return Unit.unity; |
| } |
| throw new ArithmeticException("Cannot divide " + this + " by " |
| + that); |
| } |
| return find(this.type - that.type + UNITY); |
| } |
| |
| /** |
| * Returns a new <code>Unit</code> that is the addition of this <code>Unit</code> |
| * and the <code>Unit</code> specified. |
| * |
| * @param that the <code>Unit</code> that should be added to this |
| * <code>Unit</code> |
| * |
| * @return a new <code>Unit</code> that is the addition of this <code>Unit</code> |
| * and the <code>Unit</code> specified. |
| * |
| * @throws RuntimeException if the two <code>Unit</code> s are not the same |
| */ |
| Unit add(Unit that) { |
| if (!this.equals(that)) { |
| throw new ArithmeticException("Cannot add " + this + " to " + that); |
| } |
| return this; |
| } |
| |
| /** |
| * Returns a new <code>Unit</code> that is the subtraction between this |
| * <code>Unit</code> and the <code>Unit</code> specified. |
| * |
| * @param that the <code>Unit</code> that will be subtracted from this |
| * <code>Unit</code> |
| * @return a new <code>Unit</code> that is the subtraction between this |
| * <code>Unit</code> and the <code>Unit</code> specified. |
| * |
| * @throws RuntimeException if the <code>Unit</code> specified is not the same |
| * as this <code>Unit</code> |
| */ |
| Unit sub(Unit that) { |
| if (!this.equals(that)) { |
| throw new ArithmeticException("Cannot subtract " + that + " from " |
| + this); |
| } |
| return this; |
| } |
| |
| /** |
| * Finds a <code>Unit</code> based on a type. If the <code>Unit</code> is not |
| * found, it will be created and added to the list of all units under a null |
| * name. |
| * |
| * @param type the type of the <code>Unit</code> to find |
| * |
| * @return the <code>Unit</code> |
| */ |
| static Unit find(long type) { |
| if (base == null) { |
| synchronized (Unit.class) { |
| if (base == null) { |
| int size = allUnits.length; |
| base = new Hashtable(size << 1); |
| for (int i = 0; i < size; i++) { |
| base.put(allUnits[i], allUnits[i]); |
| } |
| } |
| } |
| } |
| Unit unit = new Unit(null, type); |
| Unit out = (Unit) base.get(unit); |
| if (out == null) { |
| base.put(unit, unit); |
| out = unit; |
| } |
| return out; |
| } |
| |
| /** |
| * Returns a <code>String</code> object representing the <code>Unit</code> |
| * |
| * @return A <code>String</code> object representing the <code>Unit</code> |
| */ |
| public String toString() { |
| if (name == null) { |
| int m = (int) (((type >> m_SHIFT) & MASK) - ZERO); |
| int s = (int) (((type >> s_SHIFT) & MASK) - ZERO); |
| int kg = (int) (((type >> kg_SHIFT) & MASK) - ZERO); |
| int K = (int) (((type >> K_SHIFT) & MASK) - ZERO); |
| int A = (int) (((type >> A_SHIFT) & MASK) - ZERO); |
| int mol = (int) (((type >> mol_SHIFT) & MASK) - ZERO); |
| int cd = (int) (((type >> cd_SHIFT) & MASK) - ZERO); |
| int rad = (int) (((type >> rad_SHIFT) & MASK) - ZERO); |
| StringBuffer numerator = new StringBuffer(); |
| StringBuffer denominator = new StringBuffer(); |
| addSIname(m, "m", numerator, denominator); |
| addSIname(s, "s", numerator, denominator); |
| addSIname(kg, "kg", numerator, denominator); |
| addSIname(K, "K", numerator, denominator); |
| addSIname(A, "A", numerator, denominator); |
| addSIname(mol, "mol", numerator, denominator); |
| addSIname(cd, "cd", numerator, denominator); |
| addSIname(rad, "rad", numerator, denominator); |
| if (denominator.length() > 0) { |
| if (numerator.length() == 0) { |
| numerator.append("1"); |
| } |
| numerator.append("/"); |
| numerator.append((Object) denominator); /* |
| * we use (Object) to |
| * avoid using new 1.4 |
| * method |
| * append(StringBuffer) |
| */ |
| } |
| name = numerator.toString(); |
| } |
| return name; |
| } |
| |
| private void addSIname(int si, String name, StringBuffer numerator, |
| StringBuffer denominator) { |
| if (si != 0) { |
| StringBuffer sb = (si > 0) ? numerator : denominator; |
| if (sb.length() > 0) { |
| sb.append("*"); |
| } |
| sb.append(name); |
| int power = Math.abs(si); |
| if (power > 1) { |
| sb.append("^"); |
| sb.append(power); |
| } |
| } |
| } |
| |
| /** |
| * Checks whether the unit has a special type, i.e. not a SI unit. |
| * |
| * @return true if the type is special, otherwise false. |
| */ |
| private boolean isSpecial() { |
| return (type & x_MASK) != 0; |
| } |
| } |