1 package net.sf.openrocket.preset;
3 import static net.sf.openrocket.preset.ComponentPreset.*;
4 import net.sf.openrocket.material.Material;
5 import net.sf.openrocket.preset.ComponentPreset.Type;
6 import net.sf.openrocket.rocketcomponent.NoseCone;
7 import net.sf.openrocket.rocketcomponent.Transition;
9 public abstract class ComponentPresetFactory {
11 public static ComponentPreset create( TypedPropertyMap props ) throws InvalidComponentPresetException {
13 ComponentPreset preset = new ComponentPreset();
14 // First do validation.
15 if ( !props.containsKey(TYPE)) {
16 throw new InvalidComponentPresetException("No Type specified " + props.toString() );
19 if (!props.containsKey(MANUFACTURER)) {
20 throw new InvalidComponentPresetException("No Manufacturer specified " + props.toString() );
23 if (!props.containsKey(PARTNO)) {
24 throw new InvalidComponentPresetException("No PartNo specified " + props.toString() );
29 // Should check for various bits of each of the types.
30 Type t = props.get(TYPE);
41 makeTransition(preset);
49 // For now TUBE_COUPLER is the same as BODY_TUBE
53 case CENTERING_RING: {
54 makeCenteringRing(preset);
58 makeEngineBlock(preset);
63 preset.computeDigest();
69 private static void makeBodyTube( ComponentPreset preset ) throws InvalidComponentPresetException {
71 checkRequiredFields( preset, LENGTH );
73 checkDiametersAndThickness(preset);
75 double volume = computeVolumeOfTube( preset );
77 // Need to translate Mass to Density.
78 if ( preset.has(MASS) ) {
79 String materialName = "TubeCustom";
80 if ( preset.has(MATERIAL) ) {
81 materialName = preset.get(MATERIAL).getName();
83 Material m = Material.newMaterial(Material.Type.BULK, materialName, preset.get(MASS)/volume, false);
84 preset.put(MATERIAL, m);
90 private static void makeNoseCone( ComponentPreset preset ) throws InvalidComponentPresetException {
92 checkRequiredFields( preset, LENGTH, SHAPE, AFT_OUTER_DIAMETER );
94 if ( preset.has(MASS) ) {
95 // compute a density for this component
96 double mass = preset.get(MASS);
97 NoseCone nc = new NoseCone();
98 nc.loadPreset(preset);
99 double density = mass / nc.getComponentVolume();
101 String materialName = "NoseConeCustom";
102 if ( preset.has(MATERIAL) ) {
103 materialName = preset.get(MATERIAL).getName();
106 Material m = Material.newMaterial(Material.Type.BULK, materialName,density, false);
107 preset.put(MATERIAL, m);
113 private static void makeTransition( ComponentPreset preset ) throws InvalidComponentPresetException {
114 checkRequiredFields(preset, LENGTH, AFT_OUTER_DIAMETER, FORE_OUTER_DIAMETER);
116 if ( preset.has(MASS) ) {
117 // compute a density for this component
118 double mass = preset.get(MASS);
119 Transition tr = new Transition();
120 tr.loadPreset(preset);
121 double density = mass / tr.getComponentVolume();
123 String materialName = "TransitionCustom";
124 if ( preset.has(MATERIAL) ) {
125 materialName = preset.get(MATERIAL).getName();
128 Material m = Material.newMaterial(Material.Type.BULK, materialName,density, false);
129 preset.put(MATERIAL, m);
135 private static void makeBulkHead( ComponentPreset preset ) throws InvalidComponentPresetException {
136 checkRequiredFields(preset, LENGTH, OUTER_DIAMETER );
138 if ( preset.has(MASS) ) {
139 // compute a density for this component
140 double mass = preset.get(MASS);
141 // FIXME - Bulkhead.getComponentVolume does not exist!
142 // double density = mass / tr.getComponentVolume();
144 double volume = computeVolumeOfTube(preset);
145 double density = mass / volume;
147 String materialName = "BulkHeadCustom";
148 if ( preset.has(MATERIAL) ) {
149 materialName = preset.get(MATERIAL).getName();
152 Material m = Material.newMaterial(Material.Type.BULK, materialName,density, false);
153 preset.put(MATERIAL, m);
159 private static void makeCenteringRing( ComponentPreset preset ) throws InvalidComponentPresetException {
160 checkRequiredFields( preset, LENGTH );
162 checkDiametersAndThickness( preset );
164 double volume = computeVolumeOfTube( preset );
166 // Need to translate Mass to Density.
167 if ( preset.has(MASS) ) {
168 String materialName = "CenteringRingCustom";
169 if ( preset.has(MATERIAL) ) {
170 materialName = preset.get(MATERIAL).getName();
172 Material m = Material.newMaterial(Material.Type.BULK, materialName, preset.get(MASS)/volume, false);
173 preset.put(MATERIAL, m);
178 private static void makeEngineBlock( ComponentPreset preset ) throws InvalidComponentPresetException {
179 checkRequiredFields( preset, LENGTH );
181 checkDiametersAndThickness( preset );
183 double volume = computeVolumeOfTube( preset );
185 // Need to translate Mass to Density.
186 if ( preset.has(MASS) ) {
187 String materialName = "EngineBlockCustom";
188 if ( preset.has(MATERIAL) ) {
189 materialName = preset.get(MATERIAL).getName();
191 Material m = Material.newMaterial(Material.Type.BULK, materialName, preset.get(MASS)/volume, false);
192 preset.put(MATERIAL, m);
197 private static void checkRequiredFields( ComponentPreset preset, TypedKey<?> ... keys ) throws InvalidComponentPresetException {
198 for( TypedKey<?> key: keys ) {
199 if (! preset.has(key) ) {
200 throw new InvalidComponentPresetException( "No " + key.getName() + " specified for " + preset.getType().name() + " preset " + preset.toString());
205 private static void checkDiametersAndThickness( ComponentPreset preset ) throws InvalidComponentPresetException {
206 // Need to verify contains 2 of OD, thickness, ID. Compute the third.
207 boolean hasOd = preset.has(OUTER_DIAMETER);
208 boolean hasId = preset.has(INNER_DIAMETER);
209 boolean hasThickness = preset.has(THICKNESS);
216 outerRadius = preset.get(OUTER_DIAMETER)/2.0;
219 innerRadius = preset.get(INNER_DIAMETER)/2.0;
220 thickness = outerRadius - innerRadius;
221 } else if ( hasThickness ) {
222 thickness = preset.get(THICKNESS);
223 innerRadius = outerRadius - thickness;
225 throw new InvalidComponentPresetException("Preset underspecified " + preset.toString());
228 if ( ! hasId || ! hasThickness ) {
229 throw new InvalidComponentPresetException("Preset underspecified " + preset.toString());
231 innerRadius = preset.get(INNER_DIAMETER)/2.0;
232 thickness = preset.get(THICKNESS);
233 outerRadius = innerRadius + thickness;
236 preset.put(OUTER_DIAMETER, outerRadius *2.0);
237 preset.put(INNER_DIAMETER, innerRadius *2.0);
238 preset.put(THICKNESS, thickness );
242 private static double computeVolumeOfTube(ComponentPreset preset) {
243 double or = preset.get(OUTER_DIAMETER)/2.0;
244 double ir = preset.has(INNER_DIAMETER) ? preset.get(INNER_DIAMETER)/2.0 : 0.0;
245 double l = preset.get(LENGTH);
246 return Math.PI * (or*or - ir*ir) * l;