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; } }