1 package net.sf.openrocket.preset;
3 import static net.sf.openrocket.preset.ComponentPreset.*;
4 import net.sf.openrocket.database.Databases;
5 import net.sf.openrocket.material.Material;
6 import net.sf.openrocket.preset.ComponentPreset.Type;
7 import net.sf.openrocket.rocketcomponent.NoseCone;
8 import net.sf.openrocket.rocketcomponent.Transition;
10 public abstract class ComponentPresetFactory {
12 public static ComponentPreset create(TypedPropertyMap props) throws InvalidComponentPresetException {
14 InvalidComponentPresetException exceptions = new InvalidComponentPresetException("Invalid preset specification.");
16 ComponentPreset preset = new ComponentPreset();
17 // First do validation.
18 if (!props.containsKey(MANUFACTURER)) {
19 exceptions.addInvalidParameter(MANUFACTURER, "No Manufacturer specified");
21 if (!props.containsKey(PARTNO)) {
22 exceptions.addInvalidParameter(PARTNO, "No PartNo specified");
24 if (!props.containsKey(TYPE)) {
25 exceptions.addInvalidParameter(TYPE, "No Type specified");
26 // We can't do anything else without TYPE so throw immediately.
33 // Should check for various bits of each of the types.
34 Type t = props.get(TYPE);
37 makeBodyTube(exceptions, preset);
41 makeNoseCone(exceptions, preset);
45 makeTransition(exceptions, preset);
49 makeBulkHead(exceptions, preset);
53 // For now TUBE_COUPLER is the same as BODY_TUBE
54 makeBodyTube(exceptions, preset);
57 case CENTERING_RING: {
58 makeCenteringRing(exceptions, preset);
62 makeEngineBlock(exceptions, preset);
66 // Same processing as BODY_TUBE
67 makeBodyTube(exceptions, preset);
71 makeStreamer(exceptions, preset);
75 makeParachute(exceptions, preset);
80 if (exceptions.hasProblems()) {
84 preset.computeDigest();
90 private static void makeBodyTube(InvalidComponentPresetException exceptions, ComponentPreset preset) throws InvalidComponentPresetException {
92 checkRequiredFields(exceptions, preset, LENGTH);
94 checkDiametersAndThickness(exceptions, preset);
96 double volume = computeVolumeOfTube(preset);
98 // Need to translate Mass to Density.
99 if (preset.has(MASS)) {
100 String materialName = "TubeCustom";
101 if (preset.has(MATERIAL)) {
102 materialName = preset.get(MATERIAL).getName();
104 Material m = Databases.findMaterial(Material.Type.BULK, materialName, preset.get(MASS) / volume);
105 preset.put(MATERIAL, m);
111 private static void makeNoseCone(InvalidComponentPresetException exceptions, ComponentPreset preset) {
113 checkRequiredFields(exceptions, preset, LENGTH, SHAPE, AFT_OUTER_DIAMETER);
115 if (preset.has(MASS)) {
116 // compute a density for this component
117 double mass = preset.get(MASS);
118 NoseCone nc = new NoseCone();
119 nc.loadPreset(preset);
120 double density = mass / nc.getComponentVolume();
122 String materialName = "NoseConeCustom";
123 if (preset.has(MATERIAL)) {
124 materialName = preset.get(MATERIAL).getName();
127 Material m = Databases.findMaterial(Material.Type.BULK, materialName, density);
128 preset.put(MATERIAL, m);
134 private static void makeTransition(InvalidComponentPresetException exceptions, ComponentPreset preset) {
135 checkRequiredFields(exceptions, preset, LENGTH, AFT_OUTER_DIAMETER, FORE_OUTER_DIAMETER);
137 if (preset.has(MASS)) {
138 // compute a density for this component
139 double mass = preset.get(MASS);
140 Transition tr = new Transition();
141 tr.loadPreset(preset);
142 double density = mass / tr.getComponentVolume();
144 String materialName = "TransitionCustom";
145 if (preset.has(MATERIAL)) {
146 materialName = preset.get(MATERIAL).getName();
149 Material m = Databases.findMaterial(Material.Type.BULK, materialName, density);
150 preset.put(MATERIAL, m);
156 private static void makeBulkHead(InvalidComponentPresetException exceptions, ComponentPreset preset) {
157 checkRequiredFields(exceptions, preset, LENGTH, OUTER_DIAMETER);
159 if (preset.has(MASS)) {
160 // compute a density for this component
161 double mass = preset.get(MASS);
163 double volume = computeVolumeOfTube(preset);
164 double density = mass / volume;
166 String materialName = "BulkHeadCustom";
167 if (preset.has(MATERIAL)) {
168 materialName = preset.get(MATERIAL).getName();
171 Material m = Databases.findMaterial(Material.Type.BULK, materialName, density);
172 preset.put(MATERIAL, m);
178 private static void makeCenteringRing(InvalidComponentPresetException exceptions, ComponentPreset preset) throws InvalidComponentPresetException {
179 checkRequiredFields(exceptions, preset, LENGTH);
181 checkDiametersAndThickness(exceptions, preset);
183 double volume = computeVolumeOfTube(preset);
185 // Need to translate Mass to Density.
186 if (preset.has(MASS)) {
187 String materialName = "CenteringRingCustom";
188 if (preset.has(MATERIAL)) {
189 materialName = preset.get(MATERIAL).getName();
191 Material m = Databases.findMaterial(Material.Type.BULK, materialName, preset.get(MASS) / volume);
192 preset.put(MATERIAL, m);
197 private static void makeEngineBlock(InvalidComponentPresetException exceptions, ComponentPreset preset) throws InvalidComponentPresetException {
198 checkRequiredFields(exceptions, preset, LENGTH);
200 checkDiametersAndThickness(exceptions, preset);
202 double volume = computeVolumeOfTube(preset);
204 // Need to translate Mass to Density.
205 if (preset.has(MASS)) {
206 String materialName = "EngineBlockCustom";
207 if (preset.has(MATERIAL)) {
208 materialName = preset.get(MATERIAL).getName();
210 Material m = Databases.findMaterial(Material.Type.BULK, materialName, preset.get(MASS) / volume);
211 preset.put(MATERIAL, m);
216 private static void makeStreamer(InvalidComponentPresetException exceptions, ComponentPreset preset) {
217 checkRequiredFields(exceptions, preset, LENGTH, WIDTH);
220 private static void makeParachute(InvalidComponentPresetException exceptions, ComponentPreset preset) {
221 checkRequiredFields(exceptions, preset, DIAMETER, LINE_COUNT, LINE_LENGTH);
225 private static void checkRequiredFields(InvalidComponentPresetException exceptions, ComponentPreset preset, TypedKey<?>... keys) {
226 for (TypedKey<?> key : keys) {
227 if (!preset.has(key)) {
228 exceptions.addInvalidParameter(key, "No " + key.getName() + " specified");
233 private static void checkDiametersAndThickness(InvalidComponentPresetException exceptions, ComponentPreset preset) throws InvalidComponentPresetException {
234 // Need to verify contains 2 of OD, thickness, ID. Compute the third.
235 boolean hasOd = preset.has(OUTER_DIAMETER);
236 boolean hasId = preset.has(INNER_DIAMETER);
237 boolean hasThickness = preset.has(THICKNESS);
244 outerRadius = preset.get(OUTER_DIAMETER) / 2.0;
247 innerRadius = preset.get(INNER_DIAMETER) / 2.0;
248 thickness = outerRadius - innerRadius;
249 } else if (hasThickness) {
250 thickness = preset.get(THICKNESS);
251 innerRadius = outerRadius - thickness;
253 exceptions.addMessage("Preset dimensions underspecified");
257 if (!hasId || !hasThickness) {
258 exceptions.addMessage("Preset dimensions underspecified");
261 innerRadius = preset.get(INNER_DIAMETER) / 2.0;
262 thickness = preset.get(THICKNESS);
263 outerRadius = innerRadius + thickness;
266 preset.put(OUTER_DIAMETER, outerRadius * 2.0);
267 preset.put(INNER_DIAMETER, innerRadius * 2.0);
268 preset.put(THICKNESS, thickness);
272 private static double computeVolumeOfTube(ComponentPreset preset) {
273 double or = preset.get(OUTER_DIAMETER) / 2.0;
274 double ir = preset.has(INNER_DIAMETER) ? preset.get(INNER_DIAMETER) / 2.0 : 0.0;
275 double l = preset.get(LENGTH);
276 return Math.PI * (or * or - ir * ir) * l;