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);
62 // Same processing as BODY_TUBE
71 makeParachute(preset);
76 preset.computeDigest();
82 private static void makeBodyTube( ComponentPreset preset ) throws InvalidComponentPresetException {
84 checkRequiredFields( preset, LENGTH );
86 checkDiametersAndThickness(preset);
88 double volume = computeVolumeOfTube( preset );
90 // Need to translate Mass to Density.
91 if ( preset.has(MASS) ) {
92 String materialName = "TubeCustom";
93 if ( preset.has(MATERIAL) ) {
94 materialName = preset.get(MATERIAL).getName();
96 Material m = Material.newMaterial(Material.Type.BULK, materialName, preset.get(MASS)/volume, false);
97 preset.put(MATERIAL, m);
103 private static void makeNoseCone( ComponentPreset preset ) throws InvalidComponentPresetException {
105 checkRequiredFields( preset, LENGTH, SHAPE, AFT_OUTER_DIAMETER );
107 if ( preset.has(MASS) ) {
108 // compute a density for this component
109 double mass = preset.get(MASS);
110 NoseCone nc = new NoseCone();
111 nc.loadPreset(preset);
112 double density = mass / nc.getComponentVolume();
114 String materialName = "NoseConeCustom";
115 if ( preset.has(MATERIAL) ) {
116 materialName = preset.get(MATERIAL).getName();
119 Material m = Material.newMaterial(Material.Type.BULK, materialName,density, false);
120 preset.put(MATERIAL, m);
126 private static void makeTransition( ComponentPreset preset ) throws InvalidComponentPresetException {
127 checkRequiredFields(preset, LENGTH, AFT_OUTER_DIAMETER, FORE_OUTER_DIAMETER);
129 if ( preset.has(MASS) ) {
130 // compute a density for this component
131 double mass = preset.get(MASS);
132 Transition tr = new Transition();
133 tr.loadPreset(preset);
134 double density = mass / tr.getComponentVolume();
136 String materialName = "TransitionCustom";
137 if ( preset.has(MATERIAL) ) {
138 materialName = preset.get(MATERIAL).getName();
141 Material m = Material.newMaterial(Material.Type.BULK, materialName,density, false);
142 preset.put(MATERIAL, m);
148 private static void makeBulkHead( ComponentPreset preset ) throws InvalidComponentPresetException {
149 checkRequiredFields(preset, LENGTH, OUTER_DIAMETER );
151 if ( preset.has(MASS) ) {
152 // compute a density for this component
153 double mass = preset.get(MASS);
155 double volume = computeVolumeOfTube(preset);
156 double density = mass / volume;
158 String materialName = "BulkHeadCustom";
159 if ( preset.has(MATERIAL) ) {
160 materialName = preset.get(MATERIAL).getName();
163 Material m = Material.newMaterial(Material.Type.BULK, materialName,density, false);
164 preset.put(MATERIAL, m);
170 private static void makeCenteringRing( ComponentPreset preset ) throws InvalidComponentPresetException {
171 checkRequiredFields( preset, LENGTH );
173 checkDiametersAndThickness( preset );
175 double volume = computeVolumeOfTube( preset );
177 // Need to translate Mass to Density.
178 if ( preset.has(MASS) ) {
179 String materialName = "CenteringRingCustom";
180 if ( preset.has(MATERIAL) ) {
181 materialName = preset.get(MATERIAL).getName();
183 Material m = Material.newMaterial(Material.Type.BULK, materialName, preset.get(MASS)/volume, false);
184 preset.put(MATERIAL, m);
189 private static void makeEngineBlock( ComponentPreset preset ) throws InvalidComponentPresetException {
190 checkRequiredFields( preset, LENGTH );
192 checkDiametersAndThickness( preset );
194 double volume = computeVolumeOfTube( preset );
196 // Need to translate Mass to Density.
197 if ( preset.has(MASS) ) {
198 String materialName = "EngineBlockCustom";
199 if ( preset.has(MATERIAL) ) {
200 materialName = preset.get(MATERIAL).getName();
202 Material m = Material.newMaterial(Material.Type.BULK, materialName, preset.get(MASS)/volume, false);
203 preset.put(MATERIAL, m);
208 private static void makeStreamer( ComponentPreset preset ) throws InvalidComponentPresetException {
209 checkRequiredFields( preset, LENGTH, WIDTH );
212 private static void makeParachute( ComponentPreset preset ) throws InvalidComponentPresetException {
213 checkRequiredFields( preset, DIAMETER, LINE_COUNT, LINE_LENGTH );
217 private static void checkRequiredFields( ComponentPreset preset, TypedKey<?> ... keys ) throws InvalidComponentPresetException {
218 for( TypedKey<?> key: keys ) {
219 if (! preset.has(key) ) {
220 throw new InvalidComponentPresetException( "No " + key.getName() + " specified for " + preset.getType().name() + " preset " + preset.toString());
225 private static void checkDiametersAndThickness( ComponentPreset preset ) throws InvalidComponentPresetException {
226 // Need to verify contains 2 of OD, thickness, ID. Compute the third.
227 boolean hasOd = preset.has(OUTER_DIAMETER);
228 boolean hasId = preset.has(INNER_DIAMETER);
229 boolean hasThickness = preset.has(THICKNESS);
236 outerRadius = preset.get(OUTER_DIAMETER)/2.0;
239 innerRadius = preset.get(INNER_DIAMETER)/2.0;
240 thickness = outerRadius - innerRadius;
241 } else if ( hasThickness ) {
242 thickness = preset.get(THICKNESS);
243 innerRadius = outerRadius - thickness;
245 throw new InvalidComponentPresetException("Preset underspecified " + preset.toString());
248 if ( ! hasId || ! hasThickness ) {
249 throw new InvalidComponentPresetException("Preset underspecified " + preset.toString());
251 innerRadius = preset.get(INNER_DIAMETER)/2.0;
252 thickness = preset.get(THICKNESS);
253 outerRadius = innerRadius + thickness;
256 preset.put(OUTER_DIAMETER, outerRadius *2.0);
257 preset.put(INNER_DIAMETER, innerRadius *2.0);
258 preset.put(THICKNESS, thickness );
262 private static double computeVolumeOfTube(ComponentPreset preset) {
263 double or = preset.get(OUTER_DIAMETER)/2.0;
264 double ir = preset.has(INNER_DIAMETER) ? preset.get(INNER_DIAMETER)/2.0 : 0.0;
265 double l = preset.get(LENGTH);
266 return Math.PI * (or*or - ir*ir) * l;