7c4b2b9a0fac3f807b58e145458d31dce82cf94f
[debian/openrocket] / core / src / net / sf / openrocket / preset / ComponentPresetFactory.java
1 package net.sf.openrocket.preset;
2
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;
8
9 public abstract class ComponentPresetFactory {
10
11         public static ComponentPreset create( TypedPropertyMap props ) throws InvalidComponentPresetException {
12
13                 InvalidComponentPresetException exceptions = new InvalidComponentPresetException("Invalid preset specification.");
14                 
15                 ComponentPreset preset = new ComponentPreset();
16                 // First do validation.
17                 if (!props.containsKey(MANUFACTURER)) {
18                         exceptions.addInvalidParameter(MANUFACTURER, "No Manufacturer specified"); 
19                 }
20                 if (!props.containsKey(PARTNO)) {
21                         exceptions.addInvalidParameter(PARTNO,"No PartNo specified");
22                 }
23                 if ( !props.containsKey(TYPE)) {
24                         exceptions.addInvalidParameter(TYPE, "No Type specified" );
25                         // We can't do anything else without TYPE so throw immediately.
26                         throw exceptions;
27                 }
28
29
30                 preset.putAll(props);
31
32                 // Should check for various bits of each of the types.
33                 Type t = props.get(TYPE);
34                 switch ( t ) {
35                 case BODY_TUBE: {
36                         makeBodyTube(exceptions,preset);
37                         break;
38                 }
39                 case NOSE_CONE: {
40                         makeNoseCone(exceptions,preset);
41                         break;
42                 }
43                 case TRANSITION: {
44                         makeTransition(exceptions,preset);
45                         break;
46                 }
47                 case BULK_HEAD: {
48                         makeBulkHead(exceptions,preset);
49                         break;
50                 }
51                 case TUBE_COUPLER: {
52                         // For now TUBE_COUPLER is the same as BODY_TUBE
53                         makeBodyTube(exceptions,preset);
54                         break;
55                 }
56                 case CENTERING_RING: {
57                         makeCenteringRing(exceptions,preset);
58                         break;
59                 }
60                 case ENGINE_BLOCK: {
61                         makeEngineBlock(exceptions,preset);
62                         break;
63                 }
64                 case LAUNCH_LUG: {
65                         // Same processing as BODY_TUBE
66                         makeBodyTube(exceptions,preset);
67                         break;
68                 }
69                 case STREAMER: {
70                         makeStreamer(exceptions,preset);
71                         break;
72                 }
73                 case PARACHUTE: {
74                         makeParachute(exceptions,preset);
75                         break;
76                 }
77                 }
78
79                 if ( exceptions.hasProblems() ) {
80                         throw exceptions;
81                 }
82                 
83                 preset.computeDigest();
84
85                 return preset;
86
87         }
88
89         private static void makeBodyTube( InvalidComponentPresetException exceptions, ComponentPreset preset ) throws InvalidComponentPresetException {
90                 
91                 checkRequiredFields( exceptions, preset, LENGTH );
92
93                 checkDiametersAndThickness(exceptions, preset);
94                 
95                 double volume = computeVolumeOfTube( preset );
96                 
97                 // Need to translate Mass to Density.
98                 if ( preset.has(MASS) ) {
99                         String materialName = "TubeCustom";
100                         if ( preset.has(MATERIAL) ) {
101                                 materialName = preset.get(MATERIAL).getName();
102                         }
103                         Material m = Material.newUserMaterial(Material.Type.BULK, materialName, preset.get(MASS)/volume);
104                         preset.put(MATERIAL, m);
105                 }
106
107
108         }
109
110         private static void makeNoseCone( InvalidComponentPresetException exceptions, ComponentPreset preset ) {
111
112                 checkRequiredFields( exceptions, preset, LENGTH, SHAPE, AFT_OUTER_DIAMETER );
113
114                 if ( preset.has(MASS) ) {
115                         // compute a density for this component
116                         double mass = preset.get(MASS);
117                         NoseCone nc = new NoseCone();
118                         nc.loadPreset(preset);
119                         double density = mass / nc.getComponentVolume();
120
121                         String materialName = "NoseConeCustom";
122                         if ( preset.has(MATERIAL) ) {
123                                 materialName = preset.get(MATERIAL).getName();
124                         }
125
126                         Material m = Material.newUserMaterial(Material.Type.BULK, materialName,density);
127                         preset.put(MATERIAL, m);
128
129                 }
130
131         }
132
133         private static void makeTransition( InvalidComponentPresetException exceptions, ComponentPreset preset ) {
134                 checkRequiredFields(exceptions, preset, LENGTH, AFT_OUTER_DIAMETER, FORE_OUTER_DIAMETER);
135
136                 if ( preset.has(MASS) ) {
137                         // compute a density for this component
138                         double mass = preset.get(MASS);
139                         Transition tr = new Transition();
140                         tr.loadPreset(preset);
141                         double density = mass / tr.getComponentVolume();
142
143                         String materialName = "TransitionCustom";
144                         if ( preset.has(MATERIAL) ) {
145                                 materialName = preset.get(MATERIAL).getName();
146                         }
147
148                         Material m = Material.newUserMaterial(Material.Type.BULK, materialName,density);
149                         preset.put(MATERIAL, m);
150
151                 }
152
153         }
154
155         private static void makeBulkHead( InvalidComponentPresetException exceptions, ComponentPreset preset ) {
156                 checkRequiredFields(exceptions, preset, LENGTH, OUTER_DIAMETER );
157
158                 if ( preset.has(MASS) ) {
159                         // compute a density for this component
160                         double mass = preset.get(MASS);
161
162                         double volume = computeVolumeOfTube(preset);
163                         double density = mass / volume;
164
165                         String materialName = "BulkHeadCustom";
166                         if ( preset.has(MATERIAL) ) {
167                                 materialName = preset.get(MATERIAL).getName();
168                         }
169
170                         Material m = Material.newUserMaterial(Material.Type.BULK, materialName,density);
171                         preset.put(MATERIAL, m);
172
173                 }
174
175         }
176
177         private static void makeCenteringRing( InvalidComponentPresetException exceptions, ComponentPreset preset ) throws InvalidComponentPresetException {
178                 checkRequiredFields( exceptions, preset, LENGTH );
179
180                 checkDiametersAndThickness( exceptions, preset );
181
182                 double volume = computeVolumeOfTube( preset );
183
184                 // Need to translate Mass to Density.
185                 if ( preset.has(MASS) ) {
186                         String materialName = "CenteringRingCustom";
187                         if ( preset.has(MATERIAL) ) {
188                                 materialName = preset.get(MATERIAL).getName();
189                         }
190                         Material m = Material.newUserMaterial(Material.Type.BULK, materialName, preset.get(MASS)/volume);
191                         preset.put(MATERIAL, m);
192                 }
193
194         }
195         
196         private static void makeEngineBlock( InvalidComponentPresetException exceptions, ComponentPreset preset ) throws InvalidComponentPresetException {
197                 checkRequiredFields( exceptions, preset, LENGTH );
198
199                 checkDiametersAndThickness( exceptions, preset );
200
201                 double volume = computeVolumeOfTube( preset );
202
203                 // Need to translate Mass to Density.
204                 if ( preset.has(MASS) ) {
205                         String materialName = "EngineBlockCustom";
206                         if ( preset.has(MATERIAL) ) {
207                                 materialName = preset.get(MATERIAL).getName();
208                         }
209                         Material m = Material.newUserMaterial(Material.Type.BULK, materialName, preset.get(MASS)/volume);
210                         preset.put(MATERIAL, m);
211                 }
212
213         }
214         
215         private static void makeStreamer( InvalidComponentPresetException exceptions, ComponentPreset preset ) {
216                 checkRequiredFields( exceptions, preset, LENGTH, WIDTH );
217         }
218
219         private static void makeParachute( InvalidComponentPresetException exceptions, ComponentPreset preset ) {
220                 checkRequiredFields( exceptions, preset, DIAMETER, LINE_COUNT, LINE_LENGTH );
221         }
222         
223
224         private static void checkRequiredFields( InvalidComponentPresetException exceptions, ComponentPreset preset, TypedKey<?> ... keys ) {
225                 for( TypedKey<?> key: keys ) {
226                         if (! preset.has(key) ) {
227                                 exceptions.addInvalidParameter(key, "No " + key.getName() + " specified");
228                         }
229                 }
230         }
231
232         private static void checkDiametersAndThickness( InvalidComponentPresetException exceptions, ComponentPreset preset ) throws InvalidComponentPresetException {
233                 // Need to verify contains 2 of OD, thickness, ID.  Compute the third.
234                 boolean hasOd = preset.has(OUTER_DIAMETER);
235                 boolean hasId = preset.has(INNER_DIAMETER);
236                 boolean hasThickness = preset.has(THICKNESS);
237
238                 double outerRadius;
239                 double innerRadius;
240                 double thickness;
241                 
242                 if ( hasOd ) {
243                         outerRadius = preset.get(OUTER_DIAMETER)/2.0;
244                         thickness = 0;
245                         if ( hasId ) {
246                                 innerRadius = preset.get(INNER_DIAMETER)/2.0;
247                                 thickness = outerRadius - innerRadius;
248                         } else if ( hasThickness ) {
249                                 thickness = preset.get(THICKNESS);
250                                 innerRadius = outerRadius - thickness;
251                         } else {
252                                 exceptions.addMessage("Preset dimensions underspecified");
253                                 throw exceptions;
254                         }
255                 } else {
256                         if ( ! hasId || ! hasThickness ) {
257                                 exceptions.addMessage("Preset dimensions underspecified");
258                                 throw exceptions;
259                         }
260                         innerRadius = preset.get(INNER_DIAMETER)/2.0;
261                         thickness = preset.get(THICKNESS);
262                         outerRadius = innerRadius + thickness;
263                 }
264
265                 preset.put(OUTER_DIAMETER, outerRadius *2.0);
266                 preset.put(INNER_DIAMETER, innerRadius *2.0);
267                 preset.put(THICKNESS, thickness );
268
269         }
270         
271         private static double computeVolumeOfTube(ComponentPreset preset) {
272                 double or = preset.get(OUTER_DIAMETER)/2.0;
273                 double ir = preset.has(INNER_DIAMETER) ? preset.get(INNER_DIAMETER)/2.0 : 0.0;
274                 double l = preset.get(LENGTH);
275                 return Math.PI * (or*or - ir*ir) * l;
276         }
277
278         
279 }