1 package net.sf.openrocket.preset;
3 import java.util.HashMap;
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;
15 * A model for a preset component.
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.
20 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
22 // FIXME - Implement clone.
23 public class ComponentPreset {
25 private final TypedPropertyMap properties = new TypedPropertyMap();
27 private boolean favorite = false;
33 Type[] compatibleTypes;
36 compatibleTypes = new Type[1];
37 compatibleTypes[0] = this;
42 compatibleTypes = new Type[t.length+1];
43 compatibleTypes[0] = this;
44 for( int i=0; i<t.length; i++ ) {
45 compatibleTypes[i+1] = t[i];
49 public Type[] getCompatibleTypes() {
50 return compatibleTypes;
55 public final static TypedKey<Manufacturer> MANUFACTURER = new TypedKey<Manufacturer>("Manufacturer", Manufacturer.class);
56 public final static TypedKey<String> PARTNO = new TypedKey<String>("PartNo",String.class);
57 public final static TypedKey<Type> TYPE = new TypedKey<Type>("Type",Type.class);
58 public final static TypedKey<Double> LENGTH = new TypedKey<Double>("Length", Double.class, UnitGroup.UNITS_LENGTH);
59 public final static TypedKey<Double> INNER_DIAMETER = new TypedKey<Double>("InnerDiameter", Double.class, UnitGroup.UNITS_LENGTH);
60 public final static TypedKey<Double> OUTER_DIAMETER = new TypedKey<Double>("OuterDiameter", Double.class, UnitGroup.UNITS_LENGTH);
61 public final static TypedKey<Material> MATERIAL = new TypedKey<Material>("Material", Material.class);
62 public final static TypedKey<Finish> FINISH = new TypedKey<Finish>("Finish", Finish.class);
63 public final static TypedKey<Double> THICKNESS = new TypedKey<Double>("Thickness", Double.class, UnitGroup.UNITS_LENGTH);
64 public final static TypedKey<Boolean> FILLED = new TypedKey<Boolean>("Filled", Boolean.class);
65 public final static TypedKey<Double> MASS = new TypedKey<Double>("Mass", Double.class, UnitGroup.UNITS_MASS);
67 public final static Map<String, TypedKey<?>> keyMap = new HashMap<String, TypedKey<?>>();
69 keyMap.put(MANUFACTURER.getName(), MANUFACTURER);
70 keyMap.put(PARTNO.getName(), PARTNO);
71 keyMap.put(TYPE.getName(), TYPE);
72 keyMap.put(LENGTH.getName(), LENGTH);
73 keyMap.put(INNER_DIAMETER.getName(), INNER_DIAMETER);
74 keyMap.put(OUTER_DIAMETER.getName(), OUTER_DIAMETER);
75 keyMap.put(MATERIAL.getName(), MATERIAL);
76 keyMap.put(FINISH.getName(), FINISH);
77 keyMap.put(THICKNESS.getName(), THICKNESS);
78 keyMap.put(FILLED.getName(), FILLED);
79 keyMap.put(MASS.getName(), MASS);
82 public static ComponentPreset create( TypedPropertyMap props ) throws InvalidComponentPresetException {
84 ComponentPreset preset = new ComponentPreset();
85 // First do validation.
86 if ( !props.containsKey(TYPE)) {
87 throw new InvalidComponentPresetException("No Type specified " + props.toString() );
90 if (!props.containsKey(MANUFACTURER)) {
91 throw new InvalidComponentPresetException("No Manufacturer specified " + props.toString() );
94 if (!props.containsKey(PARTNO)) {
95 throw new InvalidComponentPresetException("No PartNo specified " + props.toString() );
98 preset.properties.putAll(props);
100 // Should check for various bits of each of the types.
101 Type t = props.get(TYPE);
105 if ( !props.containsKey(LENGTH) ) {
106 throw new InvalidComponentPresetException( "No Length specified for body tube preset " + props.toString());
109 BodyTube bt = new BodyTube();
111 bt.setLength(props.get(LENGTH));
113 // Need to verify contains 2 of OD, thickness, ID. Compute the third.
114 boolean hasOd = props.containsKey(OUTER_DIAMETER);
115 boolean hasId = props.containsKey(INNER_DIAMETER);
116 boolean hasThickness = props.containsKey(THICKNESS);
119 double outerRadius = props.get(OUTER_DIAMETER)/2.0;
120 double thickness = 0;
121 bt.setOuterRadius( outerRadius );
123 thickness = outerRadius - props.get(INNER_DIAMETER)/2.0;
124 } else if ( hasThickness ) {
125 thickness = props.get(THICKNESS);
127 throw new InvalidComponentPresetException("Body tube preset underspecified " + props.toString());
129 bt.setThickness( thickness );
131 if ( ! hasId && ! hasThickness ) {
132 throw new InvalidComponentPresetException("Body tube preset underspecified " + props.toString());
134 double innerRadius = props.get(INNER_DIAMETER)/2.0;
135 double thickness = props.get(THICKNESS);
136 bt.setOuterRadius(innerRadius + thickness);
137 bt.setThickness(thickness);
140 preset.properties.put(OUTER_DIAMETER, bt.getOuterRadius() *2.0);
141 preset.properties.put(INNER_DIAMETER, bt.getInnerRadius() *2.0);
142 preset.properties.put(THICKNESS, bt.getThickness());
144 // Need to translate Mass to Density.
145 if ( props.containsKey(MASS) ) {
146 String materialName = "TubeCustom";
147 if ( props.containsKey(MATERIAL) ) {
148 materialName = props.get(MATERIAL).getName();
150 Material m = Material.newMaterial(Material.Type.BULK, materialName, props.get(MASS)/bt.getComponentVolume(), false);
151 preset.properties.put(MATERIAL, m);
165 // Private constructor to encourage use of factory.
166 private ComponentPreset() {
170 public boolean has(Object key) {
171 return properties.containsKey(key);
174 public <T> T get(TypedKey<T> key) {
175 T value = properties.get(key);
177 throw new BugException("Preset did not contain key " + key + " " + properties.toString());
182 public boolean isFavorite() {
186 public void setFavorite(boolean favorite) {
187 this.favorite = favorite;
191 public String toString() {
192 return get(MANUFACTURER).toString() + " " + get(PARTNO);
195 public String preferenceKey() {
196 return get(MANUFACTURER).toString() + "|" + get(PARTNO);