Project/build/packaging adjustments + version 1.3
[measurements/measurements.git] / src / net / mattmccutchen / measurements / Unit.java
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 }