| 1 | package net.mattmccutchen.measurements; |
| 2 | |
| 3 | import java.util.*; |
| 4 | |
| 5 | public class Unit { |
| 6 | public static final Unit SECOND = new Unit("s" , 1.0, 1, 0, 0, 0, 0, 0); |
| 7 | public static final Unit METER = new Unit("m" , 1.0, 0, 1, 0, 0, 0, 0); |
| 8 | public static final Unit GRAM = new Unit("g" , 1.0, 0, 0, 1, 0, 0, 0); |
| 9 | public static final Unit COULOMB = new Unit("coul", 1.0, 0, 0, 0, 1, 0, 0); |
| 10 | public static final Unit KELVIN = new Unit("K" , 1.0, 0, 0, 0, 0, 1, 0); |
| 11 | public static final Unit MOLE = new Unit("mol" , 1.0, 0, 0, 0, 0, 0, 1); |
| 12 | |
| 13 | public static final Unit[] basicUnits = new Unit[] { |
| 14 | SECOND, METER, GRAM, COULOMB, KELVIN, MOLE, |
| 15 | }; // Don't mutate |
| 16 | |
| 17 | public static final Unit PERCENT = new Unit("%", 1e-2, 0, 0, 0, 0, 0, 0); |
| 18 | public static final Unit NEWTON = new Unit("N", 1e+3,-2, 1, 1, 0, 0, 0); |
| 19 | public static final Unit JOULE = new Unit("J", 1e+3,-2, 2, 1, 0, 0, 0); |
| 20 | public static final Unit WATT = new Unit("W", 1e+3,-3, 2, 1, 0, 0, 0); |
| 21 | public static final Unit VOLT = new Unit("V", 1e+3,-2, 2, 1,-1, 0, 0); |
| 22 | public static final Unit AMP = new Unit("A", 1.0 ,-1, 0, 0, 1, 0, 0); |
| 23 | public static final Unit LITER = new Unit("L", 1e-3, 0, 3, 0, 0, 0, 0); |
| 24 | |
| 25 | public static final Unit[] allUnits = new Unit[] { |
| 26 | SECOND, METER, GRAM, COULOMB, KELVIN, MOLE, |
| 27 | PERCENT, NEWTON, JOULE, WATT, VOLT, AMP, LITER, |
| 28 | }; // Don't mutate |
| 29 | |
| 30 | public final String symbol; |
| 31 | public final double factor; |
| 32 | public final int[] powers; // Don't mutate |
| 33 | |
| 34 | private Unit(String symbol, double factor, int... powers) { |
| 35 | this.symbol = symbol; |
| 36 | this.factor = factor; |
| 37 | this.powers = powers; |
| 38 | } |
| 39 | |
| 40 | private static final Map<String, Unit> unitsBySymbol; // Don't mutate |
| 41 | private static final Map<Character, Double> prefixes; // Don't mutate |
| 42 | |
| 43 | public static Unit lookupBySymbol(String symbol) { |
| 44 | Unit u = unitsBySymbol.get(symbol); |
| 45 | if (u != null) |
| 46 | return u; |
| 47 | char pfx = symbol.charAt(0); |
| 48 | symbol = symbol.substring(1); |
| 49 | u = unitsBySymbol.get(symbol); |
| 50 | Double mult1 = prefixes.get(pfx); |
| 51 | if (u != null && mult1 != null) |
| 52 | return new Unit(symbol, u.factor * mult1, u.powers); |
| 53 | return null; |
| 54 | } |
| 55 | |
| 56 | static { |
| 57 | unitsBySymbol = new LinkedHashMap<String, Unit>(); |
| 58 | for (Unit u : allUnits) |
| 59 | unitsBySymbol.put(u.symbol, u); |
| 60 | |
| 61 | prefixes = new LinkedHashMap<Character, Double>(); |
| 62 | prefixes.put('k', 1e+03); |
| 63 | prefixes.put('M', 1e+06); |
| 64 | prefixes.put('G', 1e+09); |
| 65 | prefixes.put('T', 1e+12); |
| 66 | prefixes.put('P', 1e+15); |
| 67 | prefixes.put('E', 1e+18); |
| 68 | prefixes.put('Z', 1e+21); |
| 69 | prefixes.put('Y', 1e+24); |
| 70 | prefixes.put('c', 1e-02); |
| 71 | prefixes.put('m', 1e-03); |
| 72 | prefixes.put('u', 1e-06); // micro -> u: oh well |
| 73 | prefixes.put('n', 1e-09); |
| 74 | prefixes.put('p', 1e-12); |
| 75 | prefixes.put('f', 1e-15); |
| 76 | prefixes.put('a', 1e-18); |
| 77 | prefixes.put('z', 1e-21); |
| 78 | prefixes.put('y', 1e-24); |
| 79 | } |
| 80 | |
| 81 | public static Unit parseUnitString(String ustr) { |
| 82 | double fctr = 1; |
| 83 | int[] up = new int[Unit.basicUnits.length]; |
| 84 | StringTokenizer unitT = new StringTokenizer(ustr, " */", true); |
| 85 | boolean invert = false; |
| 86 | while (unitT.hasMoreTokens()) { |
| 87 | String tok = unitT.nextToken(); |
| 88 | if (tok.equals("/")) { |
| 89 | invert = !invert; |
| 90 | continue; |
| 91 | } else if (tok.equals(" ") || tok.equals("*")) |
| 92 | continue; |
| 93 | int caret = tok.indexOf('^'); |
| 94 | String symbol; |
| 95 | int power; |
| 96 | if (caret == -1) { |
| 97 | power = 1; |
| 98 | symbol = tok; |
| 99 | } else { |
| 100 | power = Integer.parseInt(tok.substring(caret + 1)); |
| 101 | symbol = tok.substring(0, caret); |
| 102 | } |
| 103 | Unit unit = Unit.lookupBySymbol(symbol); |
| 104 | if (unit == null) |
| 105 | throw new NullPointerException(); |
| 106 | if (invert) |
| 107 | power = -power; |
| 108 | fctr *= Math.pow(unit.factor, power); |
| 109 | for (int i = 0; i < Unit.basicUnits.length; i++) |
| 110 | up[i] += power * unit.powers[i]; |
| 111 | } |
| 112 | return new Unit(ustr, fctr, up); |
| 113 | } |
| 114 | } |