Merge commit '42b2e5ca519766e37ce6941ba4faecc9691cc403' into upstream
[debian/openrocket] / core / src / net / sf / openrocket / preset / ComponentPresetFactory.java
diff --git a/core/src/net/sf/openrocket/preset/ComponentPresetFactory.java b/core/src/net/sf/openrocket/preset/ComponentPresetFactory.java
new file mode 100644 (file)
index 0000000..7d2677b
--- /dev/null
@@ -0,0 +1,280 @@
+package net.sf.openrocket.preset;
+
+import static net.sf.openrocket.preset.ComponentPreset.*;
+import net.sf.openrocket.database.Databases;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.ComponentPreset.Type;
+import net.sf.openrocket.rocketcomponent.NoseCone;
+import net.sf.openrocket.rocketcomponent.Transition;
+
+public abstract class ComponentPresetFactory {
+       
+       public static ComponentPreset create(TypedPropertyMap props) throws InvalidComponentPresetException {
+               
+               InvalidComponentPresetException exceptions = new InvalidComponentPresetException("Invalid preset specification.");
+               
+               ComponentPreset preset = new ComponentPreset();
+               // First do validation.
+               if (!props.containsKey(MANUFACTURER)) {
+                       exceptions.addInvalidParameter(MANUFACTURER, "No Manufacturer specified");
+               }
+               if (!props.containsKey(PARTNO)) {
+                       exceptions.addInvalidParameter(PARTNO, "No PartNo specified");
+               }
+               if (!props.containsKey(TYPE)) {
+                       exceptions.addInvalidParameter(TYPE, "No Type specified");
+                       // We can't do anything else without TYPE so throw immediately.
+                       throw exceptions;
+               }
+               
+               
+               preset.putAll(props);
+               
+               // Should check for various bits of each of the types.
+               Type t = props.get(TYPE);
+               switch (t) {
+               case BODY_TUBE: {
+                       makeBodyTube(exceptions, preset);
+                       break;
+               }
+               case NOSE_CONE: {
+                       makeNoseCone(exceptions, preset);
+                       break;
+               }
+               case TRANSITION: {
+                       makeTransition(exceptions, preset);
+                       break;
+               }
+               case BULK_HEAD: {
+                       makeBulkHead(exceptions, preset);
+                       break;
+               }
+               case TUBE_COUPLER: {
+                       // For now TUBE_COUPLER is the same as BODY_TUBE
+                       makeBodyTube(exceptions, preset);
+                       break;
+               }
+               case CENTERING_RING: {
+                       makeCenteringRing(exceptions, preset);
+                       break;
+               }
+               case ENGINE_BLOCK: {
+                       makeEngineBlock(exceptions, preset);
+                       break;
+               }
+               case LAUNCH_LUG: {
+                       // Same processing as BODY_TUBE
+                       makeBodyTube(exceptions, preset);
+                       break;
+               }
+               case STREAMER: {
+                       makeStreamer(exceptions, preset);
+                       break;
+               }
+               case PARACHUTE: {
+                       makeParachute(exceptions, preset);
+                       break;
+               }
+               }
+               
+               if (exceptions.hasProblems()) {
+                       throw exceptions;
+               }
+               
+               preset.computeDigest();
+               
+               return preset;
+               
+       }
+       
+       private static void makeBodyTube(InvalidComponentPresetException exceptions, ComponentPreset preset) throws InvalidComponentPresetException {
+               
+               checkRequiredFields(exceptions, preset, LENGTH);
+               
+               checkDiametersAndThickness(exceptions, preset);
+               
+               double volume = computeVolumeOfTube(preset);
+               
+               // Need to translate Mass to Density.
+               if (preset.has(MASS)) {
+                       String materialName = "TubeCustom";
+                       if (preset.has(MATERIAL)) {
+                               materialName = preset.get(MATERIAL).getName();
+                       }
+                       Material m = Databases.findMaterial(Material.Type.BULK, materialName, preset.get(MASS) / volume);
+                       preset.put(MATERIAL, m);
+               }
+               
+               
+       }
+       
+       private static void makeNoseCone(InvalidComponentPresetException exceptions, ComponentPreset preset) {
+               
+               checkRequiredFields(exceptions, preset, LENGTH, SHAPE, AFT_OUTER_DIAMETER);
+               
+               if (preset.has(MASS)) {
+                       // compute a density for this component
+                       double mass = preset.get(MASS);
+                       NoseCone nc = new NoseCone();
+                       nc.loadPreset(preset);
+                       double density = mass / nc.getComponentVolume();
+                       
+                       String materialName = "NoseConeCustom";
+                       if (preset.has(MATERIAL)) {
+                               materialName = preset.get(MATERIAL).getName();
+                       }
+                       
+                       Material m = Databases.findMaterial(Material.Type.BULK, materialName, density);
+                       preset.put(MATERIAL, m);
+                       
+               }
+               
+       }
+       
+       private static void makeTransition(InvalidComponentPresetException exceptions, ComponentPreset preset) {
+               checkRequiredFields(exceptions, preset, LENGTH, AFT_OUTER_DIAMETER, FORE_OUTER_DIAMETER);
+               
+               if (preset.has(MASS)) {
+                       // compute a density for this component
+                       double mass = preset.get(MASS);
+                       Transition tr = new Transition();
+                       tr.loadPreset(preset);
+                       double density = mass / tr.getComponentVolume();
+                       
+                       String materialName = "TransitionCustom";
+                       if (preset.has(MATERIAL)) {
+                               materialName = preset.get(MATERIAL).getName();
+                       }
+                       
+                       Material m = Databases.findMaterial(Material.Type.BULK, materialName, density);
+                       preset.put(MATERIAL, m);
+                       
+               }
+               
+       }
+       
+       private static void makeBulkHead(InvalidComponentPresetException exceptions, ComponentPreset preset) {
+               checkRequiredFields(exceptions, preset, LENGTH, OUTER_DIAMETER);
+               
+               if (preset.has(MASS)) {
+                       // compute a density for this component
+                       double mass = preset.get(MASS);
+                       
+                       double volume = computeVolumeOfTube(preset);
+                       double density = mass / volume;
+                       
+                       String materialName = "BulkHeadCustom";
+                       if (preset.has(MATERIAL)) {
+                               materialName = preset.get(MATERIAL).getName();
+                       }
+                       
+                       Material m = Databases.findMaterial(Material.Type.BULK, materialName, density);
+                       preset.put(MATERIAL, m);
+                       
+               }
+               
+       }
+       
+       private static void makeCenteringRing(InvalidComponentPresetException exceptions, ComponentPreset preset) throws InvalidComponentPresetException {
+               checkRequiredFields(exceptions, preset, LENGTH);
+               
+               checkDiametersAndThickness(exceptions, preset);
+               
+               double volume = computeVolumeOfTube(preset);
+               
+               // Need to translate Mass to Density.
+               if (preset.has(MASS)) {
+                       String materialName = "CenteringRingCustom";
+                       if (preset.has(MATERIAL)) {
+                               materialName = preset.get(MATERIAL).getName();
+                       }
+                       Material m = Databases.findMaterial(Material.Type.BULK, materialName, preset.get(MASS) / volume);
+                       preset.put(MATERIAL, m);
+               }
+               
+       }
+       
+       private static void makeEngineBlock(InvalidComponentPresetException exceptions, ComponentPreset preset) throws InvalidComponentPresetException {
+               checkRequiredFields(exceptions, preset, LENGTH);
+               
+               checkDiametersAndThickness(exceptions, preset);
+               
+               double volume = computeVolumeOfTube(preset);
+               
+               // Need to translate Mass to Density.
+               if (preset.has(MASS)) {
+                       String materialName = "EngineBlockCustom";
+                       if (preset.has(MATERIAL)) {
+                               materialName = preset.get(MATERIAL).getName();
+                       }
+                       Material m = Databases.findMaterial(Material.Type.BULK, materialName, preset.get(MASS) / volume);
+                       preset.put(MATERIAL, m);
+               }
+               
+       }
+       
+       private static void makeStreamer(InvalidComponentPresetException exceptions, ComponentPreset preset) {
+               checkRequiredFields(exceptions, preset, LENGTH, WIDTH);
+       }
+       
+       private static void makeParachute(InvalidComponentPresetException exceptions, ComponentPreset preset) {
+               checkRequiredFields(exceptions, preset, DIAMETER, LINE_COUNT, LINE_LENGTH);
+       }
+       
+       
+       private static void checkRequiredFields(InvalidComponentPresetException exceptions, ComponentPreset preset, TypedKey<?>... keys) {
+               for (TypedKey<?> key : keys) {
+                       if (!preset.has(key)) {
+                               exceptions.addInvalidParameter(key, "No " + key.getName() + " specified");
+                       }
+               }
+       }
+       
+       private static void checkDiametersAndThickness(InvalidComponentPresetException exceptions, ComponentPreset preset) throws InvalidComponentPresetException {
+               // Need to verify contains 2 of OD, thickness, ID.  Compute the third.
+               boolean hasOd = preset.has(OUTER_DIAMETER);
+               boolean hasId = preset.has(INNER_DIAMETER);
+               boolean hasThickness = preset.has(THICKNESS);
+               
+               double outerRadius;
+               double innerRadius;
+               double thickness;
+               
+               if (hasOd) {
+                       outerRadius = preset.get(OUTER_DIAMETER) / 2.0;
+                       thickness = 0;
+                       if (hasId) {
+                               innerRadius = preset.get(INNER_DIAMETER) / 2.0;
+                               thickness = outerRadius - innerRadius;
+                       } else if (hasThickness) {
+                               thickness = preset.get(THICKNESS);
+                               innerRadius = outerRadius - thickness;
+                       } else {
+                               exceptions.addMessage("Preset dimensions underspecified");
+                               throw exceptions;
+                       }
+               } else {
+                       if (!hasId || !hasThickness) {
+                               exceptions.addMessage("Preset dimensions underspecified");
+                               throw exceptions;
+                       }
+                       innerRadius = preset.get(INNER_DIAMETER) / 2.0;
+                       thickness = preset.get(THICKNESS);
+                       outerRadius = innerRadius + thickness;
+               }
+               
+               preset.put(OUTER_DIAMETER, outerRadius * 2.0);
+               preset.put(INNER_DIAMETER, innerRadius * 2.0);
+               preset.put(THICKNESS, thickness);
+               
+       }
+       
+       private static double computeVolumeOfTube(ComponentPreset preset) {
+               double or = preset.get(OUTER_DIAMETER) / 2.0;
+               double ir = preset.has(INNER_DIAMETER) ? preset.get(INNER_DIAMETER) / 2.0 : 0.0;
+               double l = preset.get(LENGTH);
+               return Math.PI * (or * or - ir * ir) * l;
+       }
+       
+       
+}