import java.util.Map;
import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.document.Simulation;
import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.optimization.general.OptimizationException;
import net.sf.openrocket.optimization.rocketoptimization.SimulationModifier;
import net.sf.openrocket.optimization.rocketoptimization.modifiers.GenericComponentModifier;
import net.sf.openrocket.rocketcomponent.BodyTube;
+import net.sf.openrocket.rocketcomponent.EllipticalFinSet;
+import net.sf.openrocket.rocketcomponent.FinSet;
+import net.sf.openrocket.rocketcomponent.FreeformFinSet;
+import net.sf.openrocket.rocketcomponent.InternalComponent;
+import net.sf.openrocket.rocketcomponent.LaunchLug;
+import net.sf.openrocket.rocketcomponent.MassComponent;
+import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.NoseCone;
+import net.sf.openrocket.rocketcomponent.Parachute;
+import net.sf.openrocket.rocketcomponent.RecoveryDevice;
+import net.sf.openrocket.rocketcomponent.RecoveryDevice.DeployEvent;
import net.sf.openrocket.rocketcomponent.Rocket;
import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.Streamer;
import net.sf.openrocket.rocketcomponent.Transition;
+import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.util.BugException;
+import net.sf.openrocket.util.Reflection;
+import net.sf.openrocket.util.Reflection.Method;
public class DefaultSimulationModifierService implements SimulationModifierService {
private static final Translator trans = Application.getTranslator();
+ private static final double DEFAULT_RANGE_MULTIPLIER = 2.0;
+
+
private static final Map<Class<?>, List<ModifierDefinition>> definitions = new HashMap<Class<?>, List<ModifierDefinition>>();
static {
//addModifier("optimization.modifier.", unitGroup, multiplier, componentClass, methodName);
*/
addModifier("optimization.modifier.nosecone.length", UnitGroup.UNITS_LENGTH, 1.0, NoseCone.class, "Length");
- addModifier("optimization.modifier.nosecone.diameter", UnitGroup.UNITS_LENGTH, 2.0, NoseCone.class, "AftRadius");
- addModifier("optimization.modifier.nosecone.thickness", UnitGroup.UNITS_LENGTH, 1.0, NoseCone.class, "Thickness");
+ addModifier("optimization.modifier.nosecone.diameter", UnitGroup.UNITS_LENGTH, 2.0, NoseCone.class, "AftRadius", "isAftRadiusAutomatic");
+ addModifier("optimization.modifier.nosecone.thickness", UnitGroup.UNITS_LENGTH, 1.0, NoseCone.class, "Thickness", "isFilled");
addModifier("optimization.modifier.transition.length", UnitGroup.UNITS_LENGTH, 1.0, Transition.class, "Length");
- addModifier("optimization.modifier.transition.forediameter", UnitGroup.UNITS_LENGTH, 2.0, Transition.class, "ForeRadius");
- addModifier("optimization.modifier.transition.aftdiameter", UnitGroup.UNITS_LENGTH, 2.0, Transition.class, "AftRadius");
- addModifier("optimization.modifier.transition.thickness", UnitGroup.UNITS_LENGTH, 1.0, Transition.class, "Thickness");
+ addModifier("optimization.modifier.transition.forediameter", UnitGroup.UNITS_LENGTH, 2.0, Transition.class, "ForeRadius", "isForeRadiusAutomatic");
+ addModifier("optimization.modifier.transition.aftdiameter", UnitGroup.UNITS_LENGTH, 2.0, Transition.class, "AftRadius", "isAftRadiusAutomatic");
+ addModifier("optimization.modifier.transition.thickness", UnitGroup.UNITS_LENGTH, 1.0, Transition.class, "Thickness", "isFilled");
addModifier("optimization.modifier.bodytube.length", UnitGroup.UNITS_LENGTH, 1.0, BodyTube.class, "Length");
- addModifier("optimization.modifier.bodytube.outerDiameter", UnitGroup.UNITS_LENGTH, 2.0, BodyTube.class, "OuterRadius");
- addModifier("optimization.modifier.bodytube.thickness", UnitGroup.UNITS_LENGTH, 1.0, BodyTube.class, "Thickness");
+ addModifier("optimization.modifier.bodytube.outerDiameter", UnitGroup.UNITS_LENGTH, 2.0, BodyTube.class, "OuterRadius", "isOuterRadiusAutomatic");
+ addModifier("optimization.modifier.bodytube.thickness", UnitGroup.UNITS_LENGTH, 1.0, BodyTube.class, "Thickness", "isFilled");
+
+ addModifier("optimization.modifier.trapezoidfinset.rootChord", UnitGroup.UNITS_LENGTH, 1.0, TrapezoidFinSet.class, "RootChord");
+ addModifier("optimization.modifier.trapezoidfinset.tipChord", UnitGroup.UNITS_LENGTH, 1.0, TrapezoidFinSet.class, "TipChord");
+ addModifier("optimization.modifier.trapezoidfinset.sweep", UnitGroup.UNITS_LENGTH, 1.0, TrapezoidFinSet.class, "Sweep");
+ addModifier("optimization.modifier.trapezoidfinset.height", UnitGroup.UNITS_LENGTH, 1.0, TrapezoidFinSet.class, "Height");
+ addModifier("optimization.modifier.finset.cant", UnitGroup.UNITS_ANGLE, 1.0, TrapezoidFinSet.class, "CantAngle");
+
+ addModifier("optimization.modifier.ellipticalfinset.length", UnitGroup.UNITS_LENGTH, 1.0, EllipticalFinSet.class, "Length");
+ addModifier("optimization.modifier.ellipticalfinset.height", UnitGroup.UNITS_LENGTH, 1.0, EllipticalFinSet.class, "Height");
+ addModifier("optimization.modifier.finset.cant", UnitGroup.UNITS_ANGLE, 1.0, EllipticalFinSet.class, "CantAngle");
+
+ addModifier("optimization.modifier.finset.cant", UnitGroup.UNITS_ANGLE, 1.0, FreeformFinSet.class, "CantAngle");
+
+ addModifier("optimization.modifier.launchlug.length", UnitGroup.UNITS_LENGTH, 1.0, LaunchLug.class, "Length");
+ addModifier("optimization.modifier.launchlug.outerDiameter", UnitGroup.UNITS_LENGTH, 2.0, LaunchLug.class, "OuterRadius");
+ addModifier("optimization.modifier.launchlug.thickness", UnitGroup.UNITS_LENGTH, 1.0, LaunchLug.class, "Thickness");
+ addModifier("optimization.modifier.masscomponent.mass", UnitGroup.UNITS_MASS, 1.0, MassComponent.class, "ComponentMass");
+
+ addModifier("optimization.modifier.parachute.diameter", UnitGroup.UNITS_LENGTH, 1.0, Parachute.class, "Diameter");
+ addModifier("optimization.modifier.parachute.coefficient", UnitGroup.UNITS_NONE, 1.0, Parachute.class, "CD");
+
+ addModifier("optimization.modifier.streamer.length", UnitGroup.UNITS_LENGTH, 1.0, Streamer.class, "StripLength");
+ addModifier("optimization.modifier.streamer.width", UnitGroup.UNITS_LENGTH, 1.0, Streamer.class, "StripWidth");
+ addModifier("optimization.modifier.streamer.aspectRatio", UnitGroup.UNITS_NONE, 1.0, Streamer.class, "AspectRatio");
+ addModifier("optimization.modifier.streamer.coefficient", UnitGroup.UNITS_NONE, 1.0, Streamer.class, "CD", "isCDAutomatic");
+
+ }
+
+ private static void addModifier(String modifierNameKey, UnitGroup unitGroup, double multiplier,
+ Class<? extends RocketComponent> componentClass, String methodName) {
+ addModifier(modifierNameKey, unitGroup, multiplier, componentClass, methodName, null);
}
private static void addModifier(String modifierNameKey, UnitGroup unitGroup, double multiplier,
- Class<? extends RocketComponent> componentClass, String methodName) {
+ Class<? extends RocketComponent> componentClass, String methodName, String autoMethod) {
+
+ String modifierDescriptionKey = modifierNameKey + ".desc";
List<ModifierDefinition> list = definitions.get(componentClass);
if (list == null) {
definitions.put(componentClass, list);
}
- ModifierDefinition definition = new ModifierDefinition(modifierNameKey, unitGroup, multiplier, componentClass, methodName);
+ ModifierDefinition definition = new ModifierDefinition(modifierNameKey, modifierDescriptionKey, unitGroup,
+ multiplier, componentClass, methodName, autoMethod);
list.add(definition);
}
List<SimulationModifier> modifiers = new ArrayList<SimulationModifier>();
Rocket rocket = document.getRocket();
+
+ // Simulation is used to calculate default min/max values
+ Simulation simulation = new Simulation(rocket);
+ simulation.getConfiguration().setMotorConfigurationID(null);
+
for (RocketComponent c : rocket) {
// Attribute modifiers
List<ModifierDefinition> list = definitions.get(c.getClass());
if (list != null) {
for (ModifierDefinition def : list) {
+
+ // Ignore modifier if value is set to automatic
+ if (def.autoMethod != null) {
+ Method m = Reflection.findMethod(c.getClass(), def.autoMethod);
+ if ((Boolean) m.invoke(c)) {
+ continue;
+ }
+ }
+
SimulationModifier mod = new GenericComponentModifier(
- trans.get(def.modifierNameKey), c, def.unitGroup, def.multiplier, def.componentClass,
- c.getID(), def.methodName);
+ trans.get(def.modifierNameKey), trans.get(def.modifierDescriptionKey), c, def.unitGroup,
+ def.multiplier, def.componentClass, c.getID(), def.methodName);
+ setDefaultMinMax(mod, simulation);
modifiers.add(mod);
}
}
- // TODO: HIGH: Conditional modifiers (overrides)
+
+ // Add override modifiers if mass/CG is overridden
+ if (c.isMassOverridden()) {
+ SimulationModifier mod = new GenericComponentModifier(
+ trans.get("optimization.modifier.rocketcomponent.overrideMass"),
+ trans.get("optimization.modifier.rocketcomponent.overrideMass.desc"),
+ c, UnitGroup.UNITS_MASS,
+ 1.0, c.getClass(), c.getID(), "OverrideMass");
+ setDefaultMinMax(mod, simulation);
+ modifiers.add(mod);
+ }
+ if (c.isCGOverridden()) {
+ SimulationModifier mod = new GenericComponentModifier(
+ trans.get("optimization.modifier.rocketcomponent.overrideCG"),
+ trans.get("optimization.modifier.rocketcomponent.overrideCG.desc"),
+ c, UnitGroup.UNITS_LENGTH,
+ 1.0, c.getClass(), c.getID(), "OverrideCGX");
+ mod.setMinValue(0);
+ mod.setMaxValue(c.getLength());
+ modifiers.add(mod);
+ }
+
+
+ // Conditional motor mount parameters
+ if (c instanceof MotorMount) {
+ MotorMount mount = (MotorMount) c;
+ if (mount.isMotorMount()) {
+
+ SimulationModifier mod = new GenericComponentModifier(
+ trans.get("optimization.modifier.motormount.overhang"),
+ trans.get("optimization.modifier.motormount.overhang.desc"),
+ c, UnitGroup.UNITS_LENGTH,
+ 1.0, c.getClass(), c.getID(), "MotorOverhang");
+ setDefaultMinMax(mod, simulation);
+ modifiers.add(mod);
+
+ mod = new GenericComponentModifier(
+ trans.get("optimization.modifier.motormount.delay"),
+ trans.get("optimization.modifier.motormount.delay.desc"),
+ c, UnitGroup.UNITS_SHORT_TIME,
+ 1.0, c.getClass(), c.getID(), "IgnitionDelay");
+ mod.setMinValue(0);
+ mod.setMaxValue(5);
+ modifiers.add(mod);
+
+ }
+ }
- // TODO: Transition / Nose cone shape parameter (conditional)
+
+ // Inner component positioning
+ if (c instanceof InternalComponent) {
+ RocketComponent parent = c.getParent();
+ SimulationModifier mod = new GenericComponentModifier(
+ trans.get("optimization.modifier.internalcomponent.position"),
+ trans.get("optimization.modifier.internalcomponent.position.desc"),
+ c, UnitGroup.UNITS_LENGTH,
+ 1.0, c.getClass(), c.getID(), "PositionValue");
+ mod.setMinValue(0);
+ mod.setMaxValue(parent.getLength());
+ modifiers.add(mod);
+ }
+
+
+ // Custom min/max for fin set position
+ if (c instanceof FinSet) {
+ RocketComponent parent = c.getParent();
+ SimulationModifier mod = new GenericComponentModifier(
+ trans.get("optimization.modifier.finset.position"),
+ trans.get("optimization.modifier.finset.position.desc"),
+ c, UnitGroup.UNITS_LENGTH,
+ 1.0, c.getClass(), c.getID(), "PositionValue");
+ mod.setMinValue(0);
+ mod.setMaxValue(parent.getLength());
+ modifiers.add(mod);
+ }
+
+
+ // Custom min/max for launch lug position
+ if (c instanceof LaunchLug) {
+ RocketComponent parent = c.getParent();
+ SimulationModifier mod = new GenericComponentModifier(
+ trans.get("optimization.modifier.launchlug.position"),
+ trans.get("optimization.modifier.launchlug.position.desc"),
+ c, UnitGroup.UNITS_LENGTH,
+ 1.0, c.getClass(), c.getID(), "PositionValue");
+ mod.setMinValue(0);
+ mod.setMaxValue(parent.getLength());
+ modifiers.add(mod);
+ }
+
+
+ // Recovery device deployment altitude and delay
+ if (c instanceof RecoveryDevice) {
+ RecoveryDevice device = (RecoveryDevice) c;
+
+ SimulationModifier mod = new GenericComponentModifier(
+ trans.get("optimization.modifier.recoverydevice.deployDelay"),
+ trans.get("optimization.modifier.recoverydevice.deployDelay.desc"),
+ c, UnitGroup.UNITS_SHORT_TIME,
+ 1.0, c.getClass(), c.getID(), "DeployDelay");
+ mod.setMinValue(0);
+ mod.setMaxValue(10);
+ modifiers.add(mod);
+
+ if (device.getDeployEvent() == DeployEvent.ALTITUDE) {
+ mod = new GenericComponentModifier(
+ trans.get("optimization.modifier.recoverydevice.deployAltitude"),
+ trans.get("optimization.modifier.recoverydevice.deployAltitude.desc"),
+ c, UnitGroup.UNITS_DISTANCE,
+ 1.0, c.getClass(), c.getID(), "DeployAltitude");
+ setDefaultMinMax(mod, simulation);
+ modifiers.add(mod);
+ }
+ }
+
+
+ // Conditional shape parameter of Transition
+ if (c instanceof Transition) {
+ Transition transition = (Transition) c;
+ Transition.Shape shape = transition.getType();
+ if (shape.usesParameter()) {
+ SimulationModifier mod = new GenericComponentModifier(
+ trans.get("optimization.modifier." + c.getClass().getSimpleName().toLowerCase() + ".shapeparameter"),
+ trans.get("optimization.modifier." + c.getClass().getSimpleName().toLowerCase() + ".shapeparameter.desc"),
+ c, UnitGroup.UNITS_NONE,
+ 1.0, c.getClass(), c.getID(), "ShapeParameter");
+ mod.setMinValue(shape.minParameter());
+ mod.setMaxValue(shape.maxParameter());
+ modifiers.add(mod);
+ }
+ }
}
return modifiers;
}
-
+ private void setDefaultMinMax(SimulationModifier mod, Simulation simulation) {
+ try {
+ double current = mod.getCurrentSIValue(simulation);
+ mod.setMinValue(current / DEFAULT_RANGE_MULTIPLIER);
+ mod.setMaxValue(current * DEFAULT_RANGE_MULTIPLIER);
+ } catch (OptimizationException e) {
+ throw new BugException("Simulation modifier threw exception", e);
+ }
+ }
+
+
/*
* String modifierName, Object relatedObject, UnitGroup unitGroup,
double multiplier, Class<? extends RocketComponent> componentClass, String componentId, String methodName
private static class ModifierDefinition {
private final String modifierNameKey;
+ private final String modifierDescriptionKey;
private final UnitGroup unitGroup;
private final double multiplier;
private final Class<? extends RocketComponent> componentClass;
private final String methodName;
+ private final String autoMethod;
- public ModifierDefinition(String modifierNameKey, UnitGroup unitGroup, double multiplier,
- Class<? extends RocketComponent> componentClass, String methodName) {
- super();
+ public ModifierDefinition(String modifierNameKey, String modifierDescriptionKey, UnitGroup unitGroup,
+ double multiplier, Class<? extends RocketComponent> componentClass, String methodName, String autoMethod) {
this.modifierNameKey = modifierNameKey;
+ this.modifierDescriptionKey = modifierDescriptionKey;
this.unitGroup = unitGroup;
this.multiplier = multiplier;
this.componentClass = componentClass;
this.methodName = methodName;
+ this.autoMethod = autoMethod;
}
}