Material localization support
[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.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;
9
10 public abstract class ComponentPresetFactory {
11         
12         public static ComponentPreset create(TypedPropertyMap props) throws InvalidComponentPresetException {
13                 
14                 InvalidComponentPresetException exceptions = new InvalidComponentPresetException("Invalid preset specification.");
15                 
16                 ComponentPreset preset = new ComponentPreset();
17                 // First do validation.
18                 if (!props.containsKey(MANUFACTURER)) {
19                         exceptions.addInvalidParameter(MANUFACTURER, "No Manufacturer specified");
20                 }
21                 if (!props.containsKey(PARTNO)) {
22                         exceptions.addInvalidParameter(PARTNO, "No PartNo specified");
23                 }
24                 if (!props.containsKey(TYPE)) {
25                         exceptions.addInvalidParameter(TYPE, "No Type specified");
26                         // We can't do anything else without TYPE so throw immediately.
27                         throw exceptions;
28                 }
29                 
30                 
31                 preset.putAll(props);
32                 
33                 // Should check for various bits of each of the types.
34                 Type t = props.get(TYPE);
35                 switch (t) {
36                 case BODY_TUBE: {
37                         makeBodyTube(exceptions, preset);
38                         break;
39                 }
40                 case NOSE_CONE: {
41                         makeNoseCone(exceptions, preset);
42                         break;
43                 }
44                 case TRANSITION: {
45                         makeTransition(exceptions, preset);
46                         break;
47                 }
48                 case BULK_HEAD: {
49                         makeBulkHead(exceptions, preset);
50                         break;
51                 }
52                 case TUBE_COUPLER: {
53                         // For now TUBE_COUPLER is the same as BODY_TUBE
54                         makeBodyTube(exceptions, preset);
55                         break;
56                 }
57                 case CENTERING_RING: {
58                         makeCenteringRing(exceptions, preset);
59                         break;
60                 }
61                 case ENGINE_BLOCK: {
62                         makeEngineBlock(exceptions, preset);
63                         break;
64                 }
65                 case LAUNCH_LUG: {
66                         // Same processing as BODY_TUBE
67                         makeBodyTube(exceptions, preset);
68                         break;
69                 }
70                 case STREAMER: {
71                         makeStreamer(exceptions, preset);
72                         break;
73                 }
74                 case PARACHUTE: {
75                         makeParachute(exceptions, preset);
76                         break;
77                 }
78                 }
79                 
80                 if (exceptions.hasProblems()) {
81                         throw exceptions;
82                 }
83                 
84                 preset.computeDigest();
85                 
86                 return preset;
87                 
88         }
89         
90         private static void makeBodyTube(InvalidComponentPresetException exceptions, ComponentPreset preset) throws InvalidComponentPresetException {
91                 
92                 checkRequiredFields(exceptions, preset, LENGTH);
93                 
94                 checkDiametersAndThickness(exceptions, preset);
95                 
96                 double volume = computeVolumeOfTube(preset);
97                 
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();
103                         }
104                         Material m = Databases.findMaterial(Material.Type.BULK, materialName, preset.get(MASS) / volume);
105                         preset.put(MATERIAL, m);
106                 }
107                 
108                 
109         }
110         
111         private static void makeNoseCone(InvalidComponentPresetException exceptions, ComponentPreset preset) {
112                 
113                 checkRequiredFields(exceptions, preset, LENGTH, SHAPE, AFT_OUTER_DIAMETER);
114                 
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();
121                         
122                         String materialName = "NoseConeCustom";
123                         if (preset.has(MATERIAL)) {
124                                 materialName = preset.get(MATERIAL).getName();
125                         }
126                         
127                         Material m = Databases.findMaterial(Material.Type.BULK, materialName, density);
128                         preset.put(MATERIAL, m);
129                         
130                 }
131                 
132         }
133         
134         private static void makeTransition(InvalidComponentPresetException exceptions, ComponentPreset preset) {
135                 checkRequiredFields(exceptions, preset, LENGTH, AFT_OUTER_DIAMETER, FORE_OUTER_DIAMETER);
136                 
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();
143                         
144                         String materialName = "TransitionCustom";
145                         if (preset.has(MATERIAL)) {
146                                 materialName = preset.get(MATERIAL).getName();
147                         }
148                         
149                         Material m = Databases.findMaterial(Material.Type.BULK, materialName, density);
150                         preset.put(MATERIAL, m);
151                         
152                 }
153                 
154         }
155         
156         private static void makeBulkHead(InvalidComponentPresetException exceptions, ComponentPreset preset) {
157                 checkRequiredFields(exceptions, preset, LENGTH, OUTER_DIAMETER);
158                 
159                 if (preset.has(MASS)) {
160                         // compute a density for this component
161                         double mass = preset.get(MASS);
162                         
163                         double volume = computeVolumeOfTube(preset);
164                         double density = mass / volume;
165                         
166                         String materialName = "BulkHeadCustom";
167                         if (preset.has(MATERIAL)) {
168                                 materialName = preset.get(MATERIAL).getName();
169                         }
170                         
171                         Material m = Databases.findMaterial(Material.Type.BULK, materialName, density);
172                         preset.put(MATERIAL, m);
173                         
174                 }
175                 
176         }
177         
178         private static void makeCenteringRing(InvalidComponentPresetException exceptions, ComponentPreset preset) throws InvalidComponentPresetException {
179                 checkRequiredFields(exceptions, preset, LENGTH);
180                 
181                 checkDiametersAndThickness(exceptions, preset);
182                 
183                 double volume = computeVolumeOfTube(preset);
184                 
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();
190                         }
191                         Material m = Databases.findMaterial(Material.Type.BULK, materialName, preset.get(MASS) / volume);
192                         preset.put(MATERIAL, m);
193                 }
194                 
195         }
196         
197         private static void makeEngineBlock(InvalidComponentPresetException exceptions, ComponentPreset preset) throws InvalidComponentPresetException {
198                 checkRequiredFields(exceptions, preset, LENGTH);
199                 
200                 checkDiametersAndThickness(exceptions, preset);
201                 
202                 double volume = computeVolumeOfTube(preset);
203                 
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();
209                         }
210                         Material m = Databases.findMaterial(Material.Type.BULK, materialName, preset.get(MASS) / volume);
211                         preset.put(MATERIAL, m);
212                 }
213                 
214         }
215         
216         private static void makeStreamer(InvalidComponentPresetException exceptions, ComponentPreset preset) {
217                 checkRequiredFields(exceptions, preset, LENGTH, WIDTH);
218         }
219         
220         private static void makeParachute(InvalidComponentPresetException exceptions, ComponentPreset preset) {
221                 checkRequiredFields(exceptions, preset, DIAMETER, LINE_COUNT, LINE_LENGTH);
222         }
223         
224         
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");
229                         }
230                 }
231         }
232         
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);
238                 
239                 double outerRadius;
240                 double innerRadius;
241                 double thickness;
242                 
243                 if (hasOd) {
244                         outerRadius = preset.get(OUTER_DIAMETER) / 2.0;
245                         thickness = 0;
246                         if (hasId) {
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;
252                         } else {
253                                 exceptions.addMessage("Preset dimensions underspecified");
254                                 throw exceptions;
255                         }
256                 } else {
257                         if (!hasId || !hasThickness) {
258                                 exceptions.addMessage("Preset dimensions underspecified");
259                                 throw exceptions;
260                         }
261                         innerRadius = preset.get(INNER_DIAMETER) / 2.0;
262                         thickness = preset.get(THICKNESS);
263                         outerRadius = innerRadius + thickness;
264                 }
265                 
266                 preset.put(OUTER_DIAMETER, outerRadius * 2.0);
267                 preset.put(INNER_DIAMETER, innerRadius * 2.0);
268                 preset.put(THICKNESS, thickness);
269                 
270         }
271         
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;
277         }
278         
279         
280 }