create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / optimization / services / DefaultSimulationModifierService.java
1 package net.sf.openrocket.optimization.services;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Locale;
8 import java.util.Map;
9
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;
38
39 public class DefaultSimulationModifierService implements SimulationModifierService {
40         
41         private static final Translator trans = Application.getTranslator();
42         
43         private static final double DEFAULT_RANGE_MULTIPLIER = 2.0;
44         
45         
46         private static final Map<Class<?>, List<ModifierDefinition>> definitions = new HashMap<Class<?>, List<ModifierDefinition>>();
47         static {
48                 //addModifier("optimization.modifier.", unitGroup, multiplier, componentClass, methodName);
49                 
50                 /*
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.
54                  */
55                 
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");
59                 
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");
64                 
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");
68                 
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");
74                 
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");
78                 
79                 addModifier("optimization.modifier.finset.cant", UnitGroup.UNITS_ANGLE, 1.0, FreeformFinSet.class, "CantAngle");
80                 
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");
84                 
85                 
86                 addModifier("optimization.modifier.masscomponent.mass", UnitGroup.UNITS_MASS, 1.0, MassComponent.class, "ComponentMass");
87                 
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");
90                 
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");
95                 
96         }
97         
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);
101         }
102         
103         private static void addModifier(String modifierNameKey, UnitGroup unitGroup, double multiplier,
104                         Class<? extends RocketComponent> componentClass, String methodName, String autoMethod) {
105                 
106                 String modifierDescriptionKey = modifierNameKey + ".desc";
107                 
108                 List<ModifierDefinition> list = definitions.get(componentClass);
109                 if (list == null) {
110                         list = new ArrayList<DefaultSimulationModifierService.ModifierDefinition>();
111                         definitions.put(componentClass, list);
112                 }
113                 
114                 ModifierDefinition definition = new ModifierDefinition(modifierNameKey, modifierDescriptionKey, unitGroup,
115                                 multiplier, componentClass, methodName, autoMethod);
116                 list.add(definition);
117         }
118         
119         
120         
121         
122         @Override
123         public Collection<SimulationModifier> getModifiers(OpenRocketDocument document) {
124                 List<SimulationModifier> modifiers = new ArrayList<SimulationModifier>();
125                 
126                 Rocket rocket = document.getRocket();
127                 
128                 // Simulation is used to calculate default min/max values
129                 Simulation simulation = new Simulation(rocket);
130                 simulation.getConfiguration().setMotorConfigurationID(null);
131                 
132                 for (RocketComponent c : rocket) {
133                         
134                         // Attribute modifiers
135                         List<ModifierDefinition> list = definitions.get(c.getClass());
136                         if (list != null) {
137                                 for (ModifierDefinition def : list) {
138                                         
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)) {
143                                                         continue;
144                                                 }
145                                         }
146                                         
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);
151                                         modifiers.add(mod);
152                                 }
153                         }
154                         
155                         
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);
164                                 modifiers.add(mod);
165                         }
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");
172                                 mod.setMinValue(0);
173                                 mod.setMaxValue(c.getLength());
174                                 modifiers.add(mod);
175                         }
176                         
177                         
178                         // Conditional motor mount parameters
179                         if (c instanceof MotorMount) {
180                                 MotorMount mount = (MotorMount) c;
181                                 if (mount.isMotorMount()) {
182                                         
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);
189                                         modifiers.add(mod);
190                                         
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");
196                                         mod.setMinValue(0);
197                                         mod.setMaxValue(5);
198                                         modifiers.add(mod);
199                                         
200                                 }
201                         }
202                         
203                         
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");
212                                 mod.setMinValue(0);
213                                 mod.setMaxValue(parent.getLength());
214                                 modifiers.add(mod);
215                         }
216                         
217                         
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");
226                                 mod.setMinValue(0);
227                                 mod.setMaxValue(parent.getLength());
228                                 modifiers.add(mod);
229                         }
230                         
231                         
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");
240                                 mod.setMinValue(0);
241                                 mod.setMaxValue(parent.getLength());
242                                 modifiers.add(mod);
243                         }
244                         
245                         
246                         // Recovery device deployment altitude and delay
247                         if (c instanceof RecoveryDevice) {
248                                 RecoveryDevice device = (RecoveryDevice) c;
249                                 
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");
255                                 mod.setMinValue(0);
256                                 mod.setMaxValue(10);
257                                 modifiers.add(mod);
258                                 
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);
266                                         modifiers.add(mod);
267                                 }
268                         }
269                         
270                         
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());
283                                         modifiers.add(mod);
284                                 }
285                         }
286                 }
287                 
288                 return modifiers;
289         }
290         
291         
292         private void setDefaultMinMax(SimulationModifier mod, Simulation simulation) {
293                 try {
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);
299                 }
300         }
301         
302         
303         /*
304          * String modifierName, Object relatedObject, UnitGroup unitGroup,
305                         double multiplier, Class<? extends RocketComponent> componentClass, String componentId, String methodName
306          */
307         
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;
316                 
317                 
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;
327                 }
328                 
329         }
330 }