language selector, bug fixed
[debian/openrocket] / src / net / sf / openrocket / simulation / GUISimulationConditions.java
1 package net.sf.openrocket.simulation;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Random;
6
7 import javax.swing.event.ChangeEvent;
8 import javax.swing.event.ChangeListener;
9
10 import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
11 import net.sf.openrocket.masscalc.BasicMassCalculator;
12 import net.sf.openrocket.models.atmosphere.AtmosphericModel;
13 import net.sf.openrocket.models.atmosphere.ExtendedISAModel;
14 import net.sf.openrocket.models.gravity.BasicGravityModel;
15 import net.sf.openrocket.models.wind.PinkNoiseWindModel;
16 import net.sf.openrocket.rocketcomponent.Rocket;
17 import net.sf.openrocket.util.BugException;
18 import net.sf.openrocket.util.ChangeSource;
19 import net.sf.openrocket.util.MathUtil;
20
21 // TODO: HIGH: Move somewhere else and clean up
22 @Deprecated
23 public class GUISimulationConditions implements ChangeSource, Cloneable {
24         
25         public static final double MAX_LAUNCH_ROD_ANGLE = Math.PI / 3;
26         
27         /**
28          * The ISA standard atmosphere.
29          */
30         private static final AtmosphericModel ISA_ATMOSPHERIC_MODEL = new ExtendedISAModel();
31         
32
33         private final Rocket rocket;
34         private String motorID = null;
35         
36
37         /*
38          * NOTE:  When adding/modifying parameters, they must also be added to the
39          * equals and copyFrom methods!!
40          */
41
42         // TODO: HIGH: Fetch default values from Prefs!
43         
44         private double launchRodLength = 1;
45         
46         /** Launch rod angle > 0, radians from vertical */
47         private double launchRodAngle = 0;
48         
49         /** Launch rod direction, 0 = upwind, PI = downwind. */
50         private double launchRodDirection = 0;
51         
52
53         private double windAverage = 2.0;
54         private double windTurbulence = 0.1;
55         
56         private double launchAltitude = 0;
57         private double launchLatitude = 45;
58         
59         private boolean useISA = true;
60         private double launchTemperature = ExtendedISAModel.STANDARD_TEMPERATURE;
61         private double launchPressure = ExtendedISAModel.STANDARD_PRESSURE;
62         private AtmosphericModel atmosphericModel = null;
63         
64
65         private double timeStep = RK4SimulationStepper.RECOMMENDED_TIME_STEP;
66         private double maximumAngle = RK4SimulationStepper.RECOMMENDED_ANGLE_STEP;
67         
68         private boolean calculateExtras = true;
69         
70
71         private List<ChangeListener> listeners = new ArrayList<ChangeListener>();
72         
73         
74
75         public GUISimulationConditions(Rocket rocket) {
76                 this.rocket = rocket;
77         }
78         
79         
80
81         public Rocket getRocket() {
82                 return rocket;
83         }
84         
85         
86         public String getMotorConfigurationID() {
87                 return motorID;
88         }
89         
90         /**
91          * Set the motor configuration ID.  This must be a valid motor configuration ID of
92          * the rocket, otherwise the configuration is set to <code>null</code>.
93          * 
94          * @param id    the configuration to set.
95          */
96         public void setMotorConfigurationID(String id) {
97                 if (id != null)
98                         id = id.intern();
99                 if (!rocket.isMotorConfigurationID(id))
100                         id = null;
101                 if (id == motorID)
102                         return;
103                 motorID = id;
104                 fireChangeEvent();
105         }
106         
107         
108         public double getLaunchRodLength() {
109                 return launchRodLength;
110         }
111         
112         public void setLaunchRodLength(double launchRodLength) {
113                 if (MathUtil.equals(this.launchRodLength, launchRodLength))
114                         return;
115                 this.launchRodLength = launchRodLength;
116                 fireChangeEvent();
117         }
118         
119         
120         public double getLaunchRodAngle() {
121                 return launchRodAngle;
122         }
123         
124         public void setLaunchRodAngle(double launchRodAngle) {
125                 launchRodAngle = MathUtil.clamp(launchRodAngle, 0, MAX_LAUNCH_ROD_ANGLE);
126                 if (MathUtil.equals(this.launchRodAngle, launchRodAngle))
127                         return;
128                 this.launchRodAngle = launchRodAngle;
129                 fireChangeEvent();
130         }
131         
132         
133         public double getLaunchRodDirection() {
134                 return launchRodDirection;
135         }
136         
137         public void setLaunchRodDirection(double launchRodDirection) {
138                 launchRodDirection = MathUtil.reduce180(launchRodDirection);
139                 if (MathUtil.equals(this.launchRodDirection, launchRodDirection))
140                         return;
141                 this.launchRodDirection = launchRodDirection;
142                 fireChangeEvent();
143         }
144         
145         
146
147         public double getWindSpeedAverage() {
148                 return windAverage;
149         }
150         
151         public void setWindSpeedAverage(double windAverage) {
152                 if (MathUtil.equals(this.windAverage, windAverage))
153                         return;
154                 this.windAverage = MathUtil.max(windAverage, 0);
155                 fireChangeEvent();
156         }
157         
158         
159         public double getWindSpeedDeviation() {
160                 return windAverage * windTurbulence;
161         }
162         
163         public void setWindSpeedDeviation(double windDeviation) {
164                 if (windAverage < 0.1) {
165                         windAverage = 0.1;
166                 }
167                 setWindTurbulenceIntensity(windDeviation / windAverage);
168         }
169         
170         
171         /**
172          * Return the wind turbulence intensity (standard deviation / average).
173          * 
174          * @return  the turbulence intensity
175          */
176         public double getWindTurbulenceIntensity() {
177                 return windTurbulence;
178         }
179         
180         /**
181          * Set the wind standard deviation to match the given turbulence intensity.
182          * 
183          * @param intensity   the turbulence intensity
184          */
185         public void setWindTurbulenceIntensity(double intensity) {
186                 // Does not check equality so that setWindSpeedDeviation can be sure of event firing
187                 this.windTurbulence = intensity;
188                 fireChangeEvent();
189         }
190         
191         
192
193
194
195         public double getLaunchAltitude() {
196                 return launchAltitude;
197         }
198         
199         public void setLaunchAltitude(double altitude) {
200                 if (MathUtil.equals(this.launchAltitude, altitude))
201                         return;
202                 this.launchAltitude = altitude;
203                 fireChangeEvent();
204         }
205         
206         
207         public double getLaunchLatitude() {
208                 return launchLatitude;
209         }
210         
211         public void setLaunchLatitude(double launchLatitude) {
212                 launchLatitude = MathUtil.clamp(launchLatitude, -90, 90);
213                 if (MathUtil.equals(this.launchLatitude, launchLatitude))
214                         return;
215                 this.launchLatitude = launchLatitude;
216                 fireChangeEvent();
217         }
218         
219         
220
221
222
223         public boolean isISAAtmosphere() {
224                 return useISA;
225         }
226         
227         public void setISAAtmosphere(boolean isa) {
228                 if (isa == useISA)
229                         return;
230                 useISA = isa;
231                 fireChangeEvent();
232         }
233         
234         
235         public double getLaunchTemperature() {
236                 return launchTemperature;
237         }
238         
239         
240
241         public void setLaunchTemperature(double launchTemperature) {
242                 if (MathUtil.equals(this.launchTemperature, launchTemperature))
243                         return;
244                 this.launchTemperature = launchTemperature;
245                 this.atmosphericModel = null;
246                 fireChangeEvent();
247         }
248         
249         
250
251         public double getLaunchPressure() {
252                 return launchPressure;
253         }
254         
255         
256
257         public void setLaunchPressure(double launchPressure) {
258                 if (MathUtil.equals(this.launchPressure, launchPressure))
259                         return;
260                 this.launchPressure = launchPressure;
261                 this.atmosphericModel = null;
262                 fireChangeEvent();
263         }
264         
265         
266         /**
267          * Returns an atmospheric model corresponding to the launch conditions.  The
268          * atmospheric models may be shared between different calls.
269          * 
270          * @return      an AtmosphericModel object.
271          */
272         public AtmosphericModel getAtmosphericModel() {
273                 if (useISA) {
274                         return ISA_ATMOSPHERIC_MODEL;
275                 }
276                 if (atmosphericModel == null) {
277                         atmosphericModel = new ExtendedISAModel(launchAltitude,
278                                         launchTemperature, launchPressure);
279                 }
280                 return atmosphericModel;
281         }
282         
283         
284         public double getTimeStep() {
285                 return timeStep;
286         }
287         
288         public void setTimeStep(double timeStep) {
289                 if (MathUtil.equals(this.timeStep, timeStep))
290                         return;
291                 this.timeStep = timeStep;
292                 fireChangeEvent();
293         }
294         
295         public double getMaximumStepAngle() {
296                 return maximumAngle;
297         }
298         
299         public void setMaximumStepAngle(double maximumAngle) {
300                 maximumAngle = MathUtil.clamp(maximumAngle, 1 * Math.PI / 180, 20 * Math.PI / 180);
301                 if (MathUtil.equals(this.maximumAngle, maximumAngle))
302                         return;
303                 this.maximumAngle = maximumAngle;
304                 fireChangeEvent();
305         }
306         
307         
308
309         public boolean getCalculateExtras() {
310                 return calculateExtras;
311         }
312         
313         
314
315         public void setCalculateExtras(boolean calculateExtras) {
316                 if (this.calculateExtras == calculateExtras)
317                         return;
318                 this.calculateExtras = calculateExtras;
319                 fireChangeEvent();
320         }
321         
322         
323
324         @Override
325         public GUISimulationConditions clone() {
326                 try {
327                         GUISimulationConditions copy = (GUISimulationConditions) super.clone();
328                         copy.listeners = new ArrayList<ChangeListener>();
329                         return copy;
330                 } catch (CloneNotSupportedException e) {
331                         throw new BugException(e);
332                 }
333         }
334         
335         
336         public void copyFrom(GUISimulationConditions src) {
337                 
338                 if (this.rocket == src.rocket) {
339                         
340                         this.motorID = src.motorID;
341                         
342                 } else {
343                         
344                         if (src.rocket.hasMotors(src.motorID)) {
345                                 // Try to find a matching motor ID
346                                 String motorDesc = src.rocket.getMotorConfigurationDescription(src.motorID);
347                                 String matchID = null;
348                                 
349                                 for (String id : this.rocket.getMotorConfigurationIDs()) {
350                                         if (motorDesc.equals(this.rocket.getMotorConfigurationDescription(id))) {
351                                                 matchID = id;
352                                                 break;
353                                         }
354                                 }
355                                 
356                                 this.motorID = matchID;
357                         } else {
358                                 this.motorID = null;
359                         }
360                 }
361                 
362                 this.launchAltitude = src.launchAltitude;
363                 this.launchLatitude = src.launchLatitude;
364                 this.launchPressure = src.launchPressure;
365                 this.launchRodAngle = src.launchRodAngle;
366                 this.launchRodDirection = src.launchRodDirection;
367                 this.launchRodLength = src.launchRodLength;
368                 this.launchTemperature = src.launchTemperature;
369                 this.maximumAngle = src.maximumAngle;
370                 this.timeStep = src.timeStep;
371                 this.windAverage = src.windAverage;
372                 this.windTurbulence = src.windTurbulence;
373                 this.calculateExtras = src.calculateExtras;
374                 
375                 fireChangeEvent();
376         }
377         
378         
379
380         /**
381          * Compares whether the two simulation conditions are equal.  The two are considered
382          * equal if the rocket, motor id and all variables are equal.
383          */
384         @Override
385         public boolean equals(Object other) {
386                 if (!(other instanceof GUISimulationConditions))
387                         return false;
388                 GUISimulationConditions o = (GUISimulationConditions) other;
389                 return ((this.rocket == o.rocket) &&
390                                 this.motorID == o.motorID &&
391                                 MathUtil.equals(this.launchAltitude, o.launchAltitude) &&
392                                 MathUtil.equals(this.launchLatitude, o.launchLatitude) &&
393                                 MathUtil.equals(this.launchPressure, o.launchPressure) &&
394                                 MathUtil.equals(this.launchRodAngle, o.launchRodAngle) &&
395                                 MathUtil.equals(this.launchRodDirection, o.launchRodDirection) &&
396                                 MathUtil.equals(this.launchRodLength, o.launchRodLength) &&
397                                 MathUtil.equals(this.launchTemperature, o.launchTemperature) &&
398                                 MathUtil.equals(this.maximumAngle, o.maximumAngle) &&
399                                 MathUtil.equals(this.timeStep, o.timeStep) &&
400                                 MathUtil.equals(this.windAverage, o.windAverage) &&
401                                 MathUtil.equals(this.windTurbulence, o.windTurbulence) && this.calculateExtras == o.calculateExtras);
402         }
403         
404         /**
405          * Hashcode method compatible with {@link #equals(Object)}.
406          */
407         @Override
408         public int hashCode() {
409                 if (motorID == null)
410                         return rocket.hashCode();
411                 return rocket.hashCode() + motorID.hashCode();
412         }
413         
414         @Override
415         public void addChangeListener(ChangeListener listener) {
416                 listeners.add(listener);
417         }
418         
419         @Override
420         public void removeChangeListener(ChangeListener listener) {
421                 listeners.remove(listener);
422         }
423         
424         private final ChangeEvent event = new ChangeEvent(this);
425         
426         private void fireChangeEvent() {
427                 ChangeListener[] array = listeners.toArray(new ChangeListener[0]);
428                 
429                 for (int i = array.length - 1; i >= 0; i--) {
430                         array[i].stateChanged(event);
431                 }
432         }
433         
434         
435         // TODO: HIGH: Clean up
436         @Deprecated
437         public SimulationConditions toSimulationConditions() {
438                 SimulationConditions conditions = new SimulationConditions();
439                 
440                 conditions.setRocket((Rocket) getRocket().copy());
441                 conditions.setMotorConfigurationID(getMotorConfigurationID());
442                 conditions.setLaunchRodLength(getLaunchRodLength());
443                 conditions.setLaunchRodAngle(getLaunchRodAngle());
444                 conditions.setLaunchRodDirection(getLaunchRodDirection());
445                 conditions.setLaunchAltitude(getLaunchAltitude());
446                 conditions.setLaunchLatitude(getLaunchLatitude());
447                 
448                 PinkNoiseWindModel windModel = new PinkNoiseWindModel();
449                 // TODO: HIGH: Randomness source for simulation
450                 windModel.setSeed(new Random().nextInt());
451                 windModel.setAverage(getWindSpeedAverage());
452                 windModel.setStandardDeviation(getWindSpeedDeviation());
453                 conditions.setWindModel(windModel);
454                 
455                 conditions.setAtmosphericModel(getAtmosphericModel());
456                 
457                 BasicGravityModel gravityModel = new BasicGravityModel(getLaunchLatitude());
458                 conditions.setGravityModel(gravityModel);
459                 
460                 conditions.setAerodynamicCalculator(new BarrowmanCalculator());
461                 conditions.setMassCalculator(new BasicMassCalculator());
462                 
463                 conditions.setTimeStep(getTimeStep());
464                 conditions.setMaximumAngleStep(getMaximumStepAngle());
465                 
466                 conditions.setCalculateExtras(getCalculateExtras());
467                 
468                 return conditions;
469         }
470         
471 }