1 package net.sf.openrocket.optimization.services;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashMap;
7 import java.util.Locale;
10 import net.sf.openrocket.document.OpenRocketDocument;
11 import net.sf.openrocket.document.Simulation;
12 import net.sf.openrocket.l10n.Translator;
13 import net.sf.openrocket.optimization.general.OptimizationException;
14 import net.sf.openrocket.optimization.rocketoptimization.SimulationModifier;
15 import net.sf.openrocket.optimization.rocketoptimization.modifiers.GenericComponentModifier;
16 import net.sf.openrocket.rocketcomponent.BodyTube;
17 import net.sf.openrocket.rocketcomponent.EllipticalFinSet;
18 import net.sf.openrocket.rocketcomponent.FinSet;
19 import net.sf.openrocket.rocketcomponent.FreeformFinSet;
20 import net.sf.openrocket.rocketcomponent.InternalComponent;
21 import net.sf.openrocket.rocketcomponent.LaunchLug;
22 import net.sf.openrocket.rocketcomponent.MassComponent;
23 import net.sf.openrocket.rocketcomponent.MotorMount;
24 import net.sf.openrocket.rocketcomponent.NoseCone;
25 import net.sf.openrocket.rocketcomponent.Parachute;
26 import net.sf.openrocket.rocketcomponent.RecoveryDevice;
27 import net.sf.openrocket.rocketcomponent.RecoveryDevice.DeployEvent;
28 import net.sf.openrocket.rocketcomponent.Rocket;
29 import net.sf.openrocket.rocketcomponent.RocketComponent;
30 import net.sf.openrocket.rocketcomponent.Streamer;
31 import net.sf.openrocket.rocketcomponent.Transition;
32 import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
33 import net.sf.openrocket.startup.Application;
34 import net.sf.openrocket.unit.UnitGroup;
35 import net.sf.openrocket.util.BugException;
36 import net.sf.openrocket.util.Reflection;
37 import net.sf.openrocket.util.Reflection.Method;
39 public class DefaultSimulationModifierService implements SimulationModifierService {
41 private static final Translator trans = Application.getTranslator();
43 private static final double DEFAULT_RANGE_MULTIPLIER = 2.0;
46 private static final Map<Class<?>, List<ModifierDefinition>> definitions = new HashMap<Class<?>, List<ModifierDefinition>>();
48 //addModifier("optimization.modifier.", unitGroup, multiplier, componentClass, methodName);
51 * Note: Each component type must contain only mutually exclusive variables.
52 * For example, body tube does not have inner diameter definition because it is
53 * defined by the outer diameter and thickness.
56 addModifier("optimization.modifier.nosecone.length", UnitGroup.UNITS_LENGTH, 1.0, NoseCone.class, "Length");
57 addModifier("optimization.modifier.nosecone.diameter", UnitGroup.UNITS_LENGTH, 2.0, NoseCone.class, "AftRadius", "isAftRadiusAutomatic");
58 addModifier("optimization.modifier.nosecone.thickness", UnitGroup.UNITS_LENGTH, 1.0, NoseCone.class, "Thickness", "isFilled");
60 addModifier("optimization.modifier.transition.length", UnitGroup.UNITS_LENGTH, 1.0, Transition.class, "Length");
61 addModifier("optimization.modifier.transition.forediameter", UnitGroup.UNITS_LENGTH, 2.0, Transition.class, "ForeRadius", "isForeRadiusAutomatic");
62 addModifier("optimization.modifier.transition.aftdiameter", UnitGroup.UNITS_LENGTH, 2.0, Transition.class, "AftRadius", "isAftRadiusAutomatic");
63 addModifier("optimization.modifier.transition.thickness", UnitGroup.UNITS_LENGTH, 1.0, Transition.class, "Thickness", "isFilled");
65 addModifier("optimization.modifier.bodytube.length", UnitGroup.UNITS_LENGTH, 1.0, BodyTube.class, "Length");
66 addModifier("optimization.modifier.bodytube.outerDiameter", UnitGroup.UNITS_LENGTH, 2.0, BodyTube.class, "OuterRadius", "isOuterRadiusAutomatic");
67 addModifier("optimization.modifier.bodytube.thickness", UnitGroup.UNITS_LENGTH, 1.0, BodyTube.class, "Thickness", "isFilled");
69 addModifier("optimization.modifier.trapezoidfinset.rootChord", UnitGroup.UNITS_LENGTH, 1.0, TrapezoidFinSet.class, "RootChord");
70 addModifier("optimization.modifier.trapezoidfinset.tipChord", UnitGroup.UNITS_LENGTH, 1.0, TrapezoidFinSet.class, "TipChord");
71 addModifier("optimization.modifier.trapezoidfinset.sweep", UnitGroup.UNITS_LENGTH, 1.0, TrapezoidFinSet.class, "Sweep");
72 addModifier("optimization.modifier.trapezoidfinset.height", UnitGroup.UNITS_LENGTH, 1.0, TrapezoidFinSet.class, "Height");
73 addModifier("optimization.modifier.finset.cant", UnitGroup.UNITS_ANGLE, 1.0, TrapezoidFinSet.class, "CantAngle");
75 addModifier("optimization.modifier.ellipticalfinset.length", UnitGroup.UNITS_LENGTH, 1.0, EllipticalFinSet.class, "Length");
76 addModifier("optimization.modifier.ellipticalfinset.height", UnitGroup.UNITS_LENGTH, 1.0, EllipticalFinSet.class, "Height");
77 addModifier("optimization.modifier.finset.cant", UnitGroup.UNITS_ANGLE, 1.0, EllipticalFinSet.class, "CantAngle");
79 addModifier("optimization.modifier.finset.cant", UnitGroup.UNITS_ANGLE, 1.0, FreeformFinSet.class, "CantAngle");
81 addModifier("optimization.modifier.launchlug.length", UnitGroup.UNITS_LENGTH, 1.0, LaunchLug.class, "Length");
82 addModifier("optimization.modifier.launchlug.outerDiameter", UnitGroup.UNITS_LENGTH, 2.0, LaunchLug.class, "OuterRadius");
83 addModifier("optimization.modifier.launchlug.thickness", UnitGroup.UNITS_LENGTH, 1.0, LaunchLug.class, "Thickness");
86 addModifier("optimization.modifier.masscomponent.mass", UnitGroup.UNITS_MASS, 1.0, MassComponent.class, "ComponentMass");
88 addModifier("optimization.modifier.parachute.diameter", UnitGroup.UNITS_LENGTH, 1.0, Parachute.class, "Diameter");
89 addModifier("optimization.modifier.parachute.coefficient", UnitGroup.UNITS_NONE, 1.0, Parachute.class, "CD");
91 addModifier("optimization.modifier.streamer.length", UnitGroup.UNITS_LENGTH, 1.0, Streamer.class, "StripLength");
92 addModifier("optimization.modifier.streamer.width", UnitGroup.UNITS_LENGTH, 1.0, Streamer.class, "StripWidth");
93 addModifier("optimization.modifier.streamer.aspectRatio", UnitGroup.UNITS_NONE, 1.0, Streamer.class, "AspectRatio");
94 addModifier("optimization.modifier.streamer.coefficient", UnitGroup.UNITS_NONE, 1.0, Streamer.class, "CD", "isCDAutomatic");
98 private static void addModifier(String modifierNameKey, UnitGroup unitGroup, double multiplier,
99 Class<? extends RocketComponent> componentClass, String methodName) {
100 addModifier(modifierNameKey, unitGroup, multiplier, componentClass, methodName, null);
103 private static void addModifier(String modifierNameKey, UnitGroup unitGroup, double multiplier,
104 Class<? extends RocketComponent> componentClass, String methodName, String autoMethod) {
106 String modifierDescriptionKey = modifierNameKey + ".desc";
108 List<ModifierDefinition> list = definitions.get(componentClass);
110 list = new ArrayList<DefaultSimulationModifierService.ModifierDefinition>();
111 definitions.put(componentClass, list);
114 ModifierDefinition definition = new ModifierDefinition(modifierNameKey, modifierDescriptionKey, unitGroup,
115 multiplier, componentClass, methodName, autoMethod);
116 list.add(definition);
123 public Collection<SimulationModifier> getModifiers(OpenRocketDocument document) {
124 List<SimulationModifier> modifiers = new ArrayList<SimulationModifier>();
126 Rocket rocket = document.getRocket();
128 // Simulation is used to calculate default min/max values
129 Simulation simulation = new Simulation(rocket);
130 simulation.getConfiguration().setMotorConfigurationID(null);
132 for (RocketComponent c : rocket) {
134 // Attribute modifiers
135 List<ModifierDefinition> list = definitions.get(c.getClass());
137 for (ModifierDefinition def : list) {
139 // Ignore modifier if value is set to automatic
140 if (def.autoMethod != null) {
141 Method m = Reflection.findMethod(c.getClass(), def.autoMethod);
142 if ((Boolean) m.invoke(c)) {
147 SimulationModifier mod = new GenericComponentModifier(
148 trans.get(def.modifierNameKey), trans.get(def.modifierDescriptionKey), c, def.unitGroup,
149 def.multiplier, def.componentClass, c.getID(), def.methodName);
150 setDefaultMinMax(mod, simulation);
156 // Add override modifiers if mass/CG is overridden
157 if (c.isMassOverridden()) {
158 SimulationModifier mod = new GenericComponentModifier(
159 trans.get("optimization.modifier.rocketcomponent.overrideMass"),
160 trans.get("optimization.modifier.rocketcomponent.overrideMass.desc"),
161 c, UnitGroup.UNITS_MASS,
162 1.0, c.getClass(), c.getID(), "OverrideMass");
163 setDefaultMinMax(mod, simulation);
166 if (c.isCGOverridden()) {
167 SimulationModifier mod = new GenericComponentModifier(
168 trans.get("optimization.modifier.rocketcomponent.overrideCG"),
169 trans.get("optimization.modifier.rocketcomponent.overrideCG.desc"),
170 c, UnitGroup.UNITS_LENGTH,
171 1.0, c.getClass(), c.getID(), "OverrideCGX");
173 mod.setMaxValue(c.getLength());
178 // Conditional motor mount parameters
179 if (c instanceof MotorMount) {
180 MotorMount mount = (MotorMount) c;
181 if (mount.isMotorMount()) {
183 SimulationModifier mod = new GenericComponentModifier(
184 trans.get("optimization.modifier.motormount.overhang"),
185 trans.get("optimization.modifier.motormount.overhang.desc"),
186 c, UnitGroup.UNITS_LENGTH,
187 1.0, c.getClass(), c.getID(), "MotorOverhang");
188 setDefaultMinMax(mod, simulation);
191 mod = new GenericComponentModifier(
192 trans.get("optimization.modifier.motormount.delay"),
193 trans.get("optimization.modifier.motormount.delay.desc"),
194 c, UnitGroup.UNITS_SHORT_TIME,
195 1.0, c.getClass(), c.getID(), "IgnitionDelay");
204 // Inner component positioning
205 if (c instanceof InternalComponent) {
206 RocketComponent parent = c.getParent();
207 SimulationModifier mod = new GenericComponentModifier(
208 trans.get("optimization.modifier.internalcomponent.position"),
209 trans.get("optimization.modifier.internalcomponent.position.desc"),
210 c, UnitGroup.UNITS_LENGTH,
211 1.0, c.getClass(), c.getID(), "PositionValue");
213 mod.setMaxValue(parent.getLength());
218 // Custom min/max for fin set position
219 if (c instanceof FinSet) {
220 RocketComponent parent = c.getParent();
221 SimulationModifier mod = new GenericComponentModifier(
222 trans.get("optimization.modifier.finset.position"),
223 trans.get("optimization.modifier.finset.position.desc"),
224 c, UnitGroup.UNITS_LENGTH,
225 1.0, c.getClass(), c.getID(), "PositionValue");
227 mod.setMaxValue(parent.getLength());
232 // Custom min/max for launch lug position
233 if (c instanceof LaunchLug) {
234 RocketComponent parent = c.getParent();
235 SimulationModifier mod = new GenericComponentModifier(
236 trans.get("optimization.modifier.launchlug.position"),
237 trans.get("optimization.modifier.launchlug.position.desc"),
238 c, UnitGroup.UNITS_LENGTH,
239 1.0, c.getClass(), c.getID(), "PositionValue");
241 mod.setMaxValue(parent.getLength());
246 // Recovery device deployment altitude and delay
247 if (c instanceof RecoveryDevice) {
248 RecoveryDevice device = (RecoveryDevice) c;
250 SimulationModifier mod = new GenericComponentModifier(
251 trans.get("optimization.modifier.recoverydevice.deployDelay"),
252 trans.get("optimization.modifier.recoverydevice.deployDelay.desc"),
253 c, UnitGroup.UNITS_SHORT_TIME,
254 1.0, c.getClass(), c.getID(), "DeployDelay");
259 if (device.getDeployEvent() == DeployEvent.ALTITUDE) {
260 mod = new GenericComponentModifier(
261 trans.get("optimization.modifier.recoverydevice.deployAltitude"),
262 trans.get("optimization.modifier.recoverydevice.deployAltitude.desc"),
263 c, UnitGroup.UNITS_DISTANCE,
264 1.0, c.getClass(), c.getID(), "DeployAltitude");
265 setDefaultMinMax(mod, simulation);
271 // Conditional shape parameter of Transition
272 if (c instanceof Transition) {
273 Transition transition = (Transition) c;
274 Transition.Shape shape = transition.getType();
275 if (shape.usesParameter()) {
276 SimulationModifier mod = new GenericComponentModifier(
277 trans.get("optimization.modifier." + c.getClass().getSimpleName().toLowerCase(Locale.ENGLISH) + ".shapeparameter"),
278 trans.get("optimization.modifier." + c.getClass().getSimpleName().toLowerCase(Locale.ENGLISH) + ".shapeparameter.desc"),
279 c, UnitGroup.UNITS_NONE,
280 1.0, c.getClass(), c.getID(), "ShapeParameter");
281 mod.setMinValue(shape.minParameter());
282 mod.setMaxValue(shape.maxParameter());
292 private void setDefaultMinMax(SimulationModifier mod, Simulation simulation) {
294 double current = mod.getCurrentSIValue(simulation);
295 mod.setMinValue(current / DEFAULT_RANGE_MULTIPLIER);
296 mod.setMaxValue(current * DEFAULT_RANGE_MULTIPLIER);
297 } catch (OptimizationException e) {
298 throw new BugException("Simulation modifier threw exception", e);
304 * String modifierName, Object relatedObject, UnitGroup unitGroup,
305 double multiplier, Class<? extends RocketComponent> componentClass, String componentId, String methodName
308 private static class ModifierDefinition {
309 private final String modifierNameKey;
310 private final String modifierDescriptionKey;
311 private final UnitGroup unitGroup;
312 private final double multiplier;
313 private final Class<? extends RocketComponent> componentClass;
314 private final String methodName;
315 private final String autoMethod;
318 public ModifierDefinition(String modifierNameKey, String modifierDescriptionKey, UnitGroup unitGroup,
319 double multiplier, Class<? extends RocketComponent> componentClass, String methodName, String autoMethod) {
320 this.modifierNameKey = modifierNameKey;
321 this.modifierDescriptionKey = modifierDescriptionKey;
322 this.unitGroup = unitGroup;
323 this.multiplier = multiplier;
324 this.componentClass = componentClass;
325 this.methodName = methodName;
326 this.autoMethod = autoMethod;