Initial commit of Matt's measurement add-in for OpenOffice.org Calc.
[measurements/measurements.git] / src / net / mattmccutchen / measurements / Unit.java
CommitLineData
3f5430db
MM
1package net.mattmccutchen.measurements;
2
3import java.util.*;
4
5public 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}