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