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