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