Major refactor of simulation options UI

This commit is contained in:
SiboVG 2023-11-15 04:41:31 +01:00
parent 41ea369856
commit 94c2c1ef38
6 changed files with 511 additions and 891 deletions

View File

@ -32,7 +32,7 @@ import net.sf.openrocket.util.WorldCoordinate;
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public class SimulationOptions implements ChangeSource, Cloneable {
public class SimulationOptions implements ChangeSource, Cloneable, SimulationOptionsInterface {
@SuppressWarnings("unused")
private static final Logger log = LoggerFactory.getLogger(SimulationOptions.class);
@ -71,7 +71,7 @@ public class SimulationOptions implements ChangeSource, Cloneable {
private double launchLongitude = preferences.getLaunchLongitude();
private GeodeticComputationStrategy geodeticComputation = GeodeticComputationStrategy.SPHERICAL;
private boolean useISA = preferences.getISAAtmosphere();
private boolean useISA = preferences.isISAAtmosphere();
private double launchTemperature = preferences.getLaunchTemperature(); // In Kelvin
private double launchPressure = preferences.getLaunchPressure(); // In Pascal
@ -161,34 +161,17 @@ public class SimulationOptions implements ChangeSource, Cloneable {
setWindTurbulenceIntensity(windDeviation / windAverage);
}
/**
* Return the wind turbulence intensity (standard deviation / average).
*
* @return the turbulence intensity
*/
public double getWindTurbulenceIntensity() {
return windTurbulence;
}
/**
* Set the wind standard deviation to match the given turbulence intensity.
*
* @param intensity the turbulence intensity
*/
public void setWindTurbulenceIntensity(double intensity) {
// Does not check equality so that setWindSpeedDeviation can be sure of event firing
this.windTurbulence = intensity;
fireChangeEvent();
}
/**
* Set the wind direction
*
* @param direction the wind direction
*/
public void setWindDirection(double direction) {
direction = MathUtil.reduce2Pi(direction);
if (launchIntoWind) {
@ -312,11 +295,12 @@ public class SimulationOptions implements ChangeSource, Cloneable {
fireChangeEvent();
}
/**
* Returns an atmospheric model corresponding to the launch conditions. The
* atmospheric models may be shared between different calls.
*
*
* @return an AtmosphericModel object.
*/
private AtmosphericModel getAtmosphericModel() {

View File

@ -0,0 +1,77 @@
package net.sf.openrocket.simulation;
import net.sf.openrocket.util.ChangeSource;
import net.sf.openrocket.util.GeodeticComputationStrategy;
public interface SimulationOptionsInterface extends ChangeSource {
double getLaunchRodLength();
void setLaunchRodLength(double launchRodLength);
boolean getLaunchIntoWind();
void setLaunchIntoWind(boolean i);
double getLaunchRodAngle();
void setLaunchRodAngle(double launchRodAngle);
double getLaunchRodDirection();
void setLaunchRodDirection(double launchRodDirection);
double getWindSpeedAverage();
void setWindSpeedAverage(double windAverage);
double getWindSpeedDeviation();
void setWindSpeedDeviation(double windDeviation);
/**
* Return the wind turbulence intensity (standard deviation / average).
*
* @return the turbulence intensity
*/
double getWindTurbulenceIntensity();
/**
* Set the wind standard deviation to match the given turbulence intensity.
*
* @param intensity the turbulence intensity
*/
void setWindTurbulenceIntensity(double intensity);
void setWindDirection(double direction);
double getWindDirection();
double getLaunchAltitude();
void setLaunchAltitude(double altitude);
double getLaunchLatitude();
void setLaunchLatitude(double launchLatitude);
double getLaunchLongitude();
void setLaunchLongitude(double launchLongitude);
GeodeticComputationStrategy getGeodeticComputation();
void setGeodeticComputation(GeodeticComputationStrategy geodeticComputation);
boolean isISAAtmosphere();
void setISAAtmosphere(boolean isa);
double getLaunchTemperature();
void setLaunchTemperature(double launchTemperature);
double getLaunchPressure();
void setLaunchPressure(double launchPressure);
}

View File

@ -428,7 +428,7 @@ public abstract class Preferences implements ChangeSource {
this.putDouble(LAUNCH_ALTITUDE, altitude);
// Update the launch temperature and pressure if using ISA
if (getISAAtmosphere()) {
if (isISAAtmosphere()) {
setLaunchTemperature(ISA_ATMOSPHERIC_MODEL.getConditions(getLaunchAltitude()).getTemperature());
setLaunchPressure(ISA_ATMOSPHERIC_MODEL.getConditions(getLaunchAltitude()).getPressure());
}
@ -518,7 +518,7 @@ public abstract class Preferences implements ChangeSource {
}
public boolean getISAAtmosphere() {
public boolean isISAAtmosphere() {
return this.getBoolean(LAUNCH_USE_ISA, true);
}

View File

@ -2,35 +2,13 @@ package net.sf.openrocket.gui.dialogs.preferences;
import java.awt.Color;
import java.awt.LayoutManager;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.EventObject;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.gui.SpinnerEditor;
import net.sf.openrocket.gui.adaptors.BooleanModel;
import net.sf.openrocket.gui.adaptors.DoubleModel;
import net.sf.openrocket.gui.components.BasicSlider;
import net.sf.openrocket.gui.components.StyledLabel;
import net.sf.openrocket.gui.components.UnitSelector;
import net.sf.openrocket.gui.simulation.SimulationConditionsPanel;
import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.gui.util.UITheme;
import net.sf.openrocket.models.atmosphere.ExtendedISAModel;
import net.sf.openrocket.simulation.SimulationOptions;
import net.sf.openrocket.unit.UnitGroup;
import net.sf.openrocket.util.Chars;
import net.sf.openrocket.util.StateChangeListener;
public class LaunchPreferencesPanel extends PreferencesPanel {
private static Color darkWarningColor;
@ -55,406 +33,8 @@ public class LaunchPreferencesPanel extends PreferencesPanel {
warning.setToolTipText(trans.get("pref.dlg.lbl.launchWarning.ttip"));
add(warning, "spanx, growx 0, gapbottom para, wrap");
JPanel sub;
String tip;
UnitSelector unit;
BasicSlider slider;
DoubleModel m;
DoubleModel temperatureModel;
DoubleModel pressureModel;
JSpinner spin;
// Wind settings: Average wind speed, turbulence intensity, std.
// deviation, and direction
sub = new JPanel(new MigLayout("fill, gap rel unrel",
"[grow][65lp!][30lp!][75lp!]", ""));
// Wind
sub.setBorder(BorderFactory.createTitledBorder(trans
.get("simedtdlg.lbl.Wind")));
this.add(sub, "growx, split 2, aligny 0, flowy, gapright para");
// Wind average
// Average windspeed:
JLabel label = new JLabel(trans.get("simedtdlg.lbl.Averwindspeed"));
// The average windspeed relative to the ground.
tip = trans.get("simedtdlg.lbl.ttip.Averwindspeed");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(preferences, "WindSpeedAverage",
UnitGroup.UNITS_WINDSPEED, 0);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
addEasterEgg(spin);
sub.add(spin, "w 65lp!");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(0, 10.0));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Wind std. deviation
// // Standard deviation:
label = new JLabel(trans.get("simedtdlg.lbl.Stddeviation"));
// // <html>The standard deviation of the windspeed.<br>
// // The windspeed is within twice the standard deviation from the
// average for 95% of the time.
tip = trans.get("simedtdlg.lbl.ttip.Stddeviation");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(preferences, "WindSpeedDeviation",
UnitGroup.UNITS_WINDSPEED, 0);
DoubleModel m2 = new DoubleModel(preferences, "WindSpeedAverage", 0.25,
UnitGroup.UNITS_COEFFICIENT, 0);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(new DoubleModel(0), m2));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Wind turbulence intensity
// // Turbulence intensity:
label = new JLabel(trans.get("simedtdlg.lbl.Turbulenceintensity"));
// // <html>The turbulence intensity is the standard deviation divided
// by the average windspeed.<br>
// // Typical values range from
// // to
tip = trans.get("simedtdlg.lbl.ttip.Turbulenceintensity1")
+ trans.get("simedtdlg.lbl.ttip.Turbulenceintensity2") + " "
+ UnitGroup.UNITS_RELATIVE.getDefaultUnit().toStringUnit(0.05)
+ " " + trans.get("simedtdlg.lbl.ttip.Turbulenceintensity3")
+ " "
+ UnitGroup.UNITS_RELATIVE.getDefaultUnit().toStringUnit(0.20)
+ ".";
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(preferences, "WindTurbulenceIntensity",
UnitGroup.UNITS_RELATIVE, 0);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
final JLabel intensityLabel = new JLabel(
getIntensityDescription(preferences
.getWindTurbulenceIntensity()));
intensityLabel.setToolTipText(tip);
sub.add(intensityLabel, "w 75lp, wrap");
m.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
intensityLabel.setText(getIntensityDescription(preferences
.getWindTurbulenceIntensity()));
}
});
// Wind Direction:
label = new JLabel(trans.get("simedtdlg.lbl.Winddirection"));
// // Direction of the wind. 0 is north
tip = trans.get("simedtdlg.lbl.ttip.Winddirection");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(preferences, "WindDirection", 1.0,
UnitGroup.UNITS_ANGLE, 0, 2 * Math.PI);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(0, 2 * Math.PI));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// // Temperature and pressure
sub = new JPanel(new MigLayout("fill, gap rel unrel",
"[grow][75lp!][35lp!][75lp!]", ""));
// // Atmospheric preferences
sub.setBorder(BorderFactory.createTitledBorder(trans
.get("simedtdlg.border.Atmoscond")));
this.add(sub, "growx, aligny 0, gapright para");
BooleanModel isa = new BooleanModel(preferences, "ISAAtmosphere");
JCheckBox check = new JCheckBox(isa);
// // Use International Standard Atmosphere
check.setText(trans.get("simedtdlg.checkbox.InterStdAtmosphere"));
// // <html>Select to use the International Standard Atmosphere model.
// // <br>This model has a temperature of
// // and a pressure of
// // at sea level.
check.setToolTipText(trans
.get("simedtdlg.checkbox.ttip.InterStdAtmosphere1")
+ " "
+ UnitGroup.UNITS_TEMPERATURE
.toStringUnit(ExtendedISAModel.STANDARD_TEMPERATURE)
+ " "
+ trans.get("simedtdlg.checkbox.ttip.InterStdAtmosphere2")
+ " "
+ UnitGroup.UNITS_PRESSURE
.toStringUnit(ExtendedISAModel.STANDARD_PRESSURE)
+ " "
+ trans.get("simedtdlg.checkbox.ttip.InterStdAtmosphere3"));
sub.add(check, "spanx, wrap unrel");
// Temperature:
label = new JLabel(trans.get("simedtdlg.lbl.Temperature"));
// // The temperature at the launch site.
tip = trans.get("simedtdlg.lbl.ttip.Temperature");
label.setToolTipText(tip);
isa.addEnableComponent(label, false);
sub.add(label);
temperatureModel = new DoubleModel(preferences, "LaunchTemperature",
UnitGroup.UNITS_TEMPERATURE, 0);
spin = new JSpinner(temperatureModel.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
isa.addEnableComponent(spin, false);
sub.add(spin, "growx");
unit = new UnitSelector(temperatureModel);
unit.setToolTipText(tip);
isa.addEnableComponent(unit, false);
sub.add(unit, "growx");
slider = new BasicSlider(temperatureModel.getSliderModel(253.15, 308.15)); // -20 ...
// 35
slider.setToolTipText(tip);
isa.addEnableComponent(slider, false);
sub.add(slider, "w 75lp, wrap");
// Pressure:
label = new JLabel(trans.get("simedtdlg.lbl.Pressure"));
// // The atmospheric pressure at the launch site.
tip = trans.get("simedtdlg.lbl.ttip.Pressure");
label.setToolTipText(tip);
isa.addEnableComponent(label, false);
sub.add(label);
pressureModel = new DoubleModel(preferences, "LaunchPressure",
UnitGroup.UNITS_PRESSURE, 0);
spin = new JSpinner(pressureModel.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
isa.addEnableComponent(spin, false);
sub.add(spin, "growx");
unit = new UnitSelector(pressureModel);
unit.setToolTipText(tip);
isa.addEnableComponent(unit, false);
sub.add(unit, "growx");
slider = new BasicSlider(pressureModel.getSliderModel(0.950e5, 1.050e5));
slider.setToolTipText(tip);
isa.addEnableComponent(slider, false);
sub.add(slider, "w 75lp, wrap");
isa.addChangeListener(new StateChangeListener() {
@Override
public void stateChanged(EventObject e) {
temperatureModel.stateChanged(e);
pressureModel.stateChanged(e);
}
});
// // Launch site preferences
sub = new JPanel(new MigLayout("fill, gap rel unrel",
"[grow][65lp!][30lp!][75lp!]", ""));
// // Launch site
sub.setBorder(BorderFactory.createTitledBorder(trans
.get("simedtdlg.lbl.Launchsite")));
this.add(sub, "growx, split 2, aligny 0, flowy");
// Latitude:
label = new JLabel(trans.get("simedtdlg.lbl.Latitude"));
// // <html>The launch site latitude affects the gravitational pull of
// Earth.<br>
// // Positive values are on the Northern hemisphere, negative values on
// the Southern hemisphere.
tip = trans.get("simedtdlg.lbl.ttip.Latitude");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(preferences, "LaunchLatitude",
UnitGroup.UNITS_NONE, -90, 90);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "growx");
label = new JLabel(Chars.DEGREE + " " + trans.get("CompassRose.lbl.north"));
label.setToolTipText(tip);
sub.add(label, "growx");
slider = new BasicSlider(m.getSliderModel(-90, 90));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Longitude:
label = new JLabel(trans.get("simedtdlg.lbl.Longitude"));
tip = trans.get("simedtdlg.lbl.ttip.Longitude");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(preferences, "LaunchLongitude",
UnitGroup.UNITS_NONE, -180, 180);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "growx");
label = new JLabel(Chars.DEGREE + " " + trans.get("CompassRose.lbl.east"));
label.setToolTipText(tip);
sub.add(label, "growx");
slider = new BasicSlider(m.getSliderModel(-180, 180));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Altitude:
label = new JLabel(trans.get("simedtdlg.lbl.Altitude"));
// // <html>The launch altitude above mean sea level.<br>
// // This affects the position of the rocket in the atmospheric model.
tip = trans.get("simedtdlg.lbl.ttip.Altitude");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(preferences, "LaunchAltitude",
UnitGroup.UNITS_DISTANCE, 0);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "growx");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(0, 250, 1000));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// // Launch rod
sub = new JPanel(new MigLayout("fill, gap rel unrel",
"[grow][65lp!][30lp!][75lp!]", ""));
// // Launch rod
sub.setBorder(BorderFactory.createTitledBorder(trans
.get("simedtdlg.border.Launchrod")));
this.add(sub, "growx, aligny 0, wrap");
// Length:
label = new JLabel(trans.get("simedtdlg.lbl.Length"));
// // The length of the launch rod.
tip = trans.get("simedtdlg.lbl.ttip.Length");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(preferences, "LaunchRodLength",
UnitGroup.UNITS_LENGTH, 0);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "growx");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(0, 1, 5));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Keep launch rod parallel to the wind.
BooleanModel intoWind = new BooleanModel(preferences, "LaunchIntoWind");
JCheckBox checkWind = new JCheckBox(intoWind);
// // Use International Standard Atmosphere
checkWind.setText(trans.get("simedtdlg.checkbox.Intowind"));
checkWind.setToolTipText(trans.get("simedtdlg.checkbox.ttip.Intowind1")
+ trans.get("simedtdlg.checkbox.ttip.Intowind2")
+ trans.get("simedtdlg.checkbox.ttip.Intowind3")
+ trans.get("simedtdlg.checkbox.ttip.Intowind4"));
sub.add(checkWind, "spanx, wrap unrel");
// Angle:
label = new JLabel(trans.get("simedtdlg.lbl.Angle"));
// // The angle of the launch rod from vertical.
tip = trans.get("simedtdlg.lbl.ttip.Angle");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(preferences, "LaunchRodAngle",
UnitGroup.UNITS_ANGLE, -SimulationOptions.MAX_LAUNCH_ROD_ANGLE,
SimulationOptions.MAX_LAUNCH_ROD_ANGLE);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "growx");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(
-SimulationOptions.MAX_LAUNCH_ROD_ANGLE, 0,
SimulationOptions.MAX_LAUNCH_ROD_ANGLE));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Direction:
JLabel directionLabel = new JLabel(trans.get("simedtdlg.lbl.Direction"));
// // <html>Direction of the launch rod.
tip = trans.get("simedtdlg.lbl.ttip.Direction1")
+ UnitGroup.UNITS_ANGLE.toStringUnit(0) + " "
+ trans.get("simedtdlg.lbl.ttip.Direction2") + " "
+ UnitGroup.UNITS_ANGLE.toStringUnit(2 * Math.PI) + " "
+ trans.get("simedtdlg.lbl.ttip.Direction3");
directionLabel.setToolTipText(tip);
sub.add(directionLabel);
m = new DoubleModel(preferences, "LaunchRodDirection", 1.0,
UnitGroup.UNITS_ANGLE, 0, 2 * Math.PI);
JSpinner directionSpin = new JSpinner(m.getSpinnerModel());
directionSpin.setEditor(new SpinnerEditor(directionSpin));
directionSpin.setToolTipText(tip);
sub.add(directionSpin, "growx");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
BasicSlider directionSlider = new BasicSlider(m.getSliderModel(0,
2 * Math.PI));
directionSlider.setToolTipText(tip);
sub.add(directionSlider, "w 75lp, wrap");
intoWind.addEnableComponent(directionLabel, false);
intoWind.addEnableComponent(directionSpin, false);
intoWind.addEnableComponent(unit, false);
intoWind.addEnableComponent(directionSlider, false);
// Simulation conditions
SimulationConditionsPanel.addSimulationConditionsPanel(this, preferences);
}
@ -467,46 +47,4 @@ public class LaunchPreferencesPanel extends PreferencesPanel {
darkWarningColor = GUIUtil.getUITheme().getDarkWarningColor();
}
private String getIntensityDescription(double i) {
if (i < 0.001)
// // None
return trans.get("simedtdlg.IntensityDesc.None");
if (i < 0.05)
// // Very low
return trans.get("simedtdlg.IntensityDesc.Verylow");
if (i < 0.10)
// // Low
return trans.get("simedtdlg.IntensityDesc.Low");
if (i < 0.15)
// // Medium
return trans.get("simedtdlg.IntensityDesc.Medium");
if (i < 0.20)
// // High
return trans.get("simedtdlg.IntensityDesc.High");
if (i < 0.25)
// // Very high
return trans.get("simedtdlg.IntensityDesc.Veryhigh");
// // Extreme
return trans.get("simedtdlg.IntensityDesc.Extreme");
}
/**
* Shh, don't tell anyone about this easter-egg. (displays a fun quote when the text of the spinner equals 42)
* @param spinner the magic spinner!
*/
private void addEasterEgg(JSpinner spinner) {
JTextField textField = ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField();
textField.addKeyListener(new KeyAdapter() {
@Override
public void keyTyped(KeyEvent e) {
String text = textField.getText() + e.getKeyChar();
if (text.equals("42")) {
JOptionPane.showMessageDialog(LaunchPreferencesPanel.this,
"The answer to the ultimate question of life, the universe, and everything.",
"42", JOptionPane.INFORMATION_MESSAGE);
}
}
});
}
}

View File

@ -1,15 +1,20 @@
package net.sf.openrocket.gui.simulation;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.EventObject;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
@ -24,6 +29,7 @@ import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.models.atmosphere.ExtendedISAModel;
import net.sf.openrocket.simulation.DefaultSimulationOptionFactory;
import net.sf.openrocket.simulation.SimulationOptions;
import net.sf.openrocket.simulation.SimulationOptionsInterface;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.unit.UnitGroup;
import net.sf.openrocket.util.Chars;
@ -38,405 +44,11 @@ public class SimulationConditionsPanel extends JPanel {
super(new MigLayout("fill"));
final SimulationOptions conditions = simulation.getOptions();
JPanel sub;
String tip;
UnitSelector unit;
BasicSlider slider;
DoubleModel m;
JSpinner spin;
DoubleModel temperatureModel;
DoubleModel pressureModel;
//// Wind settings: Average wind speed, turbulence intensity, std. deviation, and direction
sub = new JPanel(new MigLayout("fill, gap rel unrel",
"[grow][65lp!][30lp!][75lp!]", ""));
//// Wind
sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.lbl.Wind")));
this.add(sub, "growx, split 2, aligny 0, flowy, gapright para");
// Wind average
//// Average windspeed:
JLabel label = new JLabel(trans.get("simedtdlg.lbl.Averwindspeed"));
//// The average windspeed relative to the ground.
tip = trans.get("simedtdlg.lbl.ttip.Averwindspeed");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(conditions, "WindSpeedAverage", UnitGroup.UNITS_WINDSPEED, 0);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(0, 10.0));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Wind std. deviation
//// Standard deviation:
label = new JLabel(trans.get("simedtdlg.lbl.Stddeviation"));
//// <html>The standard deviation of the windspeed.<br>
//// The windspeed is within twice the standard deviation from the average for 95% of the time.
tip = trans.get("simedtdlg.lbl.ttip.Stddeviation");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(conditions, "WindSpeedDeviation", UnitGroup.UNITS_WINDSPEED, 0);
DoubleModel m2 = new DoubleModel(conditions, "WindSpeedAverage", 0.25,
UnitGroup.UNITS_COEFFICIENT, 0);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(new DoubleModel(0), m2));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Wind turbulence intensity
//// Turbulence intensity:
label = new JLabel(trans.get("simedtdlg.lbl.Turbulenceintensity"));
//// <html>The turbulence intensity is the standard deviation divided by the average windspeed.<br>
//// Typical values range from
//// to
tip = trans.get("simedtdlg.lbl.ttip.Turbulenceintensity1") +
trans.get("simedtdlg.lbl.ttip.Turbulenceintensity2") + " " +
UnitGroup.UNITS_RELATIVE.getDefaultUnit().toStringUnit(0.05) +
" " + trans.get("simedtdlg.lbl.ttip.Turbulenceintensity3") + " " +
UnitGroup.UNITS_RELATIVE.getDefaultUnit().toStringUnit(0.20) + ".";
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(conditions, "WindTurbulenceIntensity", UnitGroup.UNITS_RELATIVE, 0);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
final JLabel intensityLabel = new JLabel(
getIntensityDescription(conditions.getWindTurbulenceIntensity()));
intensityLabel.setToolTipText(tip);
sub.add(intensityLabel, "w 75lp, wrap");
m.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
intensityLabel.setText(
getIntensityDescription(conditions.getWindTurbulenceIntensity()));
}
});
// Wind Direction:
label = new JLabel(trans.get("simedtdlg.lbl.Winddirection"));
//// Direction of the wind. 0 is north
tip = trans.get("simedtdlg.lbl.ttip.Winddirection");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(conditions, "WindDirection", 1.0, UnitGroup.UNITS_ANGLE,
0, 2*Math.PI);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(0, 2*Math.PI));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
//// Temperature and pressure
sub = new JPanel(new MigLayout("fill, gap rel unrel",
"[grow][75lp!][35lp!][75lp!]", ""));
//// Atmospheric conditions
sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Atmoscond")));
this.add(sub, "growx, aligny 0, gapright para");
BooleanModel isa = new BooleanModel(conditions, "ISAAtmosphere");
JCheckBox check = new JCheckBox(isa);
//// Use International Standard Atmosphere
check.setText(trans.get("simedtdlg.checkbox.InterStdAtmosphere"));
//// <html>Select to use the International Standard Atmosphere model.
//// <br>This model has a temperature of
//// and a pressure of
//// at sea level.
check.setToolTipText(trans.get("simedtdlg.checkbox.ttip.InterStdAtmosphere1") + " " +
UnitGroup.UNITS_TEMPERATURE.toStringUnit(ExtendedISAModel.STANDARD_TEMPERATURE) +
" " + trans.get("simedtdlg.checkbox.ttip.InterStdAtmosphere2") + " " +
UnitGroup.UNITS_PRESSURE.toStringUnit(ExtendedISAModel.STANDARD_PRESSURE) +
" " + trans.get("simedtdlg.checkbox.ttip.InterStdAtmosphere3"));
sub.add(check, "spanx, wrap unrel");
// Temperature:
label = new JLabel(trans.get("simedtdlg.lbl.Temperature"));
//// The temperature at the launch site.
tip = trans.get("simedtdlg.lbl.ttip.Temperature");
label.setToolTipText(tip);
isa.addEnableComponent(label, false);
sub.add(label);
temperatureModel = new DoubleModel(conditions, "LaunchTemperature", UnitGroup.UNITS_TEMPERATURE, 0);
spin = new JSpinner(temperatureModel.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
isa.addEnableComponent(spin, false);
sub.add(spin, "growx");
unit = new UnitSelector(temperatureModel);
unit.setToolTipText(tip);
isa.addEnableComponent(unit, false);
sub.add(unit, "growx");
slider = new BasicSlider(temperatureModel.getSliderModel(253.15, 308.15)); // -20 ... 35
slider.setToolTipText(tip);
isa.addEnableComponent(slider, false);
sub.add(slider, "w 75lp, wrap");
// Pressure:
label = new JLabel(trans.get("simedtdlg.lbl.Pressure"));
//// The atmospheric pressure at the launch site.
tip = trans.get("simedtdlg.lbl.ttip.Pressure");
label.setToolTipText(tip);
isa.addEnableComponent(label, false);
sub.add(label);
pressureModel = new DoubleModel(conditions, "LaunchPressure", UnitGroup.UNITS_PRESSURE, 0);
spin = new JSpinner(pressureModel.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
isa.addEnableComponent(spin, false);
sub.add(spin, "growx");
unit = new UnitSelector(pressureModel);
unit.setToolTipText(tip);
isa.addEnableComponent(unit, false);
sub.add(unit, "growx");
slider = new BasicSlider(pressureModel.getSliderModel(0.950e5, 1.050e5));
slider.setToolTipText(tip);
isa.addEnableComponent(slider, false);
sub.add(slider, "w 75lp, wrap");
// Simulation conditions settings
addSimulationConditionsPanel(this, conditions);
isa.addChangeListener(new StateChangeListener() {
@Override
public void stateChanged(EventObject e) {
temperatureModel.stateChanged(e);
pressureModel.stateChanged(e);
}
});
//// Launch site conditions
sub = new JPanel(new MigLayout("fill, gap rel unrel",
"[grow][65lp!][30lp!][75lp!]", ""));
//// Launch site
sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.lbl.Launchsite")));
this.add(sub, "growx, split 2, aligny 0, flowy");
// Latitude:
label = new JLabel(trans.get("simedtdlg.lbl.Latitude"));
//// <html>The launch site latitude affects the gravitational pull of Earth.<br>
//// Positive values are on the Northern hemisphere, negative values on the Southern hemisphere.
tip = trans.get("simedtdlg.lbl.ttip.Latitude");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(conditions, "LaunchLatitude", UnitGroup.UNITS_NONE, -90, 90);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
label = new JLabel(Chars.DEGREE + " N");
label.setToolTipText(tip);
sub.add(label, "growx");
slider = new BasicSlider(m.getSliderModel(-90, 90));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Longitude:
label = new JLabel(trans.get("simedtdlg.lbl.Longitude"));
tip = trans.get("simedtdlg.lbl.ttip.Longitude");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(conditions, "LaunchLongitude", UnitGroup.UNITS_NONE, -180, 180);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
label = new JLabel(Chars.DEGREE + " E");
label.setToolTipText(tip);
sub.add(label, "growx");
slider = new BasicSlider(m.getSliderModel(-180, 180));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Altitude:
label = new JLabel(trans.get("simedtdlg.lbl.Altitude"));
//// <html>The launch altitude above mean sea level.<br>
//// This affects the position of the rocket in the atmospheric model.
tip = trans.get("simedtdlg.lbl.ttip.Altitude");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(conditions, "LaunchAltitude", UnitGroup.UNITS_DISTANCE, 0);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(0, 250, 1000));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
//// Launch rod
sub = new JPanel(new MigLayout("fill, gap rel unrel",
"[grow][65lp!][30lp!][75lp!]", ""));
//// Launch rod
sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Launchrod")));
this.add(sub, "growx, aligny 0, wrap");
// Length:
label = new JLabel(trans.get("simedtdlg.lbl.Length"));
//// The length of the launch rod.
tip = trans.get("simedtdlg.lbl.ttip.Length");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(conditions, "LaunchRodLength", UnitGroup.UNITS_LENGTH, 0);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(0, 1, 5));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Keep launch rod parallel to the wind.
BooleanModel intoWind = new BooleanModel(conditions, "LaunchIntoWind");
JCheckBox checkWind = new JCheckBox(intoWind);
//// Use International Standard Atmosphere
checkWind.setText(trans.get("simedtdlg.checkbox.Intowind"));
checkWind.setToolTipText(
trans.get("simedtdlg.checkbox.ttip.Intowind1") +
trans.get("simedtdlg.checkbox.ttip.Intowind2") +
trans.get("simedtdlg.checkbox.ttip.Intowind3") +
trans.get("simedtdlg.checkbox.ttip.Intowind4"));
sub.add(checkWind, "spanx, wrap unrel");
// Angle:
label = new JLabel(trans.get("simedtdlg.lbl.Angle"));
//// The angle of the launch rod from vertical.
tip = trans.get("simedtdlg.lbl.ttip.Angle");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(conditions, "LaunchRodAngle", UnitGroup.UNITS_ANGLE,
-SimulationOptions.MAX_LAUNCH_ROD_ANGLE, SimulationOptions.MAX_LAUNCH_ROD_ANGLE);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(-SimulationOptions.MAX_LAUNCH_ROD_ANGLE, 0,
SimulationOptions.MAX_LAUNCH_ROD_ANGLE));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Direction:
JLabel directionLabel = new JLabel(trans.get("simedtdlg.lbl.Direction"));
//// <html>Direction of the launch rod.
tip = trans.get("simedtdlg.lbl.ttip.Direction1") +
UnitGroup.UNITS_ANGLE.toStringUnit(0) +
" " + trans.get("simedtdlg.lbl.ttip.Direction2") + " " +
UnitGroup.UNITS_ANGLE.toStringUnit(2*Math.PI) +
" " + trans.get("simedtdlg.lbl.ttip.Direction3");
directionLabel.setToolTipText(tip);
sub.add(directionLabel);
m = new DoubleModel(conditions, "LaunchRodDirection", 1.0, UnitGroup.UNITS_ANGLE,
0, 2*Math.PI);
JSpinner directionSpin = new JSpinner(m.getSpinnerModel());
directionSpin.setEditor(new SpinnerEditor(directionSpin));
directionSpin.setToolTipText(tip);
sub.add(directionSpin, "w 65lp!");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
BasicSlider directionSlider = new BasicSlider(m.getSliderModel(0, 2*Math.PI));
directionSlider.setToolTipText(tip);
sub.add(directionSlider, "w 75lp, wrap");
intoWind.addEnableComponent(directionLabel, false);
intoWind.addEnableComponent(directionSpin, false);
intoWind.addEnableComponent(unit, false);
intoWind.addEnableComponent(directionSlider, false);
JButton restoreDefaults = new SelectColorButton(trans.get("simedtdlg.but.resettodefault"));
restoreDefaults.addActionListener(new ActionListener() {
@ -468,8 +80,398 @@ public class SimulationConditionsPanel extends JPanel {
this.add(saveDefaults, "gapbottom para, gapright para, right");
}
private String getIntensityDescription(double i) {
/**
* Adds the simulation conditions panel to the parent panel.
* @param parent The parent panel.
* @param target The object containing the simulation conditions setters/getters.
*/
public static void addSimulationConditionsPanel(JPanel parent, SimulationOptionsInterface target) {
JPanel sub;
DoubleModel pressureModel;
DoubleModel m;
JSpinner spin;
DoubleModel temperatureModel;
String tip;
BasicSlider slider;
UnitSelector unit;
//// Wind settings: Average wind speed, turbulence intensity, std. deviation, and direction
sub = new JPanel(new MigLayout("fill, gap rel unrel",
"[grow][75lp!][30lp!][75lp!]", ""));
//// Wind
sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.lbl.Wind")));
parent.add(sub, "growx, split 2, aligny 0, flowy, gapright para");
// Wind average
//// Average windspeed:
JLabel label = new JLabel(trans.get("simedtdlg.lbl.Averwindspeed"));
//// The average windspeed relative to the ground.
tip = trans.get("simedtdlg.lbl.ttip.Averwindspeed");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(target, "WindSpeedAverage", UnitGroup.UNITS_WINDSPEED, 0);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(0, 10.0));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Wind std. deviation
//// Standard deviation:
label = new JLabel(trans.get("simedtdlg.lbl.Stddeviation"));
//// <html>The standard deviation of the windspeed.<br>
//// The windspeed is within twice the standard deviation from the average for 95% of the time.
tip = trans.get("simedtdlg.lbl.ttip.Stddeviation");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(target, "WindSpeedDeviation", UnitGroup.UNITS_WINDSPEED, 0);
DoubleModel m2 = new DoubleModel(target, "WindSpeedAverage", 0.25,
UnitGroup.UNITS_COEFFICIENT, 0);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
addEasterEgg(spin, parent);
sub.add(spin, "w 65lp!");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(new DoubleModel(0), m2));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Wind turbulence intensity
//// Turbulence intensity:
label = new JLabel(trans.get("simedtdlg.lbl.Turbulenceintensity"));
//// <html>The turbulence intensity is the standard deviation divided by the average windspeed.<br>
//// Typical values range from
//// to
tip = trans.get("simedtdlg.lbl.ttip.Turbulenceintensity1") +
trans.get("simedtdlg.lbl.ttip.Turbulenceintensity2") + " " +
UnitGroup.UNITS_RELATIVE.getDefaultUnit().toStringUnit(0.05) +
" " + trans.get("simedtdlg.lbl.ttip.Turbulenceintensity3") + " " +
UnitGroup.UNITS_RELATIVE.getDefaultUnit().toStringUnit(0.20) + ".";
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(target, "WindTurbulenceIntensity", UnitGroup.UNITS_RELATIVE, 0);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
final JLabel intensityLabel = new JLabel(
getIntensityDescription(target.getWindTurbulenceIntensity()));
intensityLabel.setToolTipText(tip);
sub.add(intensityLabel, "w 75lp, wrap");
m.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
intensityLabel.setText(
getIntensityDescription(target.getWindTurbulenceIntensity()));
}
});
// Wind Direction:
label = new JLabel(trans.get("simedtdlg.lbl.Winddirection"));
//// Direction of the wind. 0 is north
tip = trans.get("simedtdlg.lbl.ttip.Winddirection");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(target, "WindDirection", 1.0, UnitGroup.UNITS_ANGLE,
0, 2*Math.PI);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(0, 2*Math.PI));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
//// Temperature and pressure
sub = new JPanel(new MigLayout("fill, gap rel unrel",
"[grow][85lp!][35lp!][75lp!]", ""));
//// Atmospheric conditions
sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Atmoscond")));
parent.add(sub, "growx, aligny 0, gapright para");
BooleanModel isa = new BooleanModel(target, "ISAAtmosphere");
JCheckBox check = new JCheckBox(isa);
//// Use International Standard Atmosphere
check.setText(trans.get("simedtdlg.checkbox.InterStdAtmosphere"));
//// <html>Select to use the International Standard Atmosphere model.
//// <br>This model has a temperature of
//// and a pressure of
//// at sea level.
check.setToolTipText(trans.get("simedtdlg.checkbox.ttip.InterStdAtmosphere1") + " " +
UnitGroup.UNITS_TEMPERATURE.toStringUnit(ExtendedISAModel.STANDARD_TEMPERATURE) +
" " + trans.get("simedtdlg.checkbox.ttip.InterStdAtmosphere2") + " " +
UnitGroup.UNITS_PRESSURE.toStringUnit(ExtendedISAModel.STANDARD_PRESSURE) +
" " + trans.get("simedtdlg.checkbox.ttip.InterStdAtmosphere3"));
sub.add(check, "spanx, wrap unrel");
// Temperature:
label = new JLabel(trans.get("simedtdlg.lbl.Temperature"));
//// The temperature at the launch site.
tip = trans.get("simedtdlg.lbl.ttip.Temperature");
label.setToolTipText(tip);
isa.addEnableComponent(label, false);
sub.add(label);
temperatureModel = new DoubleModel(target, "LaunchTemperature", UnitGroup.UNITS_TEMPERATURE, 0);
spin = new JSpinner(temperatureModel.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
isa.addEnableComponent(spin, false);
sub.add(spin, "growx");
unit = new UnitSelector(temperatureModel);
unit.setToolTipText(tip);
isa.addEnableComponent(unit, false);
sub.add(unit, "growx");
slider = new BasicSlider(temperatureModel.getSliderModel(253.15, 308.15)); // -20 ... 35
slider.setToolTipText(tip);
isa.addEnableComponent(slider, false);
sub.add(slider, "w 75lp, wrap");
// Pressure:
label = new JLabel(trans.get("simedtdlg.lbl.Pressure"));
//// The atmospheric pressure at the launch site.
tip = trans.get("simedtdlg.lbl.ttip.Pressure");
label.setToolTipText(tip);
isa.addEnableComponent(label, false);
sub.add(label);
pressureModel = new DoubleModel(target, "LaunchPressure", UnitGroup.UNITS_PRESSURE, 0);
spin = new JSpinner(pressureModel.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
isa.addEnableComponent(spin, false);
sub.add(spin, "growx");
unit = new UnitSelector(pressureModel);
unit.setToolTipText(tip);
isa.addEnableComponent(unit, false);
sub.add(unit, "growx");
slider = new BasicSlider(pressureModel.getSliderModel(0.950e5, 1.050e5));
slider.setToolTipText(tip);
isa.addEnableComponent(slider, false);
sub.add(slider, "w 75lp, wrap");
isa.addChangeListener(new StateChangeListener() {
@Override
public void stateChanged(EventObject e) {
temperatureModel.stateChanged(e);
pressureModel.stateChanged(e);
}
});
//// Launch site conditions
sub = new JPanel(new MigLayout("fill, gap rel unrel",
"[grow][65lp!][30lp!][75lp!]", ""));
//// Launch site
sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.lbl.Launchsite")));
parent.add(sub, "growx, split 2, aligny 0, flowy");
// Latitude:
label = new JLabel(trans.get("simedtdlg.lbl.Latitude"));
//// <html>The launch site latitude affects the gravitational pull of Earth.<br>
//// Positive values are on the Northern hemisphere, negative values on the Southern hemisphere.
tip = trans.get("simedtdlg.lbl.ttip.Latitude");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(target, "LaunchLatitude", UnitGroup.UNITS_NONE, -90, 90);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
label = new JLabel(Chars.DEGREE + " N");
label.setToolTipText(tip);
sub.add(label, "growx");
slider = new BasicSlider(m.getSliderModel(-90, 90));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Longitude:
label = new JLabel(trans.get("simedtdlg.lbl.Longitude"));
tip = trans.get("simedtdlg.lbl.ttip.Longitude");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(target, "LaunchLongitude", UnitGroup.UNITS_NONE, -180, 180);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
label = new JLabel(Chars.DEGREE + " E");
label.setToolTipText(tip);
sub.add(label, "growx");
slider = new BasicSlider(m.getSliderModel(-180, 180));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Altitude:
label = new JLabel(trans.get("simedtdlg.lbl.Altitude"));
//// <html>The launch altitude above mean sea level.<br>
//// This affects the position of the rocket in the atmospheric model.
tip = trans.get("simedtdlg.lbl.ttip.Altitude");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(target, "LaunchAltitude", UnitGroup.UNITS_DISTANCE, 0);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "w 65lp!");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(0, 250, 1000));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
//// Launch rod
sub = new JPanel(new MigLayout("fill, gap rel unrel",
"[grow][75lp!][30lp!][75lp!]", ""));
//// Launch rod
sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Launchrod")));
parent.add(sub, "growx, aligny 0, wrap");
// Length:
label = new JLabel(trans.get("simedtdlg.lbl.Length"));
//// The length of the launch rod.
tip = trans.get("simedtdlg.lbl.ttip.Length");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(target, "LaunchRodLength", UnitGroup.UNITS_LENGTH, 0);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "growx");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(0, 1, 5));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Keep launch rod parallel to the wind.
BooleanModel intoWind = new BooleanModel(target, "LaunchIntoWind");
JCheckBox checkWind = new JCheckBox(intoWind);
//// Use International Standard Atmosphere
checkWind.setText(trans.get("simedtdlg.checkbox.Intowind"));
checkWind.setToolTipText(
trans.get("simedtdlg.checkbox.ttip.Intowind1") +
trans.get("simedtdlg.checkbox.ttip.Intowind2") +
trans.get("simedtdlg.checkbox.ttip.Intowind3") +
trans.get("simedtdlg.checkbox.ttip.Intowind4"));
sub.add(checkWind, "spanx, wrap unrel");
// Angle:
label = new JLabel(trans.get("simedtdlg.lbl.Angle"));
//// The angle of the launch rod from vertical.
tip = trans.get("simedtdlg.lbl.ttip.Angle");
label.setToolTipText(tip);
sub.add(label);
m = new DoubleModel(target, "LaunchRodAngle", UnitGroup.UNITS_ANGLE,
-SimulationOptions.MAX_LAUNCH_ROD_ANGLE, SimulationOptions.MAX_LAUNCH_ROD_ANGLE);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip);
sub.add(spin, "growx");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(-SimulationOptions.MAX_LAUNCH_ROD_ANGLE, 0,
SimulationOptions.MAX_LAUNCH_ROD_ANGLE));
slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap");
// Direction:
JLabel directionLabel = new JLabel(trans.get("simedtdlg.lbl.Direction"));
//// <html>Direction of the launch rod.
tip = trans.get("simedtdlg.lbl.ttip.Direction1") +
UnitGroup.UNITS_ANGLE.toStringUnit(0) +
" " + trans.get("simedtdlg.lbl.ttip.Direction2") + " " +
UnitGroup.UNITS_ANGLE.toStringUnit(2*Math.PI) +
" " + trans.get("simedtdlg.lbl.ttip.Direction3");
directionLabel.setToolTipText(tip);
sub.add(directionLabel);
m = new DoubleModel(target, "LaunchRodDirection", 1.0, UnitGroup.UNITS_ANGLE,
0, 2*Math.PI);
JSpinner directionSpin = new JSpinner(m.getSpinnerModel());
directionSpin.setEditor(new SpinnerEditor(directionSpin));
directionSpin.setToolTipText(tip);
sub.add(directionSpin, "growx");
unit = new UnitSelector(m);
unit.setToolTipText(tip);
sub.add(unit, "growx");
BasicSlider directionSlider = new BasicSlider(m.getSliderModel(0, 2*Math.PI));
directionSlider.setToolTipText(tip);
sub.add(directionSlider, "w 75lp, wrap");
intoWind.addEnableComponent(directionLabel, false);
intoWind.addEnableComponent(directionSpin, false);
intoWind.addEnableComponent(unit, false);
intoWind.addEnableComponent(directionSlider, false);
}
private static String getIntensityDescription(double i) {
if (i < 0.001)
//// None
return trans.get("simedtdlg.IntensityDesc.None");
@ -491,5 +493,23 @@ public class SimulationConditionsPanel extends JPanel {
//// Extreme
return trans.get("simedtdlg.IntensityDesc.Extreme");
}
/**
* Shh, don't tell anyone about this easter-egg. (displays a fun quote when the text of the spinner equals 42)
* @param spinner the magic spinner!
*/
private static void addEasterEgg(JSpinner spinner, Component parent) {
JTextField textField = ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField();
textField.addKeyListener(new KeyAdapter() {
@Override
public void keyTyped(KeyEvent e) {
String text = textField.getText() + e.getKeyChar();
if (text.equals("42")) {
JOptionPane.showMessageDialog(parent,
"The answer to the ultimate question of life, the universe, and everything.",
"42", JOptionPane.INFORMATION_MESSAGE);
}
}
});
}
}

View File

@ -32,6 +32,7 @@ import net.sf.openrocket.rocketcomponent.RailButton;
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.TubeFinSet;
import net.sf.openrocket.simulation.SimulationOptionsInterface;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -50,7 +51,7 @@ import net.sf.openrocket.util.BugException;
import net.sf.openrocket.util.BuildProperties;
public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
public class SwingPreferences extends net.sf.openrocket.startup.Preferences implements SimulationOptionsInterface {
private static final Logger log = LoggerFactory.getLogger(SwingPreferences.class);
private static final String SPLIT_CHARACTER = "|";