Add units.
[debian/openrocket] / core / src / net / sf / openrocket / preset / ComponentPreset.java
1 package net.sf.openrocket.preset;
2
3 import java.util.HashMap;
4 import java.util.Map;
5
6 import net.sf.openrocket.material.Material;
7 import net.sf.openrocket.motor.Manufacturer;
8 import net.sf.openrocket.rocketcomponent.BodyTube;
9 import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
10 import net.sf.openrocket.unit.UnitGroup;
11 import net.sf.openrocket.util.BugException;
12
13
14 /**
15  * A model for a preset component.
16  * <p>
17  * A preset component contains a component class type, manufacturer information,
18  * part information, and a method that returns a prototype of the preset component.
19  * 
20  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
21  */
22 public class ComponentPreset {
23         
24         private final TypedPropertyMap properties = new TypedPropertyMap();
25         
26         
27         // TODO - Implement clone.
28         
29         public enum Type {
30                 BODY_TUBE,
31                 NOSE_CONE
32         }
33         
34         public final static TypedKey<Manufacturer> MANUFACTURER = new TypedKey<Manufacturer>("Manufacturer", Manufacturer.class);
35         public final static TypedKey<String> PARTNO = new TypedKey<String>("PartNo",String.class);
36         public final static TypedKey<Type> TYPE = new TypedKey<Type>("Type",Type.class);
37         public final static TypedKey<Double> LENGTH = new TypedKey<Double>("Length", Double.class, UnitGroup.UNITS_LENGTH);
38         public final static TypedKey<Double> INNER_DIAMETER = new TypedKey<Double>("InnerDiameter", Double.class, UnitGroup.UNITS_LENGTH);
39         public final static TypedKey<Double> OUTER_DIAMETER = new TypedKey<Double>("OuterDiameter", Double.class, UnitGroup.UNITS_LENGTH);
40         public final static TypedKey<Material> MATERIAL = new TypedKey<Material>("Material", Material.class);
41         public final static TypedKey<Finish> FINISH = new TypedKey<Finish>("Finish", Finish.class);
42         public final static TypedKey<Double> THICKNESS = new TypedKey<Double>("Thickness", Double.class, UnitGroup.UNITS_LENGTH);
43         public final static TypedKey<Boolean> FILLED = new TypedKey<Boolean>("Filled", Boolean.class);
44         public final static TypedKey<Double> MASS = new TypedKey<Double>("Mass", Double.class, UnitGroup.UNITS_MASS);
45         
46         public final static Map<String, TypedKey<?>> keyMap = new HashMap<String, TypedKey<?>>();
47         static {
48                 keyMap.put(MANUFACTURER.getName(), MANUFACTURER);
49                 keyMap.put(PARTNO.getName(), PARTNO);
50                 keyMap.put(TYPE.getName(), TYPE);
51                 keyMap.put(LENGTH.getName(), LENGTH);
52                 keyMap.put(INNER_DIAMETER.getName(), INNER_DIAMETER);
53                 keyMap.put(OUTER_DIAMETER.getName(), OUTER_DIAMETER);
54                 keyMap.put(MATERIAL.getName(), MATERIAL);
55                 keyMap.put(FINISH.getName(), FINISH);
56                 keyMap.put(THICKNESS.getName(), THICKNESS);
57                 keyMap.put(FILLED.getName(), FILLED);
58                 keyMap.put(MASS.getName(), MASS);
59         }
60         
61         public static ComponentPreset create( TypedPropertyMap props ) throws InvalidComponentPresetException {
62                 
63                 ComponentPreset preset = new ComponentPreset();
64                 // First do validation.
65                 if ( !props.containsKey(TYPE)) {
66                         throw new InvalidComponentPresetException("No Type specified " + props.toString() );
67                 }
68                 
69                 if (!props.containsKey(MANUFACTURER)) {
70                         throw new InvalidComponentPresetException("No Manufacturer specified " + props.toString() );
71                 }
72
73                 if (!props.containsKey(PARTNO)) {
74                         throw new InvalidComponentPresetException("No PartNo specified " + props.toString() );
75                 }
76
77                 preset.properties.putAll(props);
78                 
79                 // Should check for various bits of each of the types.
80                 Type t = props.get(TYPE);
81                 switch ( t ) {
82                 case BODY_TUBE: {
83                         
84                         if ( !props.containsKey(LENGTH) ) {
85                                 throw new InvalidComponentPresetException( "No Length specified for body tube preset " + props.toString());
86                         }
87                         
88                         BodyTube bt = new BodyTube();
89                         
90                         bt.setLength(props.get(LENGTH));
91                         
92                         // Need to verify contains 2 of OD, thickness, ID.  Compute the third.
93                         boolean hasOd = props.containsKey(OUTER_DIAMETER);
94                         boolean hasId = props.containsKey(INNER_DIAMETER);
95                         boolean hasThickness = props.containsKey(THICKNESS);
96                         
97                         if ( hasOd ) {
98                                 double outerRadius = props.get(OUTER_DIAMETER)/2.0;
99                                 double thickness = 0;
100                                 bt.setOuterRadius( outerRadius );
101                                 if ( hasId ) {
102                                         thickness = outerRadius - props.get(INNER_DIAMETER)/2.0;
103                                 } else if ( hasThickness ) {
104                                         thickness = props.get(THICKNESS);
105                                 } else {
106                                         throw new InvalidComponentPresetException("Body tube preset underspecified " + props.toString());
107                                 }
108                                 bt.setThickness( thickness );
109                         } else {
110                                 if ( ! hasId && ! hasThickness ) {
111                                         throw new InvalidComponentPresetException("Body tube preset underspecified " + props.toString());
112                                 }
113                                 double innerRadius = props.get(INNER_DIAMETER)/2.0;
114                                 double thickness = props.get(THICKNESS);
115                                 bt.setOuterRadius(innerRadius + thickness);
116                                 bt.setThickness(thickness);
117                         }
118
119                         preset.properties.put(OUTER_DIAMETER, bt.getOuterRadius() *2.0);
120                         preset.properties.put(INNER_DIAMETER, bt.getInnerRadius() *2.0);
121                         preset.properties.put(THICKNESS, bt.getThickness());
122                         
123                         // Need to translate Mass to Density.
124                         if ( props.containsKey(MASS) ) {
125                                 String materialName = "TubeCustom";
126                                 if ( props.containsKey(MATERIAL) ) {
127                                         materialName = props.get(MATERIAL).getName();
128                                 }
129                                 Material m = Material.newMaterial(Material.Type.BULK, materialName, props.get(MASS)/bt.getComponentVolume(), false);
130                                 preset.properties.put(MATERIAL, m);
131                         }
132                         
133                         break;
134                 }
135                 case NOSE_CONE: {
136                         break;
137                 }
138                 }
139                 
140                 return preset;
141
142         }
143
144         // Private constructor to encourage use of factory.
145         private ComponentPreset() {
146                 
147         }
148         
149         public boolean has(Object key) {
150                 return properties.containsKey(key);
151         }
152         
153         public <T> T get(TypedKey<T> key) {
154                 T value = properties.get(key);
155                 if (value == null) {
156                         throw new BugException("Preset did not contain key " + key + " " + properties.toString());
157                 }
158                 return (T) value;
159         }
160         
161         @Override
162         public String toString() {
163                 return get(MANUFACTURER).toString() + " " + get(PARTNO);
164         }
165         
166         
167 }