updates for 0.9.4
[debian/openrocket] / src / net / sf / openrocket / unit / UnitGroup.java
1 package net.sf.openrocket.unit;
2
3 import static net.sf.openrocket.util.Chars.*;
4 import static net.sf.openrocket.util.MathUtil.pow2;
5
6 import java.util.ArrayList;
7 import java.util.Collections;
8 import java.util.HashMap;
9 import java.util.Map;
10 import java.util.regex.Matcher;
11 import java.util.regex.Pattern;
12
13 import net.sf.openrocket.rocketcomponent.Configuration;
14 import net.sf.openrocket.rocketcomponent.Rocket;
15
16
17 /**
18  * A group of units (eg. length, mass etc.).  Contains a list of different units of a same
19  * quantity.
20  * 
21  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
22  */
23
24 public class UnitGroup {
25
26         public static final UnitGroup UNITS_NONE;
27         
28         public static final UnitGroup UNITS_MOTOR_DIMENSIONS;
29         public static final UnitGroup UNITS_LENGTH;
30         public static final UnitGroup UNITS_DISTANCE;
31         
32         public static final UnitGroup UNITS_AREA;
33         public static final UnitGroup UNITS_STABILITY;
34         public static final UnitGroup UNITS_VELOCITY;
35         public static final UnitGroup UNITS_ACCELERATION;
36         public static final UnitGroup UNITS_MASS;
37         public static final UnitGroup UNITS_ANGLE;
38         public static final UnitGroup UNITS_DENSITY_BULK;
39         public static final UnitGroup UNITS_DENSITY_SURFACE;
40         public static final UnitGroup UNITS_DENSITY_LINE;
41         public static final UnitGroup UNITS_FORCE;
42         public static final UnitGroup UNITS_IMPULSE;
43         
44         /** Time in the order of less than a second (time step etc). */
45         public static final UnitGroup UNITS_TIME_STEP;
46         
47         /** Time in the order of seconds (motor delay etc). */
48         public static final UnitGroup UNITS_SHORT_TIME;
49         
50         /** Time in the order of the flight time of a rocket. */
51         public static final UnitGroup UNITS_FLIGHT_TIME;
52         public static final UnitGroup UNITS_ROLL;
53         public static final UnitGroup UNITS_TEMPERATURE;
54         public static final UnitGroup UNITS_PRESSURE;
55         public static final UnitGroup UNITS_RELATIVE;
56         public static final UnitGroup UNITS_ROUGHNESS;
57         
58         public static final UnitGroup UNITS_COEFFICIENT;
59         
60 //      public static final UnitGroup UNITS_FREQUENCY;
61         
62         
63         public static final Map<String, UnitGroup> UNITS;
64         
65         
66         /*
67          * Note:  Units may not use HTML tags.
68          */
69         static {
70                 UNITS_NONE = new UnitGroup();
71                 UNITS_NONE.addUnit(Unit.NOUNIT2);
72                 
73                 UNITS_LENGTH = new UnitGroup();
74                 UNITS_LENGTH.addUnit(new GeneralUnit(0.001,"mm"));
75                 UNITS_LENGTH.addUnit(new GeneralUnit(0.01,"cm"));
76                 UNITS_LENGTH.addUnit(new GeneralUnit(1,"m"));
77                 UNITS_LENGTH.addUnit(new GeneralUnit(0.0254,"in"));
78                 UNITS_LENGTH.addUnit(new GeneralUnit(0.3048,"ft"));
79                 UNITS_LENGTH.setDefaultUnit(1);
80                 
81                 UNITS_MOTOR_DIMENSIONS = new UnitGroup();
82                 UNITS_MOTOR_DIMENSIONS.addUnit(new GeneralUnit(0.001,"mm"));
83                 UNITS_MOTOR_DIMENSIONS.addUnit(new GeneralUnit(0.01,"cm"));
84                 UNITS_MOTOR_DIMENSIONS.addUnit(new GeneralUnit(0.0254,"in"));
85                 UNITS_MOTOR_DIMENSIONS.setDefaultUnit(0);
86                 
87                 UNITS_DISTANCE = new UnitGroup();
88                 UNITS_DISTANCE.addUnit(new GeneralUnit(1,"m"));
89                 UNITS_DISTANCE.addUnit(new GeneralUnit(1000,"km"));
90                 UNITS_DISTANCE.addUnit(new GeneralUnit(0.3048,"ft"));
91                 UNITS_DISTANCE.addUnit(new GeneralUnit(0.9144,"yd"));
92                 UNITS_DISTANCE.addUnit(new GeneralUnit(1609.344,"mi"));
93                 
94                 UNITS_AREA = new UnitGroup();
95                 UNITS_AREA.addUnit(new GeneralUnit(pow2(0.001),"mm" + SQUARED));
96                 UNITS_AREA.addUnit(new GeneralUnit(pow2(0.01),"cm" + SQUARED));
97                 UNITS_AREA.addUnit(new GeneralUnit(1,"m" + SQUARED));
98                 UNITS_AREA.addUnit(new GeneralUnit(pow2(0.0254),"in" + SQUARED));
99                 UNITS_AREA.addUnit(new GeneralUnit(pow2(0.3048),"ft" + SQUARED));
100                 UNITS_AREA.setDefaultUnit(1);
101                 
102                 
103                 UNITS_STABILITY = new UnitGroup();
104                 UNITS_STABILITY.addUnit(new GeneralUnit(0.001,"mm"));
105                 UNITS_STABILITY.addUnit(new GeneralUnit(0.01,"cm"));
106                 UNITS_STABILITY.addUnit(new GeneralUnit(0.0254,"in"));
107                 UNITS_STABILITY.addUnit(new CaliberUnit((Rocket)null));
108                 UNITS_STABILITY.setDefaultUnit(3);
109                 
110                 UNITS_VELOCITY = new UnitGroup();
111                 UNITS_VELOCITY.addUnit(new GeneralUnit(1, "m/s"));
112                 UNITS_VELOCITY.addUnit(new GeneralUnit(1/3.6, "km/h"));
113                 UNITS_VELOCITY.addUnit(new GeneralUnit(0.3048, "ft/s"));
114                 UNITS_VELOCITY.addUnit(new GeneralUnit(0.44704, "mph"));
115                 
116                 UNITS_ACCELERATION = new UnitGroup();
117                 UNITS_ACCELERATION.addUnit(new GeneralUnit(1, "m/s" + SQUARED));
118                 UNITS_ACCELERATION.addUnit(new GeneralUnit(0.3048, "ft/s" + SQUARED));
119                 
120
121                 UNITS_MASS = new UnitGroup();
122                 UNITS_MASS.addUnit(new GeneralUnit(0.001,"g"));
123                 UNITS_MASS.addUnit(new GeneralUnit(1,"kg"));
124                 UNITS_MASS.addUnit(new GeneralUnit(0.0283495231,"oz"));
125                 UNITS_MASS.addUnit(new GeneralUnit(0.45359237,"lb"));
126                 
127                 UNITS_ANGLE = new UnitGroup();
128                 UNITS_ANGLE.addUnit(new DegreeUnit());
129                 UNITS_ANGLE.addUnit(new FixedPrecisionUnit("rad",0.01));
130                 
131                 UNITS_DENSITY_BULK = new UnitGroup();
132                 UNITS_DENSITY_BULK.addUnit(new GeneralUnit(1000,"g/cm" + CUBED));
133                 UNITS_DENSITY_BULK.addUnit(new GeneralUnit(1,"kg/m" + CUBED));
134                 UNITS_DENSITY_BULK.addUnit(new GeneralUnit(1729.99404,"oz/in" + CUBED));
135                 UNITS_DENSITY_BULK.addUnit(new GeneralUnit(16.0184634,"lb/ft" + CUBED));
136
137                 UNITS_DENSITY_SURFACE = new UnitGroup();
138                 UNITS_DENSITY_SURFACE.addUnit(new GeneralUnit(10,"g/cm" + SQUARED));
139                 UNITS_DENSITY_SURFACE.addUnit(new GeneralUnit(0.001,"g/m" + SQUARED));
140                 UNITS_DENSITY_SURFACE.addUnit(new GeneralUnit(1,"kg/m" + SQUARED));
141                 UNITS_DENSITY_SURFACE.addUnit(new GeneralUnit(43.9418487,"oz/in" + SQUARED));
142                 UNITS_DENSITY_SURFACE.addUnit(new GeneralUnit(0.305151727,"oz/ft" + SQUARED));
143                 UNITS_DENSITY_SURFACE.addUnit(new GeneralUnit(4.88242764,"lb/ft" + SQUARED));
144                 UNITS_DENSITY_SURFACE.setDefaultUnit(1);
145
146                 UNITS_DENSITY_LINE = new UnitGroup();
147                 UNITS_DENSITY_LINE.addUnit(new GeneralUnit(0.001,"g/m"));
148                 UNITS_DENSITY_LINE.addUnit(new GeneralUnit(1,"kg/m"));
149                 UNITS_DENSITY_LINE.addUnit(new GeneralUnit(0.0930102465,"oz/ft"));
150
151                 UNITS_FORCE = new UnitGroup();
152                 UNITS_FORCE.addUnit(new GeneralUnit(1,"N"));
153                 UNITS_FORCE.addUnit(new GeneralUnit(4.44822162,"lbf"));
154                 UNITS_FORCE.addUnit(new GeneralUnit(9.80665,"kgf"));
155
156                 UNITS_IMPULSE = new UnitGroup();
157                 UNITS_IMPULSE.addUnit(new GeneralUnit(1,"Ns"));
158                 UNITS_IMPULSE.addUnit(new GeneralUnit(4.44822162, "lbf"+DOT+"s"));
159
160                 UNITS_TIME_STEP = new UnitGroup();
161                 UNITS_TIME_STEP.addUnit(new FixedPrecisionUnit("ms", 1, 0.001));
162                 UNITS_TIME_STEP.addUnit(new FixedPrecisionUnit("s", 0.01));
163                 UNITS_TIME_STEP.setDefaultUnit(1);
164
165                 UNITS_SHORT_TIME = new UnitGroup();
166                 UNITS_SHORT_TIME.addUnit(new GeneralUnit(1,"s"));
167
168                 UNITS_FLIGHT_TIME = new UnitGroup();
169                 UNITS_FLIGHT_TIME.addUnit(new GeneralUnit(1,"s"));
170                 UNITS_FLIGHT_TIME.addUnit(new GeneralUnit(60,"min"));
171                 
172                 UNITS_ROLL = new UnitGroup();
173                 UNITS_ROLL.addUnit(new GeneralUnit(1, "rad/s"));
174                 UNITS_ROLL.addUnit(new GeneralUnit(2*Math.PI, "r/s"));
175                 UNITS_ROLL.addUnit(new GeneralUnit(2*Math.PI/60, "rpm"));
176                 UNITS_ROLL.setDefaultUnit(1);
177
178                 UNITS_TEMPERATURE = new UnitGroup();
179                 UNITS_TEMPERATURE.addUnit(new FixedPrecisionUnit("K", 1));
180                 UNITS_TEMPERATURE.addUnit(new TemperatureUnit(1, 273.15, DEGREE+"C"));
181                 UNITS_TEMPERATURE.addUnit(new TemperatureUnit(5.0/9.0, 459.67, DEGREE+"F"));
182                 UNITS_TEMPERATURE.setDefaultUnit(1);
183                 
184                 UNITS_PRESSURE = new UnitGroup();
185                 UNITS_PRESSURE.addUnit(new FixedPrecisionUnit("mbar", 1, 1.0e2));
186                 UNITS_PRESSURE.addUnit(new FixedPrecisionUnit("bar", 0.001, 1.0e5));
187                 UNITS_PRESSURE.addUnit(new FixedPrecisionUnit("atm", 0.001, 1.01325e5));
188                 UNITS_PRESSURE.addUnit(new GeneralUnit(101325.0/760.0, "mmHg"));
189                 UNITS_PRESSURE.addUnit(new GeneralUnit(3386.389, "inHg"));
190                 UNITS_PRESSURE.addUnit(new GeneralUnit(6894.75729, "psi"));
191                 UNITS_PRESSURE.addUnit(new GeneralUnit(1, "Pa"));
192
193                 UNITS_RELATIVE = new UnitGroup();
194                 UNITS_RELATIVE.addUnit(new FixedPrecisionUnit(""+ZWSP, 0.01, 1.0));
195                 UNITS_RELATIVE.addUnit(new FixedPrecisionUnit("%", 1, 0.01));
196                 UNITS_RELATIVE.addUnit(new FixedPrecisionUnit(""+PERMILLE, 1, 0.001));
197                 UNITS_RELATIVE.setDefaultUnit(1);
198
199                 
200                 UNITS_ROUGHNESS = new UnitGroup();
201                 UNITS_ROUGHNESS.addUnit(new GeneralUnit(0.000001, MICRO+"m"));
202                 UNITS_ROUGHNESS.addUnit(new GeneralUnit(0.0000254, "mil"));
203                 
204                 
205                 UNITS_COEFFICIENT = new UnitGroup();
206                 UNITS_COEFFICIENT.addUnit(new FixedPrecisionUnit(""+ZWSP, 0.01));  // zero-width space
207                 
208                 
209                 // This is not used by OpenRocket, and not extensively tested:
210 //              UNITS_FREQUENCY = new UnitGroup();
211 //              UNITS_FREQUENCY.addUnit(new GeneralUnit(1, "s"));
212 //              UNITS_FREQUENCY.addUnit(new GeneralUnit(0.001, "ms"));
213 //              UNITS_FREQUENCY.addUnit(new GeneralUnit(0.000001, MICRO + "s"));
214 //              UNITS_FREQUENCY.addUnit(new FrequencyUnit(1, "Hz"));
215 //              UNITS_FREQUENCY.addUnit(new FrequencyUnit(1000, "kHz"));
216 //              UNITS_FREQUENCY.setDefaultUnit(3);
217                 
218
219                 HashMap<String,UnitGroup> map = new HashMap<String,UnitGroup>();
220                 map.put("NONE", UNITS_NONE);
221                 map.put("LENGTH", UNITS_LENGTH);
222                 map.put("MOTOR_DIMENSIONS", UNITS_MOTOR_DIMENSIONS);
223                 map.put("DISTANCE", UNITS_DISTANCE);
224                 map.put("VELOCITY", UNITS_VELOCITY);
225                 map.put("ACCELERATION", UNITS_ACCELERATION);
226                 map.put("AREA", UNITS_AREA);
227                 map.put("STABILITY", UNITS_STABILITY);
228                 map.put("MASS", UNITS_MASS);
229                 map.put("ANGLE", UNITS_ANGLE);
230                 map.put("DENSITY_BULK", UNITS_DENSITY_BULK);
231                 map.put("DENSITY_SURFACE", UNITS_DENSITY_SURFACE);
232                 map.put("DENSITY_LINE", UNITS_DENSITY_LINE);
233                 map.put("FORCE", UNITS_FORCE);
234                 map.put("IMPULSE", UNITS_IMPULSE);
235                 map.put("TIME_STEP", UNITS_TIME_STEP);
236                 map.put("SHORT_TIME", UNITS_SHORT_TIME);
237                 map.put("FLIGHT_TIME", UNITS_FLIGHT_TIME);
238                 map.put("ROLL", UNITS_ROLL);
239                 map.put("TEMPERATURE", UNITS_TEMPERATURE);
240                 map.put("PRESSURE", UNITS_PRESSURE);
241                 map.put("RELATIVE", UNITS_RELATIVE);
242                 map.put("ROUGHNESS", UNITS_ROUGHNESS);
243                 map.put("COEFFICIENT", UNITS_COEFFICIENT);
244
245                 UNITS = Collections.unmodifiableMap(map);
246         }
247         
248         public static void setDefaultMetricUnits() {
249                 UNITS_LENGTH.setDefaultUnit("cm");
250                 UNITS_MOTOR_DIMENSIONS.setDefaultUnit("mm");
251                 UNITS_DISTANCE.setDefaultUnit("m");
252                 UNITS_AREA.setDefaultUnit("cm"+SQUARED);
253                 UNITS_STABILITY.setDefaultUnit("cal");
254                 UNITS_VELOCITY.setDefaultUnit("m/s");
255                 UNITS_ACCELERATION.setDefaultUnit("m/s"+SQUARED);
256                 UNITS_MASS.setDefaultUnit("g");
257                 UNITS_ANGLE.setDefaultUnit(""+DEGREE);
258                 UNITS_DENSITY_BULK.setDefaultUnit("g/cm"+CUBED);
259                 UNITS_DENSITY_SURFACE.setDefaultUnit("g/m"+SQUARED);
260                 UNITS_DENSITY_LINE.setDefaultUnit("g/m");
261                 UNITS_FORCE.setDefaultUnit("N");
262                 UNITS_IMPULSE.setDefaultUnit("Ns");
263                 UNITS_TIME_STEP.setDefaultUnit("s");
264                 UNITS_FLIGHT_TIME.setDefaultUnit("s");
265                 UNITS_ROLL.setDefaultUnit("r/s");
266                 UNITS_TEMPERATURE.setDefaultUnit(DEGREE+"C");
267                 UNITS_PRESSURE.setDefaultUnit("mbar");
268                 UNITS_RELATIVE.setDefaultUnit("%");
269                 UNITS_ROUGHNESS.setDefaultUnit(MICRO+"m");
270         }
271         
272         public static void setDefaultImperialUnits() {
273                 UNITS_LENGTH.setDefaultUnit("in");
274                 UNITS_MOTOR_DIMENSIONS.setDefaultUnit("in");
275                 UNITS_DISTANCE.setDefaultUnit("ft");
276                 UNITS_AREA.setDefaultUnit("in"+SQUARED);
277                 UNITS_STABILITY.setDefaultUnit("cal");
278                 UNITS_VELOCITY.setDefaultUnit("ft/s");
279                 UNITS_ACCELERATION.setDefaultUnit("ft/s"+SQUARED);
280                 UNITS_MASS.setDefaultUnit("oz");
281                 UNITS_ANGLE.setDefaultUnit(""+DEGREE);
282                 UNITS_DENSITY_BULK.setDefaultUnit("oz/in"+CUBED);
283                 UNITS_DENSITY_SURFACE.setDefaultUnit("oz/ft"+SQUARED);
284                 UNITS_DENSITY_LINE.setDefaultUnit("oz/ft");
285                 UNITS_FORCE.setDefaultUnit("N");
286                 UNITS_IMPULSE.setDefaultUnit("Ns");
287                 UNITS_TIME_STEP.setDefaultUnit("s");
288                 UNITS_FLIGHT_TIME.setDefaultUnit("s");
289                 UNITS_ROLL.setDefaultUnit("r/s");
290                 UNITS_TEMPERATURE.setDefaultUnit(DEGREE+"F");
291                 UNITS_PRESSURE.setDefaultUnit("mbar");
292                 UNITS_RELATIVE.setDefaultUnit("%");
293                 UNITS_ROUGHNESS.setDefaultUnit("mil");
294         }
295         
296         
297         
298         public static UnitGroup stabilityUnits(Rocket rocket) {
299                 return new StabilityUnitGroup(rocket);
300         }
301         
302         
303         public static UnitGroup stabilityUnits(Configuration config) {
304                 return new StabilityUnitGroup(config);
305         }
306         
307
308         //////////////////////////////////////////////////////
309
310         
311         private ArrayList<Unit> units = new ArrayList<Unit>();
312         private int defaultUnit = 0;
313         
314         public int getUnitCount() {
315                 return units.size();
316         }
317
318         public Unit getDefaultUnit() {
319                 return units.get(defaultUnit);
320         }
321         
322         public int getDefaultUnitIndex() {
323                 return defaultUnit;
324         }
325         
326         public void setDefaultUnit(int n) {
327                 if (n<0 || n>=units.size()) {
328                         throw new IllegalArgumentException("index out of range: "+n);
329                 }
330                 defaultUnit = n;
331         }
332         
333         
334         
335         /**
336          * Find a unit by approximate unit name.  Only letters and (ordinary) numbers are
337          * considered in the matching.  This method is mainly means for testing, allowing
338          * a simple means to obtain a particular unit.
339          * 
340          * @param str   the unit name.
341          * @return              the corresponding unit, or <code>null</code> if not found.
342          */
343         public Unit findApproximate(String str) {
344                 str = str.replaceAll("\\W", "").trim();
345                 for (Unit u: units) {
346                         String name = u.getUnit().replaceAll("\\W", "").trim();
347                         if (str.equalsIgnoreCase(name))
348                                 return u;
349                 }
350                 return null;
351         }
352         
353         /**
354          * Set the default unit based on the unit name.  Throws an exception if a
355          * unit with the provided name is not available.
356          * 
357          * @param   name        the unit name.
358          * @throws  IllegalArgumentException    if the corresponding unit is not found in the group.
359          */
360         public void setDefaultUnit(String name) throws IllegalArgumentException {
361                 for (int i=0; i < units.size(); i++) {
362                         if (units.get(i).getUnit().equals(name)) {
363                                 setDefaultUnit(i);
364                                 return;
365                         }
366                 }
367                 throw new IllegalArgumentException("name="+name);
368         }
369
370         
371         public Unit getUnit(int n) {
372                 return units.get(n);
373         }
374         
375         public int getUnitIndex(Unit u) {
376                 return units.indexOf(u);
377         }
378         
379         public void addUnit(Unit u) {
380                 units.add(u);
381         }
382         
383         public void addUnit(int n, Unit u) {
384                 units.add(n,u);
385         }
386         
387         public void removeUnit(int n) {
388                 units.remove(n);
389         }
390         
391         public boolean contains(Unit u) {
392                 return units.contains(u);
393         }
394         
395         public Unit[] getUnits() {
396                 return units.toArray(new Unit[0]);
397         }
398         
399         
400         /**
401          * Return the value formatted by the default unit of this group.
402          * It is the same as calling <code>getDefaultUnit().toString(value)</code>.
403          * 
404          * @param value         the SI value to format.
405          * @return                      the formatted string.
406          * @see                         Unit#toString(double)
407          */
408         public String toString(double value) {
409                 return this.getDefaultUnit().toString(value);
410         }
411         
412         
413         /**
414          * Return the value formatted by the default unit of this group including the unit.
415          * It is the same as calling <code>getDefaultUnit().toStringUnit(value)</code>.
416          * 
417          * @param value         the SI value to format.
418          * @return                      the formatted string.
419          * @see                         Unit#toStringUnit(double)
420          */
421         public String toStringUnit(double value) {
422                 return this.getDefaultUnit().toStringUnit(value);
423         }
424         
425         
426
427         
428         
429         /**
430          * Creates a new Value object with the specified value and the default unit of this group.
431          * 
432          * @param value the value to set.
433          * @return              a new Value object.
434          */
435         public Value toValue(double value) {
436                 return this.getDefaultUnit().toValue(value);
437         }
438         
439         
440         
441         
442         private static final Pattern STRING_PATTERN = Pattern.compile("^\\s*([0-9.,-]+)(.*?)$");
443         /**
444          * Converts a string into an SI value.  If the string has one of the units in this
445          * group appended to it, that unit will be used in conversion.  Otherwise the default
446          * unit will be used.  If an unknown unit is specified or the value does not parse
447          * with <code>Double.parseDouble</code> then a <code>NumberFormatException</code> 
448          * is thrown.
449          * <p>
450          * This method is applicable only for simple units without e.g. powers.
451          * 
452          * @param str   the string to parse.
453          * @return              the SI value.
454          * @throws NumberFormatException   if the string cannot be parsed.
455          */
456         public double fromString(String str) {
457                 Matcher matcher = STRING_PATTERN.matcher(str);
458                 
459                 if (!matcher.matches()) {
460                         throw new NumberFormatException("string did not match required pattern");
461                 }
462                 
463                 double value = Double.parseDouble(matcher.group(1));
464                 String unit = matcher.group(2).trim();
465                 
466                 if (unit.equals("")) {
467                         value = this.getDefaultUnit().fromUnit(value);
468                 } else {
469                         int i;
470                         for (i=0; i < units.size(); i++) {
471                                 Unit u = units.get(i);
472                                 if (unit.equalsIgnoreCase(u.getUnit())) {
473                                         value = u.fromUnit(value);
474                                         break;
475                                 }
476                         }
477                         if (i >= units.size()) {
478                                 throw new NumberFormatException("unknown unit "+unit);
479                         }
480                 }
481                 
482                 return value;
483         }
484         
485         
486         ///////////////////////////
487         
488         
489         /**
490          * A private class that switches the CaliberUnit to a rocket-specific CaliberUnit.
491          * All other methods are passed through to UNITS_STABILITY.
492          */
493         private static class StabilityUnitGroup extends UnitGroup {
494                 
495                 private final CaliberUnit caliberUnit;
496                 
497                 
498                 public StabilityUnitGroup(Rocket rocket) {
499                         caliberUnit = new CaliberUnit(rocket);
500                 }
501                 
502                 public StabilityUnitGroup(Configuration config) {
503                         caliberUnit = new CaliberUnit(config);
504                 }
505                 
506
507                 ////  Modify CaliberUnit to use local variable
508                 
509                 @Override
510                 public Unit getDefaultUnit() {
511                         return getUnit(UNITS_STABILITY.getDefaultUnitIndex());
512                 }
513
514                 @Override
515                 public Unit getUnit(int n) {
516                         Unit u = UNITS_STABILITY.getUnit(n);
517                         if (u instanceof CaliberUnit) {
518                                 return caliberUnit;
519                         }
520                         return u;
521                 }
522
523                 @Override
524                 public int getUnitIndex(Unit u) {
525                         if (u instanceof CaliberUnit) {
526                                 for (int i=0; i < UNITS_STABILITY.getUnitCount(); i++) {
527                                         if (UNITS_STABILITY.getUnit(i) instanceof CaliberUnit)
528                                                 return i;
529                                 }
530                         }
531                         return UNITS_STABILITY.getUnitIndex(u);
532                 }
533
534                 
535
536                 ////  Pass on to UNITS_STABILITY
537                 
538                 @Override
539                 public int getDefaultUnitIndex() {
540                         return UNITS_STABILITY.getDefaultUnitIndex();
541                 }
542
543                 @Override
544                 public void setDefaultUnit(int n) {
545                         UNITS_STABILITY.setDefaultUnit(n);
546                 }
547
548                 @Override
549                 public int getUnitCount() {
550                         return UNITS_STABILITY.getUnitCount();
551                 }
552
553
554                 ////  Unsupported methods
555                 
556                 @Override
557                 public void addUnit(int n, Unit u) {
558                         throw new UnsupportedOperationException("StabilityUnitGroup must not be modified");
559                 }
560
561                 @Override
562                 public void addUnit(Unit u) {
563                         throw new UnsupportedOperationException("StabilityUnitGroup must not be modified");
564                 }
565
566                 @Override
567                 public void removeUnit(int n) {
568                         throw new UnsupportedOperationException("StabilityUnitGroup must not be modified");
569                 }
570         }
571 }