diff --git a/core/resources/datafiles/thrustcurves/thrustcurves.ser b/core/resources/datafiles/thrustcurves/thrustcurves.ser
index b6227b887..061d74654 100644
Binary files a/core/resources/datafiles/thrustcurves/thrustcurves.ser and b/core/resources/datafiles/thrustcurves/thrustcurves.ser differ
diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties
index 169cd9cdd..7dfc9d3a3 100644
--- a/core/resources/l10n/messages.properties
+++ b/core/resources/l10n/messages.properties
@@ -306,6 +306,7 @@ PreferencesDialog.lbl.languageEffect = The language will change the next time yo
! Simulation edit dialog
simedtdlg.but.runsimulation = Run simulation
simedtdlg.but.resettodefault = Reset to default
+simedtdlg.but.savedefault = Save as default
simedtdlg.but.add = Add
simedtdlg.but.remove = Remove
simedtdlg.title.Editsim = Edit simulation
@@ -438,12 +439,6 @@ SimuRunDlg.lbl.Altitude = Altitude:
SimuRunDlg.lbl.Velocity = Velocity:
SimuRunDlg.msg.Unabletosim = Unable to simulate:
SimuRunDlg.msg.errorOccurred = An error occurred during the simulation:
-SimuRunDlg.msg.AnException1 = An exception occurred during the simulation:
-SimuRunDlg.msg.AnException2 = Please report this as a bug along with the details below.
-SimuRunDlg.msg.AssertionError1 = A computation error occurred during the simulation.
-SimuRunDlg.msg.AssertionError2 = Please report this as a bug along with the details below.
-SimuRunDlg.msg.unknownerror1 = An unknown error was encountered during the simulation.
-SimuRunDlg.msg.unknownerror2 = The program may be unstable, you should save all your designs and restart OpenRocket now!
RK4SimulationStepper.error.valuesTooLarge = Simulation values exceeded limits. Try selecting a shorter time step.
@@ -468,7 +463,6 @@ SimExpPan.checkbox.Incflightevents = Include flight events
SimExpPan.checkbox.ttip.Incflightevents = Include a comment line for every flight event.
SimExpPan.lbl.Commentchar = Comment character:
SimExpPan.lbl.ttip.Commentchar = The character(s) that mark a comment line.
-SimExpPan.but.Exporttofile = Export to file...
SimExpPan.Fileexists.desc1 = File \"
SimExpPan.Fileexists.desc2 = \" exists. Overwrite?
SimExpPan.Fileexists.title = File exists
@@ -581,7 +575,6 @@ simplotpanel.lbl.Flightevents = Flight events:
simplotpanel.but.All = All
simplotpanel.but.None = None
simplotpanel.but.NewYaxisplottype = New Y axis plot type
-simplotpanel.but.Plotflight = Plot flight
simplotpanel.lbl.Axis = Axis:
simplotpanel.but.ttip.Removethisplot = Remove this plot
simplotpanel.Desc = The data will be plotted in time order even if the X axis type is not time.
@@ -1394,6 +1387,7 @@ FlightEvent.Type.GROUND_HIT = Ground hit
FlightEvent.Type.SIMULATION_END = Simulation end
FlightEvent.Type.ALTITUDE = Altitude change
FlightEvent.Type.TUMBLE = Tumbling
+FlightEvent.Type.EXCEPTION = Exception
! ThrustCurveMotorColumns
TCurveMotorCol.MANUFACTURER = Manufacturer
diff --git a/core/src/net/sf/openrocket/aerodynamics/Warning.java b/core/src/net/sf/openrocket/aerodynamics/Warning.java
index 363606d72..72df1ec49 100644
--- a/core/src/net/sf/openrocket/aerodynamics/Warning.java
+++ b/core/src/net/sf/openrocket/aerodynamics/Warning.java
@@ -8,7 +8,7 @@ import net.sf.openrocket.unit.UnitGroup;
public abstract class Warning {
private static final Translator trans = Application.getTranslator();
-
+
/**
* Return a Warning with the specific text.
*/
@@ -36,8 +36,8 @@ public abstract class Warning {
*/
@Override
public boolean equals(Object o) {
- return o != null && (o.getClass() == this.getClass());
- }
+ return o != null && (o.getClass() == this.getClass());
+ }
/**
* A hashCode
method compatible with the equals
method.
@@ -79,21 +79,21 @@ public abstract class Warning {
return (trans.get("Warning.LargeAOA.str2") +
UnitGroup.UNITS_ANGLE.getDefaultUnit().toString(aoa) + ").");
}
-
+
@Override
public boolean replaceBy(Warning other) {
if (!(other instanceof LargeAOA))
return false;
- LargeAOA o = (LargeAOA)other;
- if (Double.isNaN(this.aoa)) // If this has value NaN then replace
+ LargeAOA o = (LargeAOA) other;
+ if (Double.isNaN(this.aoa)) // If this has value NaN then replace
return true;
return (o.aoa > this.aoa);
}
}
public static class MissingMotor extends Warning {
-
+
private Motor.Type type = null;
private String manufacturer = null;
private String designation = null;
@@ -101,7 +101,7 @@ public abstract class Warning {
private double diameter = Double.NaN;
private double length = Double.NaN;
private double delay = Double.NaN;
-
+
@Override
public String toString() {
String str = "No motor with designation '" + designation + "'";
@@ -110,82 +110,82 @@ public abstract class Warning {
str += " found.";
return str;
}
-
+
public Motor.Type getType() {
return type;
}
-
-
+
+
public void setType(Motor.Type type) {
this.type = type;
}
-
-
+
+
public String getManufacturer() {
return manufacturer;
}
-
-
+
+
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
-
-
+
+
public String getDesignation() {
return designation;
}
-
-
+
+
public void setDesignation(String designation) {
this.designation = designation;
}
-
-
+
+
public String getDigest() {
return digest;
}
-
-
+
+
public void setDigest(String digest) {
this.digest = digest;
}
-
-
+
+
public double getDiameter() {
return diameter;
}
-
-
+
+
public void setDiameter(double diameter) {
this.diameter = diameter;
}
-
-
+
+
public double getLength() {
return length;
}
-
-
+
+
public void setLength(double length) {
this.length = length;
}
-
-
+
+
public double getDelay() {
return delay;
}
-
-
+
+
public void setDelay(double delay) {
this.delay = delay;
}
-
-
+
+
@Override
public boolean replaceBy(Warning other) {
return false;
}
-
+
@Override
public int hashCode() {
final int prime = 31;
@@ -206,7 +206,7 @@ public abstract class Warning {
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
-
+
@Override
public boolean equals(Object obj) {
if (this == obj)
@@ -272,7 +272,7 @@ public abstract class Warning {
if (!(other instanceof Other))
return false;
- Other o = (Other)other;
+ Other o = (Other) other;
return (o.description.equals(this.description));
}
@@ -280,7 +280,7 @@ public abstract class Warning {
public int hashCode() {
return description.hashCode();
}
-
+
@Override
public boolean replaceBy(Warning other) {
return false;
@@ -289,40 +289,40 @@ public abstract class Warning {
/** A Warning
that the body diameter is discontinuous. */
-////Discontinuity in rocket body diameter.
- public static final Warning DISCONTINUITY =
- new Other(trans.get("Warning.DISCONTINUITY"));
+ ////Discontinuity in rocket body diameter.
+ public static final Warning DISCONTINUITY =
+ new Other(trans.get("Warning.DISCONTINUITY"));
/** A Warning
that the fins are thick compared to the rocket body. */
-////Thick fins may not be modeled accurately.
+ ////Thick fins may not be modeled accurately.
public static final Warning THICK_FIN =
- new Other(trans.get("Warning.THICK_FIN"));
+ new Other(trans.get("Warning.THICK_FIN"));
/** A Warning
that the fins have jagged edges. */
-////Jagged-edged fin predictions may be inaccurate.
+ ////Jagged-edged fin predictions may be inaccurate.
public static final Warning JAGGED_EDGED_FIN =
- new Other(trans.get("Warning.JAGGED_EDGED_FIN"));
+ new Other(trans.get("Warning.JAGGED_EDGED_FIN"));
/** A Warning
that simulation listeners have affected the simulation */
-////Listeners modified the flight simulation
+ ////Listeners modified the flight simulation
public static final Warning LISTENERS_AFFECTED =
- new Other(trans.get("Warning.LISTENERS_AFFECTED"));
+ new Other(trans.get("Warning.LISTENERS_AFFECTED"));
-////Recovery device opened while motor still burning.
+ ////Recovery device opened while motor still burning.
public static final Warning RECOVERY_DEPLOYMENT_WHILE_BURNING =
- new Other(trans.get("Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING"));
+ new Other(trans.get("Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING"));
//// Invalid parameter encountered, ignoring.
public static final Warning FILE_INVALID_PARAMETER =
- new Other(trans.get("Warning.FILE_INVALID_PARAMETER"));
-
+ new Other(trans.get("Warning.FILE_INVALID_PARAMETER"));
+
public static final Warning PARALLEL_FINS =
- new Other(trans.get("Warning.PARALLEL_FINS"));
+ new Other(trans.get("Warning.PARALLEL_FINS"));
public static final Warning SUPERSONIC =
- new Other(trans.get("Warning.SUPERSONIC"));
-
+ new Other(trans.get("Warning.SUPERSONIC"));
+
public static final Warning RECOVERY_LAUNCH_ROD =
- new Other(trans.get("Warning.RECOVERY_LAUNCH_ROD"));
+ new Other(trans.get("Warning.RECOVERY_LAUNCH_ROD"));
}
diff --git a/core/src/net/sf/openrocket/document/Simulation.java b/core/src/net/sf/openrocket/document/Simulation.java
index ad3379b8a..594734e2b 100644
--- a/core/src/net/sf/openrocket/document/Simulation.java
+++ b/core/src/net/sf/openrocket/document/Simulation.java
@@ -13,6 +13,7 @@ import net.sf.openrocket.masscalc.MassCalculator;
import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.rocketcomponent.Rocket;
import net.sf.openrocket.simulation.BasicEventSimulationEngine;
+import net.sf.openrocket.simulation.DefaultSimulationOptionFactory;
import net.sf.openrocket.simulation.FlightData;
import net.sf.openrocket.simulation.RK4SimulationStepper;
import net.sf.openrocket.simulation.SimulationConditions;
@@ -105,8 +106,11 @@ public class Simulation implements ChangeSource, Cloneable {
this.status = Status.NOT_SIMULATED;
options = new SimulationOptions(rocket);
- options.setMotorConfigurationID(
- rocket.getDefaultConfiguration().getFlightConfigurationID());
+
+ DefaultSimulationOptionFactory f = Application.getInjector().getInstance(DefaultSimulationOptionFactory.class);
+ options.copyConditionsFrom(f.getDefault());
+
+ options.setMotorConfigurationID(rocket.getDefaultConfiguration().getFlightConfigurationID());
options.addChangeListener(new ConditionListener());
}
@@ -374,7 +378,21 @@ public class Simulation implements ChangeSource, Cloneable {
return simulatedData;
}
-
+ /**
+ * Return true if this simulation contains plotable flight data.
+ *
+ * @return
+ */
+ public boolean hasSimulationData() {
+ FlightData data = getSimulatedData();
+ if (data == null) {
+ return false;
+ }
+ if (data.getBranchCount() == 0) {
+ return false;
+ }
+ return true;
+ }
/**
* Returns a copy of this simulation suitable for cut/copy/paste operations.
diff --git a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/FlightConfigurationDialog.java b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/FlightConfigurationDialog.java
index 9a4d98d69..487b0ac66 100644
--- a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/FlightConfigurationDialog.java
+++ b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/FlightConfigurationDialog.java
@@ -15,6 +15,7 @@ import javax.swing.JTabbedPane;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.document.Simulation;
import net.sf.openrocket.gui.adaptors.FlightConfigurationModel;
import net.sf.openrocket.gui.main.BasicFrame;
import net.sf.openrocket.gui.util.GUIUtil;
@@ -170,6 +171,10 @@ public class FlightConfigurationDialog extends JDialog {
private void addConfiguration() {
String newId = rocket.newFlightConfigurationID();
rocket.getDefaultConfiguration().setFlightConfigurationID(newId);
+
+ // Create a new simulation for this configuration.
+ createSimulationForNewConfiguration();
+
configurationChanged();
}
@@ -188,9 +193,22 @@ public class FlightConfigurationDialog extends JDialog {
rocket.setFlightConfigurationName(currentId, oldName);
rocket.getDefaultConfiguration().setFlightConfigurationID(newConfigId);
+ // Create a new simulation for this configuration.
+ createSimulationForNewConfiguration();
+
configurationChanged();
}
+ /**
+ * prereq - assumes that the new configuration has been set as the default configuration.
+ */
+ private void createSimulationForNewConfiguration() {
+ Simulation newSim = new Simulation(rocket);
+ OpenRocketDocument doc = BasicFrame.findDocument(rocket);
+ newSim.setName(doc.getNextSimulationName());
+ doc.addSimulation(newSim);
+ }
+
private void renameConfiguration() {
new RenameConfigDialog(this, rocket).setVisible(true);
}
diff --git a/core/src/net/sf/openrocket/gui/main/SimulationEditDialog.java b/core/src/net/sf/openrocket/gui/main/SimulationEditDialog.java
deleted file mode 100644
index 62175e4de..000000000
--- a/core/src/net/sf/openrocket/gui/main/SimulationEditDialog.java
+++ /dev/null
@@ -1,1070 +0,0 @@
-package net.sf.openrocket.gui.main;
-
-
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Window;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.swing.AbstractListModel;
-import javax.swing.BorderFactory;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JSpinner;
-import javax.swing.JTabbedPane;
-import javax.swing.JTextField;
-import javax.swing.ListCellRenderer;
-import javax.swing.SwingUtilities;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-
-import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.document.OpenRocketDocument;
-import net.sf.openrocket.document.Simulation;
-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.adaptors.EnumModel;
-import net.sf.openrocket.gui.adaptors.FlightConfigurationModel;
-import net.sf.openrocket.gui.components.BasicSlider;
-import net.sf.openrocket.gui.components.DescriptionArea;
-import net.sf.openrocket.gui.components.SimulationExportPanel;
-import net.sf.openrocket.gui.components.UnitSelector;
-import net.sf.openrocket.gui.dialogs.flightconfiguration.FlightConfigurationDialog;
-import net.sf.openrocket.gui.plot.Axis;
-import net.sf.openrocket.gui.plot.PlotConfiguration;
-import net.sf.openrocket.gui.plot.SimulationPlotPanel;
-import net.sf.openrocket.gui.scalefigure.RocketPanel;
-import net.sf.openrocket.gui.util.GUIUtil;
-import net.sf.openrocket.gui.util.Icons;
-import net.sf.openrocket.l10n.Translator;
-import net.sf.openrocket.models.atmosphere.ExtendedISAModel;
-import net.sf.openrocket.rocketcomponent.Configuration;
-import net.sf.openrocket.simulation.FlightData;
-import net.sf.openrocket.simulation.FlightDataBranch;
-import net.sf.openrocket.simulation.FlightDataType;
-import net.sf.openrocket.simulation.RK4SimulationStepper;
-import net.sf.openrocket.simulation.SimulationOptions;
-import net.sf.openrocket.simulation.listeners.SimulationListener;
-import net.sf.openrocket.simulation.listeners.example.CSVSaveListener;
-import net.sf.openrocket.startup.Application;
-import net.sf.openrocket.unit.Unit;
-import net.sf.openrocket.unit.UnitGroup;
-import net.sf.openrocket.util.Chars;
-import net.sf.openrocket.util.GeodeticComputationStrategy;
-
-import org.jfree.chart.ChartFactory;
-import org.jfree.chart.ChartPanel;
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.axis.NumberAxis;
-import org.jfree.chart.plot.PlotOrientation;
-import org.jfree.chart.plot.ValueMarker;
-import org.jfree.chart.plot.XYPlot;
-import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
-import org.jfree.data.xy.XYSeries;
-import org.jfree.data.xy.XYSeriesCollection;
-
-
-public class SimulationEditDialog extends JDialog {
-
- public static final int DEFAULT = -1;
- public static final int EDIT = 1;
- public static final int PLOT = 2;
-
-
- private final Window parentWindow;
- private final Simulation simulation;
- private final OpenRocketDocument document;
- private final SimulationOptions conditions;
- private final Configuration configuration;
- private static final Translator trans = Application.getTranslator();
-
-
- public SimulationEditDialog(Window parent, OpenRocketDocument document, Simulation s) {
- this(parent, document, s, 0);
- }
-
- public SimulationEditDialog(Window parent, OpenRocketDocument document, Simulation s, int tab) {
- //// Edit simulation
- super(parent, trans.get("simedtdlg.title.Editsim"), JDialog.ModalityType.DOCUMENT_MODAL);
- this.document = document;
- this.parentWindow = parent;
- this.simulation = s;
- this.conditions = simulation.getOptions();
- configuration = simulation.getConfiguration();
-
- JPanel mainPanel = new JPanel(new MigLayout("fill", "[grow, fill]"));
-
- //// Simulation name:
- mainPanel.add(new JLabel(trans.get("simedtdlg.lbl.Simname") + " "), "span, split 2, shrink");
- final JTextField field = new JTextField(simulation.getName());
- field.getDocument().addDocumentListener(new DocumentListener() {
- @Override
- public void changedUpdate(DocumentEvent e) {
- setText();
- }
-
- @Override
- public void insertUpdate(DocumentEvent e) {
- setText();
- }
-
- @Override
- public void removeUpdate(DocumentEvent e) {
- setText();
- }
-
- private void setText() {
- String name = field.getText();
- if (name == null || name.equals(""))
- return;
- //System.out.println("Setting name:" + name);
- simulation.setName(name);
-
- }
- });
- mainPanel.add(field, "shrinky, growx, wrap");
-
- JTabbedPane tabbedPane = new JTabbedPane();
-
- //// Launch conditions
- tabbedPane.addTab(trans.get("simedtdlg.tab.Launchcond"), flightConditionsTab());
- //// Simulation options
- tabbedPane.addTab(trans.get("simedtdlg.tab.Simopt"), simulationOptionsTab());
- //// Plot data
- tabbedPane.addTab(trans.get("simedtdlg.tab.Plotdata"), plotTab());
- //// Export data
- tabbedPane.addTab(trans.get("simedtdlg.tab.Exportdata"), exportTab());
-
- // Select the initial tab
- if (tab == EDIT) {
- tabbedPane.setSelectedIndex(0);
- } else if (tab == PLOT) {
- tabbedPane.setSelectedIndex(2);
- } else {
- FlightData data = s.getSimulatedData();
- if (data == null || data.getBranchCount() == 0)
- tabbedPane.setSelectedIndex(0);
- else
- tabbedPane.setSelectedIndex(2);
- }
-
- mainPanel.add(tabbedPane, "spanx, grow, wrap");
-
-
- // Buttons
- mainPanel.add(new JPanel(), "spanx, split, growx");
-
- JButton button;
- //// Run simulation button
- button = new JButton(trans.get("simedtdlg.but.runsimulation"));
- button.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- SimulationEditDialog.this.dispose();
- SimulationRunDialog.runSimulations(parentWindow, SimulationEditDialog.this.document, simulation);
- }
- });
- mainPanel.add(button, "gapright para");
-
- //// Close button
- JButton close = new JButton(trans.get("dlg.but.close"));
- close.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- SimulationEditDialog.this.dispose();
- }
- });
- mainPanel.add(close, "");
-
-
- this.add(mainPanel);
- this.validate();
- this.pack();
- this.setLocationByPlatform(true);
-
- GUIUtil.setDisposableDialogOptions(this, button);
- }
-
-
-
-
-
- private JPanel flightConditionsTab() {
- JPanel panel = new JPanel(new MigLayout("fill"));
- JPanel sub;
- String tip;
- UnitSelector unit;
- BasicSlider slider;
- DoubleModel m;
- JSpinner spin;
-
- //// Flight selector
- //// Flight configuration:
- JLabel label = new JLabel(trans.get("simedtdlg.lbl.Flightcfg"));
- //// Select the motor configuration to use.
- label.setToolTipText(trans.get("simedtdlg.lbl.ttip.Flightcfg"));
- panel.add(label, "shrinkx, spanx, split 2");
-
- JComboBox combo = new JComboBox(new FlightConfigurationModel(configuration));
- //// Select the motor configuration to use.
- combo.setToolTipText(trans.get("simedtdlg.combo.ttip.Flightcfg"));
- combo.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- conditions.setMotorConfigurationID(configuration.getFlightConfigurationID());
- }
- });
- panel.add(combo, "");
-
- //// Edit button
- JButton button = new JButton(trans.get("simedtdlg.but.FlightcfgEdit"));
- button.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- JDialog configDialog = new FlightConfigurationDialog(document.getRocket(),SwingUtilities.windowForComponent(SimulationEditDialog.this));
- configDialog.show();
- }
- });
- panel.add(button, "wrap");
-
- //// Wind settings: Average wind speed, turbulence intensity, std. deviation
- sub = new JPanel(new MigLayout("fill, gap rel unrel",
- "[grow][65lp!][30lp!][75lp!]", ""));
- //// Wind
- sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.lbl.Wind")));
- panel.add(sub, "growx, split 2, aligny 0, flowy, gapright para");
-
-
- // Wind average
- //// Average windspeed:
- 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"));
- //// The standard deviation of the windspeed.
- //// 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"));
- //// The turbulence intensity is the standard deviation divided by the average windspeed.
- //// 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()));
- }
- });
-
-
-
-
-
- //// Temperature and pressure
- sub = new JPanel(new MigLayout("fill, gap rel unrel",
- "[grow][65lp!][30lp!][75lp!]", ""));
- //// Atmospheric conditions
- sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Atmoscond")));
- panel.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"));
- //// Select to use the International Standard Atmosphere model.
- ////
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);
-
- m = new DoubleModel(conditions, "LaunchTemperature", UnitGroup.UNITS_TEMPERATURE, 0);
-
- spin = new JSpinner(m.getSpinnerModel());
- spin.setEditor(new SpinnerEditor(spin));
- spin.setToolTipText(tip);
- isa.addEnableComponent(spin, false);
- sub.add(spin, "w 65lp!");
-
- unit = new UnitSelector(m);
- unit.setToolTipText(tip);
- isa.addEnableComponent(unit, false);
- sub.add(unit, "growx");
- slider = new BasicSlider(m.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);
-
- m = new DoubleModel(conditions, "LaunchPressure", UnitGroup.UNITS_PRESSURE, 0);
-
- spin = new JSpinner(m.getSpinnerModel());
- spin.setEditor(new SpinnerEditor(spin));
- spin.setToolTipText(tip);
- isa.addEnableComponent(spin, false);
- sub.add(spin, "w 65lp!");
-
- unit = new UnitSelector(m);
- unit.setToolTipText(tip);
- isa.addEnableComponent(unit, false);
- sub.add(unit, "growx");
- slider = new BasicSlider(m.getSliderModel(0.950e5, 1.050e5));
- slider.setToolTipText(tip);
- isa.addEnableComponent(slider, false);
- sub.add(slider, "w 75lp, wrap");
-
-
-
-
-
- //// 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")));
- panel.add(sub, "growx, split 2, aligny 0, flowy");
-
-
- // Latitude:
- label = new JLabel(trans.get("simedtdlg.lbl.Latitude"));
- //// The launch site latitude affects the gravitational pull of Earth.
- //// 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"));
- //// The launch altitude above mean sea level.
- //// 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")));
- panel.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");
-
-
-
- // 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,
- 0, 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(0, Math.PI / 9,
- SimulationOptions.MAX_LAUNCH_ROD_ANGLE));
- slider.setToolTipText(tip);
- sub.add(slider, "w 75lp, wrap");
-
-
-
- // Direction:
- label = new JLabel(trans.get("simedtdlg.lbl.Direction"));
- //// Direction of the launch rod relative to the wind.
- //// = towards the wind,
- //// = downwind.
- tip = trans.get("simedtdlg.lbl.ttip.Direction1") +
- UnitGroup.UNITS_ANGLE.toStringUnit(0) +
- " " + trans.get("simedtdlg.lbl.ttip.Direction2") + " " +
- UnitGroup.UNITS_ANGLE.toStringUnit(Math.PI) +
- " " + trans.get("simedtdlg.lbl.ttip.Direction3");
- label.setToolTipText(tip);
- sub.add(label);
-
- m = new DoubleModel(conditions, "LaunchRodDirection", UnitGroup.UNITS_ANGLE,
- -Math.PI, 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(-Math.PI, Math.PI));
- slider.setToolTipText(tip);
- sub.add(slider, "w 75lp, wrap");
-
- return panel;
- }
-
-
- 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");
- }
-
-
-
- private JPanel simulationOptionsTab() {
- JPanel panel = new JPanel(new MigLayout("fill"));
- JPanel sub, subsub;
- String tip;
- JLabel label;
- DoubleModel m;
- JSpinner spin;
- UnitSelector unit;
- BasicSlider slider;
-
-
- //// Simulation options
- sub = new JPanel(new MigLayout("fill, gap rel unrel",
- "[grow][65lp!][30lp!][75lp!]", ""));
- //// Simulator options
- sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Simopt")));
- panel.add(sub, "growx, growy, aligny 0");
-
-
- // Separate panel for computation methods, as they use a different layout
- subsub = new JPanel(new MigLayout("insets 0, fill"));
-
-
- //// Calculation method:
- tip = trans.get("simedtdlg.lbl.ttip.Calcmethod");
- label = new JLabel(trans.get("simedtdlg.lbl.Calcmethod"));
- label.setToolTipText(tip);
- subsub.add(label, "gapright para");
-
- //// Extended Barrowman
- label = new JLabel(trans.get("simedtdlg.lbl.ExtBarrowman"));
- label.setToolTipText(tip);
- subsub.add(label, "growx, wrap para");
-
-
- // Simulation method
- tip = trans.get("simedtdlg.lbl.ttip.Simmethod1") +
- trans.get("simedtdlg.lbl.ttip.Simmethod2");
- label = new JLabel(trans.get("simedtdlg.lbl.Simmethod"));
- label.setToolTipText(tip);
- subsub.add(label, "gapright para");
-
- label = new JLabel("6-DOF Runge-Kutta 4");
- label.setToolTipText(tip);
- subsub.add(label, "growx, wrap para");
-
-
- //// Geodetic calculation method:
- label = new JLabel(trans.get("simedtdlg.lbl.GeodeticMethod"));
- label.setToolTipText(trans.get("simedtdlg.lbl.ttip.GeodeticMethodTip"));
- subsub.add(label, "gapright para");
-
- EnumModel gcsModel = new EnumModel(conditions, "GeodeticComputation");
- final JComboBox gcsCombo = new JComboBox(gcsModel);
- ActionListener gcsTTipListener = new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- GeodeticComputationStrategy gcs = (GeodeticComputationStrategy) gcsCombo.getSelectedItem();
- gcsCombo.setToolTipText(gcs.getDescription());
- }
- };
- gcsCombo.addActionListener(gcsTTipListener);
- gcsTTipListener.actionPerformed(null);
- subsub.add(gcsCombo, "growx, wrap para");
-
- sub.add(subsub, "spanx, wrap para");
-
-
- //// Time step:
- label = new JLabel(trans.get("simedtdlg.lbl.Timestep"));
- tip = trans.get("simedtdlg.lbl.ttip.Timestep1") +
- trans.get("simedtdlg.lbl.ttip.Timestep2") + " " +
- UnitGroup.UNITS_TIME_STEP.toStringUnit(RK4SimulationStepper.RECOMMENDED_TIME_STEP) +
- ".";
- label.setToolTipText(tip);
- sub.add(label);
-
- m = new DoubleModel(conditions, "TimeStep", UnitGroup.UNITS_TIME_STEP, 0, 1);
-
- spin = new JSpinner(m.getSpinnerModel());
- spin.setEditor(new SpinnerEditor(spin));
- spin.setToolTipText(tip);
- sub.add(spin, "w 65lp!");
- //sub.add(spin, "nogrid");
-
- unit = new UnitSelector(m);
- unit.setToolTipText(tip);
- sub.add(unit, "w 25");
- //sub.add(unit, "nogrid");
- slider = new BasicSlider(m.getSliderModel(0, 0.2));
- slider.setToolTipText(tip);
- sub.add(slider, "w 75lp, wrap");
- //sub.add(slider,"wrap");
-
-
-
-
- //// Reset to default button
- JButton button = new JButton(trans.get("simedtdlg.but.resettodefault"));
- //// Reset the time step to its default value (
- button.setToolTipText(trans.get("simedtdlg.but.ttip.resettodefault") +
- UnitGroup.UNITS_SHORT_TIME.toStringUnit(RK4SimulationStepper.RECOMMENDED_TIME_STEP) +
- ").");
- button.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- conditions.setTimeStep(RK4SimulationStepper.RECOMMENDED_TIME_STEP);
- conditions.setGeodeticComputation(GeodeticComputationStrategy.SPHERICAL);
- }
- });
-
- sub.add(button, "align left");
-
-
-
-
- //// Simulation listeners
- sub = new JPanel(new MigLayout("fill, gap 0 0"));
- //// Simulator listeners
- sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Simlist")));
- panel.add(sub, "growx, growy");
-
-
- DescriptionArea desc = new DescriptionArea(5);
- //// Simulation listeners is an advanced feature that allows user-written code to listen to and interact with the simulation.
- //// For details on writing simulation listeners, see the OpenRocket technical documentation.
- desc.setText(trans.get("simedtdlg.txt.longA1") +
- trans.get("simedtdlg.txt.longA2"));
- sub.add(desc, "aligny 0, growx, wrap para");
-
- //// Current listeners:
- label = new JLabel(trans.get("simedtdlg.lbl.Curlist"));
- sub.add(label, "spanx, wrap rel");
-
- final ListenerListModel listenerModel = new ListenerListModel();
- final JList list = new JList(listenerModel);
- list.setCellRenderer(new ListenerCellRenderer());
- JScrollPane scroll = new JScrollPane(list);
- // scroll.setPreferredSize(new Dimension(1,1));
- sub.add(scroll, "height 1px, grow, wrap rel");
-
- //// Add button
- button = new JButton(trans.get("simedtdlg.but.add"));
- button.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- String previous = Application.getPreferences().getString("previousListenerName", "");
- String input = (String) JOptionPane.showInputDialog(SimulationEditDialog.this,
- new Object[] {
- //// Type the full Java class name of the simulation listener, for example:
- "Type the full Java class name of the simulation listener, for example:",
- "" + CSVSaveListener.class.getName() + "" },
- //// Add simulation listener
- trans.get("simedtdlg.lbl.Addsimlist"),
- JOptionPane.QUESTION_MESSAGE,
- null, null,
- previous
- );
- if (input == null || input.equals(""))
- return;
-
- Application.getPreferences().putString("previousListenerName", input);
- simulation.getSimulationListeners().add(input);
- listenerModel.fireContentsChanged();
- }
- });
- sub.add(button, "split 2, sizegroup buttons, alignx 50%, gapright para");
-
- //// Remove button
- button = new JButton(trans.get("simedtdlg.but.remove"));
- button.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- int[] selected = list.getSelectedIndices();
- Arrays.sort(selected);
- for (int i = selected.length - 1; i >= 0; i--) {
- simulation.getSimulationListeners().remove(selected[i]);
- }
- listenerModel.fireContentsChanged();
- }
- });
- sub.add(button, "sizegroup buttons, alignx 50%");
-
-
- return panel;
- }
-
-
- private class ListenerListModel extends AbstractListModel {
- @Override
- public String getElementAt(int index) {
- if (index < 0 || index >= getSize())
- return null;
- return simulation.getSimulationListeners().get(index);
- }
-
- @Override
- public int getSize() {
- return simulation.getSimulationListeners().size();
- }
-
- public void fireContentsChanged() {
- super.fireContentsChanged(this, 0, getSize());
- }
- }
-
-
-
-
- /**
- * A panel for plotting the previously calculated data.
- */
- private JPanel plotTab() {
-
- // Check that data exists
- if (simulation.getSimulatedData() == null ||
- simulation.getSimulatedData().getBranchCount() == 0) {
- return noDataPanel();
- }
-
- return new SimulationPlotPanel(simulation);
- }
-
-
-
- /**
- * A panel for exporting the data.
- */
- private JPanel exportTab() {
- FlightData data = simulation.getSimulatedData();
-
- // Check that data exists
- if (data == null || data.getBranchCount() == 0 ||
- data.getBranch(0).getTypes().length == 0) {
- return noDataPanel();
- }
-
- return new SimulationExportPanel(simulation);
- }
-
-
- /**
- * Return a panel stating that there is no data available, and that the user
- * should run the simulation first.
- */
- public static JPanel noDataPanel() {
- JPanel panel = new JPanel(new MigLayout("fill"));
-
- // No data available
- //// No flight data available.
- panel.add(new JLabel(trans.get("simedtdlg.lbl.Noflightdata")),
- "alignx 50%, aligny 100%, wrap para");
- //// Please run the simulation first.
- panel.add(new JLabel(trans.get("simedtdlg.lbl.runsimfirst")),
- "alignx 50%, aligny 0%, wrap");
- return panel;
- }
-
-
- @SuppressWarnings("unused")
- private void performPlot(PlotConfiguration config) {
-
- // Fill the auto-selections
- FlightDataBranch branch = simulation.getSimulatedData().getBranch(0);
- PlotConfiguration filled = config.fillAutoAxes(branch);
- List axes = filled.getAllAxes();
-
-
- // Create the data series for both axes
- XYSeriesCollection[] data = new XYSeriesCollection[2];
- data[0] = new XYSeriesCollection();
- data[1] = new XYSeriesCollection();
-
-
- // Get the domain axis type
- final FlightDataType domainType = filled.getDomainAxisType();
- final Unit domainUnit = filled.getDomainAxisUnit();
- if (domainType == null) {
- throw new IllegalArgumentException("Domain axis type not specified.");
- }
- List x = branch.get(domainType);
-
-
- // Create the XYSeries objects from the flight data and store into the collections
- int length = filled.getTypeCount();
- String[] axisLabel = new String[2];
- for (int i = 0; i < length; i++) {
- // Get info
- FlightDataType type = filled.getType(i);
- Unit unit = filled.getUnit(i);
- int axis = filled.getAxis(i);
- String name = getLabel(type, unit);
-
- // Store data in provided units
- List y = branch.get(type);
- XYSeries series = new XYSeries(name, false, true);
- for (int j = 0; j < x.size(); j++) {
- series.add(domainUnit.toUnit(x.get(j)), unit.toUnit(y.get(j)));
- }
- data[axis].addSeries(series);
-
- // Update axis label
- if (axisLabel[axis] == null)
- axisLabel[axis] = type.getName();
- else
- axisLabel[axis] += "; " + type.getName();
- }
-
-
- // Create the chart using the factory to get all default settings
- JFreeChart chart = ChartFactory.createXYLineChart(
- //// Simulated flight
- trans.get("simedtdlg.chart.Simflight"),
- null,
- null,
- null,
- PlotOrientation.VERTICAL,
- true,
- true,
- false
- );
-
-
- // Add the data and formatting to the plot
- XYPlot plot = chart.getXYPlot();
- int axisno = 0;
- for (int i = 0; i < 2; i++) {
- // Check whether axis has any data
- if (data[i].getSeriesCount() > 0) {
- // Create and set axis
- double min = axes.get(i).getMinValue();
- double max = axes.get(i).getMaxValue();
- NumberAxis axis = new PresetNumberAxis(min, max);
- axis.setLabel(axisLabel[i]);
- // axis.setRange(axes.get(i).getMinValue(), axes.get(i).getMaxValue());
- plot.setRangeAxis(axisno, axis);
-
- // Add data and map to the axis
- plot.setDataset(axisno, data[i]);
- plot.setRenderer(axisno, new StandardXYItemRenderer());
- plot.mapDatasetToRangeAxis(axisno, axisno);
- axisno++;
- }
- }
-
- plot.getDomainAxis().setLabel(getLabel(domainType, domainUnit));
- plot.addDomainMarker(new ValueMarker(0));
- plot.addRangeMarker(new ValueMarker(0));
-
-
- // Create the dialog
- //// Simulation results
- final JDialog dialog = new JDialog(this, trans.get("simedtdlg.dlg.Simres"));
- dialog.setModalityType(ModalityType.DOCUMENT_MODAL);
-
- JPanel panel = new JPanel(new MigLayout("fill"));
- dialog.add(panel);
-
- ChartPanel chartPanel = new ChartPanel(chart,
- false, // properties
- true, // save
- false, // print
- true, // zoom
- true); // tooltips
- chartPanel.setMouseWheelEnabled(true);
- chartPanel.setEnforceFileExtensions(true);
- chartPanel.setInitialDelay(500);
-
- chartPanel.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1));
-
- panel.add(chartPanel, "grow, wrap 20lp");
-
- //// Close button
- JButton button = new JButton(trans.get("dlg.but.close"));
- button.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- dialog.setVisible(false);
- }
- });
- panel.add(button, "right");
-
- dialog.setLocationByPlatform(true);
- dialog.pack();
-
- GUIUtil.setDisposableDialogOptions(dialog, button);
-
- dialog.setVisible(true);
- }
-
-
- private class PresetNumberAxis extends NumberAxis {
- private final double min;
- private final double max;
-
- public PresetNumberAxis(double min, double max) {
- this.min = min;
- this.max = max;
- autoAdjustRange();
- }
-
- @Override
- protected void autoAdjustRange() {
- this.setRange(min, max);
- }
- }
-
-
- private String getLabel(FlightDataType type, Unit unit) {
- String name = type.getName();
- if (unit != null && !UnitGroup.UNITS_NONE.contains(unit) &&
- !UnitGroup.UNITS_COEFFICIENT.contains(unit) && unit.getUnit().length() > 0)
- name += " (" + unit.getUnit() + ")";
- return name;
- }
-
-
-
- private class ListenerCellRenderer extends JLabel implements ListCellRenderer {
-
- @Override
- public Component getListCellRendererComponent(JList list, Object value,
- int index, boolean isSelected, boolean cellHasFocus) {
- String s = value.toString();
- setText(s);
-
- // Attempt instantiating, catch any exceptions
- Exception ex = null;
- try {
- Class> c = Class.forName(s);
- @SuppressWarnings("unused")
- SimulationListener l = (SimulationListener) c.newInstance();
- } catch (Exception e) {
- ex = e;
- }
-
- if (ex == null) {
- setIcon(Icons.SIMULATION_LISTENER_OK);
- //// Listener instantiated successfully.
- setToolTipText("Listener instantiated successfully.");
- } else {
- setIcon(Icons.SIMULATION_LISTENER_ERROR);
- //// Unable to instantiate listener due to exception:
- setToolTipText("Unable to instantiate listener due to exception:
" +
- ex.toString());
- }
-
- if (isSelected) {
- setBackground(list.getSelectionBackground());
- setForeground(list.getSelectionForeground());
- } else {
- setBackground(list.getBackground());
- setForeground(list.getForeground());
- }
- setOpaque(true);
- return this;
- }
- }
-}
diff --git a/core/src/net/sf/openrocket/gui/main/SimulationPanel.java b/core/src/net/sf/openrocket/gui/main/SimulationPanel.java
index 9b34c547b..cf962e6d0 100644
--- a/core/src/net/sf/openrocket/gui/main/SimulationPanel.java
+++ b/core/src/net/sf/openrocket/gui/main/SimulationPanel.java
@@ -35,6 +35,9 @@ import net.sf.openrocket.formatting.RocketDescriptor;
import net.sf.openrocket.gui.adaptors.Column;
import net.sf.openrocket.gui.adaptors.ColumnTableModel;
import net.sf.openrocket.gui.components.StyledLabel;
+import net.sf.openrocket.gui.simulation.SimulationEditDialog;
+import net.sf.openrocket.gui.simulation.SimulationRunDialog;
+import net.sf.openrocket.gui.simulation.SimulationWarningDialog;
import net.sf.openrocket.gui.util.Icons;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
@@ -68,13 +71,14 @@ public class SimulationPanel extends JPanel {
private final ColumnTableModel simulationTableModel;
private final JTable simulationTable;
+ private final JButton editButton;
+ private final JButton runButton;
+ private final JButton deleteButton;
+ private final JButton plotButton;
public SimulationPanel(OpenRocketDocument doc) {
super(new MigLayout("fill", "[grow][][][][][][grow]"));
- JButton button;
-
-
this.document = doc;
@@ -82,59 +86,60 @@ public class SimulationPanel extends JPanel {
//////// The simulation action buttons
//// New simulation button
- button = new JButton(trans.get("simpanel.but.newsimulation"));
- //// Add a new simulation
- button.setToolTipText(trans.get("simpanel.but.ttip.newsimulation"));
- button.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- Simulation sim = new Simulation(document.getRocket());
- sim.setName(document.getNextSimulationName());
-
- int n = document.getSimulationCount();
- document.addSimulation(sim);
- simulationTableModel.fireTableDataChanged();
- simulationTable.clearSelection();
- simulationTable.addRowSelectionInterval(n, n);
-
- openDialog(sim, SimulationEditDialog.EDIT);
- }
- });
- this.add(button, "skip 1, gapright para");
+ {
+ JButton button = new JButton(trans.get("simpanel.but.newsimulation"));
+ //// Add a new simulation
+ button.setToolTipText(trans.get("simpanel.but.ttip.newsimulation"));
+ button.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Simulation sim = new Simulation(document.getRocket());
+ sim.setName(document.getNextSimulationName());
+
+ int n = document.getSimulationCount();
+ document.addSimulation(sim);
+ simulationTableModel.fireTableDataChanged();
+ simulationTable.clearSelection();
+ simulationTable.addRowSelectionInterval(n, n);
+
+ openDialog(false, sim);
+ }
+ });
+ this.add(button, "skip 1, gapright para");
+ }
//// Edit simulation button
- button = new JButton(trans.get("simpanel.but.editsimulation"));
+ editButton = new JButton(trans.get("simpanel.but.editsimulation"));
//// Edit the selected simulation
- button.setToolTipText(trans.get("simpanel.but.ttip.editsim"));
- button.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- int selected = simulationTable.getSelectedRow();
- if (selected < 0)
- return; // TODO: MEDIUM: "None selected" dialog
-
- selected = simulationTable.convertRowIndexToModel(selected);
- simulationTable.clearSelection();
- simulationTable.addRowSelectionInterval(selected, selected);
-
- openDialog(document.getSimulations().get(selected), SimulationEditDialog.EDIT);
- }
- });
- this.add(button, "gapright para");
-
- //// Run simulations
- button = new JButton(trans.get("simpanel.but.runsimulations"));
- //// Re-run the selected simulations
- button.setToolTipText(trans.get("simpanel.but.ttip.runsimu"));
- button.addActionListener(new ActionListener() {
+ editButton.setToolTipText(trans.get("simpanel.but.ttip.editsim"));
+ editButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int[] selection = simulationTable.getSelectedRows();
- if (selection.length == 0) {
- JOptionPane.showMessageDialog(simulationTable, "No simulations selected.");
- return;
+ if (selection.length == 0)
+ return; // TODO: LOW: "None selected" dialog
+
+ Simulation[] sims = new Simulation[selection.length];
+ for (int i = 0; i < selection.length; i++) {
+ selection[i] = simulationTable.convertRowIndexToModel(selection[i]);
+ sims[i] = document.getSimulation(selection[i]);
}
-
+ openDialog(false, sims);
+ }
+ });
+ this.add(editButton, "gapright para");
+
+ //// Run simulations
+ runButton = new JButton(trans.get("simpanel.but.runsimulations"));
+ //// Re-run the selected simulations
+ runButton.setToolTipText(trans.get("simpanel.but.ttip.runsimu"));
+ runButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ int[] selection = simulationTable.getSelectedRows();
+ if (selection.length == 0)
+ return; // TODO: LOW: "None selected" dialog
+
Simulation[] sims = new Simulation[selection.length];
for (int i = 0; i < selection.length; i++) {
selection[i] = simulationTable.convertRowIndexToModel(selection[i]);
@@ -148,13 +153,13 @@ public class SimulationPanel extends JPanel {
fireMaintainSelection();
}
});
- this.add(button, "gapright para");
+ this.add(runButton, "gapright para");
//// Delete simulations button
- button = new JButton(trans.get("simpanel.but.deletesimulations"));
+ deleteButton = new JButton(trans.get("simpanel.but.deletesimulations"));
//// Delete the selected simulations
- button.setToolTipText(trans.get("simpanel.but.ttip.deletesim"));
- button.addActionListener(new ActionListener() {
+ deleteButton.setToolTipText(trans.get("simpanel.but.ttip.deletesim"));
+ deleteButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int[] selection = simulationTable.getSelectedRows();
@@ -203,12 +208,12 @@ public class SimulationPanel extends JPanel {
simulationTableModel.fireTableDataChanged();
}
});
- this.add(button, "gapright para");
+ this.add(deleteButton, "gapright para");
//// Plot / export button
- button = new JButton(trans.get("simpanel.but.plotexport"));
+ plotButton = new JButton(trans.get("simpanel.but.plotexport"));
// button = new JButton("Plot flight");
- button.addActionListener(new ActionListener() {
+ plotButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selected = simulationTable.getSelectedRow();
@@ -219,10 +224,21 @@ public class SimulationPanel extends JPanel {
simulationTable.clearSelection();
simulationTable.addRowSelectionInterval(selected, selected);
- openDialog(document.getSimulations().get(selected), SimulationEditDialog.PLOT);
+
+ Simulation sim = document.getSimulations().get(selected);
+
+ if (!sim.hasSimulationData()) {
+ new SimulationRunDialog(SwingUtilities.getWindowAncestor(
+ SimulationPanel.this), document, sim).setVisible(true);
+ }
+
+ fireMaintainSelection();
+
+ openDialog(true, sim);
+
}
});
- this.add(button, "wrap para");
+ this.add(plotButton, "wrap para");
@@ -476,13 +492,19 @@ public class SimulationPanel extends JPanel {
int selected = simulationTable.getSelectedRow();
if (selected < 0)
return;
-
selected = simulationTable.convertRowIndexToModel(selected);
- simulationTable.clearSelection();
- simulationTable.addRowSelectionInterval(selected, selected);
- openDialog(document.getSimulations().get(selected),
- SimulationEditDialog.DEFAULT);
+ int column = simulationTable.columnAtPoint(e.getPoint());
+ if (column == 0) {
+ SimulationWarningDialog.showWarningDialog(SimulationPanel.this, document.getSimulations().get(selected));
+ } else {
+ simulationTable.clearSelection();
+ simulationTable.addRowSelectionInterval(selected, selected);
+
+ openDialog(document.getSimulations().get(selected));
+ }
+ } else {
+ updateButtonStates();
}
}
});
@@ -511,6 +533,26 @@ public class SimulationPanel extends JPanel {
JScrollPane scrollpane = new JScrollPane(simulationTable);
this.add(scrollpane, "spanx, grow, wrap rel");
+ updateButtonStates();
+ }
+
+ private void updateButtonStates() {
+ int[] selection = simulationTable.getSelectedRows();
+ if (selection.length == 0) {
+ editButton.setEnabled(false);
+ runButton.setEnabled(false);
+ deleteButton.setEnabled(false);
+ plotButton.setEnabled(false);
+ } else {
+ if (selection.length > 1) {
+ plotButton.setEnabled(false);
+ } else {
+ plotButton.setEnabled(true);
+ }
+ editButton.setEnabled(true);
+ runButton.setEnabled(true);
+ deleteButton.setEnabled(true);
+ }
}
@@ -518,12 +560,23 @@ public class SimulationPanel extends JPanel {
return simulationTable.getSelectionModel();
}
- private void openDialog(final Simulation sim, int position) {
- new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, sim, position)
- .setVisible(true);
+ private void openDialog(boolean plotMode, final Simulation... sims) {
+ SimulationEditDialog d = new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, sims);
+ if (plotMode) {
+ d.setPlotMode();
+ }
+ d.setVisible(true);
fireMaintainSelection();
}
+ private void openDialog(final Simulation sim) {
+ boolean plotMode = false;
+ if (sim.hasSimulationData()) {
+ plotMode = true;
+ }
+ openDialog(plotMode, sim);
+ }
+
private void fireMaintainSelection() {
int[] selection = simulationTable.getSelectedRows();
simulationTableModel.fireTableDataChanged();
diff --git a/core/src/net/sf/openrocket/gui/plot/PlotConfiguration.java b/core/src/net/sf/openrocket/gui/plot/PlotConfiguration.java
index db604a1f2..8f1f455de 100644
--- a/core/src/net/sf/openrocket/gui/plot/PlotConfiguration.java
+++ b/core/src/net/sf/openrocket/gui/plot/PlotConfiguration.java
@@ -37,6 +37,7 @@ public class PlotConfiguration implements Cloneable {
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
config.setEvent(FlightEvent.Type.TUMBLE, true);
+ config.setEvent(FlightEvent.Type.EXCEPTION, true);
configs.add(config);
//// Total motion vs. time
@@ -51,6 +52,7 @@ public class PlotConfiguration implements Cloneable {
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
config.setEvent(FlightEvent.Type.TUMBLE, true);
+ config.setEvent(FlightEvent.Type.EXCEPTION, true);
configs.add(config);
//// Flight side profile
@@ -63,6 +65,7 @@ public class PlotConfiguration implements Cloneable {
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
config.setEvent(FlightEvent.Type.TUMBLE, true);
+ config.setEvent(FlightEvent.Type.EXCEPTION, true);
configs.add(config);
//// Stability vs. time
@@ -77,6 +80,7 @@ public class PlotConfiguration implements Cloneable {
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
config.setEvent(FlightEvent.Type.TUMBLE, true);
+ config.setEvent(FlightEvent.Type.EXCEPTION, true);
configs.add(config);
//// Drag coefficients vs. Mach number
@@ -86,6 +90,7 @@ public class PlotConfiguration implements Cloneable {
config.addPlotDataType(FlightDataType.TYPE_FRICTION_DRAG_COEFF, 0);
config.addPlotDataType(FlightDataType.TYPE_BASE_DRAG_COEFF, 0);
config.addPlotDataType(FlightDataType.TYPE_PRESSURE_DRAG_COEFF, 0);
+ config.setEvent(FlightEvent.Type.EXCEPTION, true);
configs.add(config);
//// Roll characteristics
@@ -102,6 +107,7 @@ public class PlotConfiguration implements Cloneable {
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
config.setEvent(FlightEvent.Type.TUMBLE, true);
+ config.setEvent(FlightEvent.Type.EXCEPTION, true);
configs.add(config);
//// Angle of attack and orientation vs. time
@@ -116,6 +122,7 @@ public class PlotConfiguration implements Cloneable {
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
config.setEvent(FlightEvent.Type.TUMBLE, true);
+ config.setEvent(FlightEvent.Type.EXCEPTION, true);
configs.add(config);
//// Simulation time step and computation time
@@ -129,6 +136,7 @@ public class PlotConfiguration implements Cloneable {
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
config.setEvent(FlightEvent.Type.TUMBLE, true);
+ config.setEvent(FlightEvent.Type.EXCEPTION, true);
configs.add(config);
DEFAULT_CONFIGURATIONS = configs.toArray(new PlotConfiguration[0]);
diff --git a/core/src/net/sf/openrocket/gui/plot/SimulationPlot.java b/core/src/net/sf/openrocket/gui/plot/SimulationPlot.java
index a254275c1..043617a51 100644
--- a/core/src/net/sf/openrocket/gui/plot/SimulationPlot.java
+++ b/core/src/net/sf/openrocket/gui/plot/SimulationPlot.java
@@ -20,6 +20,7 @@ import java.util.HashSet;
import java.util.List;
import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.gui.simulation.SimulationPlotPanel;
import net.sf.openrocket.simulation.FlightDataBranch;
import net.sf.openrocket.simulation.FlightDataType;
import net.sf.openrocket.simulation.FlightEvent;
@@ -152,7 +153,6 @@ public class SimulationPlot {
Unit unit = filled.getUnit(i);
int axis = filled.getAxis(i);
String name = getLabel(type, unit);
- this.legendItems.lineLabels.add(name);
List seriesNames = Util.generateSeriesLabels(simulation);
@@ -166,7 +166,7 @@ public class SimulationPlot {
List plotx = thisBranch.get(domainType);
List ploty = thisBranch.get(type);
XYSeries series = new XYSeries(seriesNames.get(branchIndex) + ": " + name, false, true);
- series.setDescription(thisBranch.getBranchName() + ": " + name);
+ series.setDescription(name);
int pointCount = plotx.size();
for (int j = 0; j < pointCount; j++) {
series.add(domainUnit.toUnit(plotx.get(j)), unit.toUnit(ploty.get(j)));
@@ -249,6 +249,8 @@ public class SimulationPlot {
}
// Now we pull the colors for the legend.
for (int j = 0; j < data[i].getSeriesCount(); j += branchCount) {
+ String name = data[i].getSeries(j).getDescription();
+ this.legendItems.lineLabels.add(name);
Paint linePaint = r.lookupSeriesPaint(j);
this.legendItems.linePaints.add(linePaint);
Shape itemShape = r.lookupSeriesShape(j);
diff --git a/core/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java b/core/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java
index 1bb158549..d57563a1c 100644
--- a/core/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java
+++ b/core/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java
@@ -7,8 +7,6 @@ import java.awt.event.InputEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
import javax.swing.JButton;
import javax.swing.JCheckBox;
@@ -113,8 +111,8 @@ public class SimulationPlotDialog extends JDialog {
//// Add series selection box
ArrayList stages = new ArrayList();
stages.add("All");
- stages.addAll( Util.generateSeriesLabels(simulation));
-
+ stages.addAll(Util.generateSeriesLabels(simulation));
+
final JComboBox stageSelection = new JComboBox(stages.toArray(new String[0]));
stageSelection.addItemListener(new ItemListener() {
@@ -159,8 +157,8 @@ public class SimulationPlotDialog extends JDialog {
* @param simulation the simulation to plot.
* @param config the configuration of the plot.
*/
- public static void showPlot(Window parent, Simulation simulation, PlotConfiguration config) {
- new SimulationPlotDialog(parent, simulation, config).setVisible(true);
+ public static SimulationPlotDialog getPlot(Window parent, Simulation simulation, PlotConfiguration config) {
+ return new SimulationPlotDialog(parent, simulation, config);
}
}
diff --git a/core/src/net/sf/openrocket/gui/print/PrintSimulationWorker.java b/core/src/net/sf/openrocket/gui/print/PrintSimulationWorker.java
index 53a710c80..be4fbe6c9 100644
--- a/core/src/net/sf/openrocket/gui/print/PrintSimulationWorker.java
+++ b/core/src/net/sf/openrocket/gui/print/PrintSimulationWorker.java
@@ -4,7 +4,7 @@
package net.sf.openrocket.gui.print;
import net.sf.openrocket.document.Simulation;
-import net.sf.openrocket.gui.main.SimulationWorker;
+import net.sf.openrocket.gui.simulation.SimulationWorker;
import net.sf.openrocket.simulation.FlightData;
/**
diff --git a/core/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java b/core/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java
index 70e9928e8..5ae1d1581 100644
--- a/core/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java
+++ b/core/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java
@@ -54,8 +54,8 @@ import net.sf.openrocket.gui.figureelements.CGCaret;
import net.sf.openrocket.gui.figureelements.CPCaret;
import net.sf.openrocket.gui.figureelements.Caret;
import net.sf.openrocket.gui.figureelements.RocketInfo;
-import net.sf.openrocket.gui.main.SimulationWorker;
import net.sf.openrocket.gui.main.componenttree.ComponentTreeModel;
+import net.sf.openrocket.gui.simulation.SimulationWorker;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.masscalc.BasicMassCalculator;
diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationConditionsPanel.java b/core/src/net/sf/openrocket/gui/simulation/SimulationConditionsPanel.java
new file mode 100644
index 000000000..2839704b1
--- /dev/null
+++ b/core/src/net/sf/openrocket/gui/simulation/SimulationConditionsPanel.java
@@ -0,0 +1,441 @@
+package net.sf.openrocket.gui.simulation;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSpinner;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.document.Simulation;
+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.UnitSelector;
+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.startup.Application;
+import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.util.Chars;
+
+public class SimulationConditionsPanel extends JPanel {
+ private static final Translator trans = Application.getTranslator();
+
+
+ SimulationConditionsPanel(final Simulation simulation) {
+ super(new MigLayout("fill"));
+
+ final SimulationOptions conditions = simulation.getOptions();
+
+ JPanel sub;
+ String tip;
+ UnitSelector unit;
+ BasicSlider slider;
+ DoubleModel m;
+ JSpinner spin;
+
+ //// Wind settings: Average wind speed, turbulence intensity, std. deviation
+ 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"));
+ //// The standard deviation of the windspeed.
+ //// 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"));
+ //// The turbulence intensity is the standard deviation divided by the average windspeed.
+ //// 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()));
+ }
+ });
+
+
+
+
+
+ //// Temperature and pressure
+ sub = new JPanel(new MigLayout("fill, gap rel unrel",
+ "[grow][65lp!][30lp!][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"));
+ //// Select to use the International Standard Atmosphere model.
+ ////
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);
+
+ m = new DoubleModel(conditions, "LaunchTemperature", UnitGroup.UNITS_TEMPERATURE, 0);
+
+ spin = new JSpinner(m.getSpinnerModel());
+ spin.setEditor(new SpinnerEditor(spin));
+ spin.setToolTipText(tip);
+ isa.addEnableComponent(spin, false);
+ sub.add(spin, "w 65lp!");
+
+ unit = new UnitSelector(m);
+ unit.setToolTipText(tip);
+ isa.addEnableComponent(unit, false);
+ sub.add(unit, "growx");
+ slider = new BasicSlider(m.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);
+
+ m = new DoubleModel(conditions, "LaunchPressure", UnitGroup.UNITS_PRESSURE, 0);
+
+ spin = new JSpinner(m.getSpinnerModel());
+ spin.setEditor(new SpinnerEditor(spin));
+ spin.setToolTipText(tip);
+ isa.addEnableComponent(spin, false);
+ sub.add(spin, "w 65lp!");
+
+ unit = new UnitSelector(m);
+ unit.setToolTipText(tip);
+ isa.addEnableComponent(unit, false);
+ sub.add(unit, "growx");
+ slider = new BasicSlider(m.getSliderModel(0.950e5, 1.050e5));
+ slider.setToolTipText(tip);
+ isa.addEnableComponent(slider, false);
+ sub.add(slider, "w 75lp, wrap");
+
+
+
+
+
+ //// 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"));
+ //// The launch site latitude affects the gravitational pull of Earth.
+ //// 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"));
+ //// The launch altitude above mean sea level.
+ //// 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");
+
+
+
+ // 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,
+ 0, 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(0, Math.PI / 9,
+ SimulationOptions.MAX_LAUNCH_ROD_ANGLE));
+ slider.setToolTipText(tip);
+ sub.add(slider, "w 75lp, wrap");
+
+
+
+ // Direction:
+ label = new JLabel(trans.get("simedtdlg.lbl.Direction"));
+ //// Direction of the launch rod relative to the wind.
+ //// = towards the wind,
+ //// = downwind.
+ tip = trans.get("simedtdlg.lbl.ttip.Direction1") +
+ UnitGroup.UNITS_ANGLE.toStringUnit(0) +
+ " " + trans.get("simedtdlg.lbl.ttip.Direction2") + " " +
+ UnitGroup.UNITS_ANGLE.toStringUnit(Math.PI) +
+ " " + trans.get("simedtdlg.lbl.ttip.Direction3");
+ label.setToolTipText(tip);
+ sub.add(label);
+
+ m = new DoubleModel(conditions, "LaunchRodDirection", UnitGroup.UNITS_ANGLE,
+ -Math.PI, 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(-Math.PI, Math.PI));
+ slider.setToolTipText(tip);
+ sub.add(slider, "w 75lp, wrap");
+
+ JButton restoreDefaults = new JButton(trans.get("simedtdlg.but.resettodefault"));
+ restoreDefaults.addActionListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+
+ DefaultSimulationOptionFactory f = Application.getInjector().getInstance(DefaultSimulationOptionFactory.class);
+ SimulationOptions defaults = f.getDefault();
+ conditions.copyConditionsFrom(defaults);
+
+ }
+
+ });
+ this.add(restoreDefaults, "span, split 3, skip, gapbottom para, gapright para, right");
+
+ JButton saveDefaults = new JButton(trans.get("simedtdlg.but.savedefault"));
+ saveDefaults.addActionListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+
+ DefaultSimulationOptionFactory f = Application.getInjector().getInstance(DefaultSimulationOptionFactory.class);
+ f.saveDefault(conditions);
+
+ }
+
+ });
+
+ this.add(saveDefaults, "gapbottom para, gapright para, right");
+
+ }
+
+ 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");
+ }
+
+}
diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java b/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java
new file mode 100644
index 000000000..cdaf9e0c1
--- /dev/null
+++ b/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java
@@ -0,0 +1,298 @@
+package net.sf.openrocket.gui.simulation;
+
+
+import java.awt.CardLayout;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.gui.adaptors.FlightConfigurationModel;
+import net.sf.openrocket.gui.dialogs.flightconfiguration.FlightConfigurationDialog;
+import net.sf.openrocket.gui.util.GUIUtil;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.rocketcomponent.Configuration;
+import net.sf.openrocket.simulation.SimulationOptions;
+import net.sf.openrocket.startup.Application;
+
+
+public class SimulationEditDialog extends JDialog {
+
+ private final Window parentWindow;
+ private final Simulation[] simulation;
+ private final OpenRocketDocument document;
+ private final SimulationOptions conditions;
+ private final Configuration configuration;
+ private static final Translator trans = Application.getTranslator();
+
+ JPanel cards;
+ private final static String EDITMODE = "EDIT";
+ private final static String PLOTMODE = "PLOT";
+
+ public SimulationEditDialog(Window parent, final OpenRocketDocument document, Simulation... sims) {
+ //// Edit simulation
+ super(parent, trans.get("simedtdlg.title.Editsim"), JDialog.ModalityType.DOCUMENT_MODAL);
+ this.document = document;
+ this.parentWindow = parent;
+ this.simulation = sims;
+ this.conditions = simulation[0].getOptions();
+ configuration = simulation[0].getConfiguration();
+
+ this.cards = new JPanel(new CardLayout());
+ this.add(cards);
+ buildEditCard();
+ buildPlotCard();
+
+ this.validate();
+ this.pack();
+
+ this.setLocationByPlatform(true);
+
+ GUIUtil.setDisposableDialogOptions(this, null);
+ }
+
+ private boolean isSingleEdit() {
+ return simulation.length == 1;
+ }
+
+ private boolean allowsPlotMode() {
+ return simulation.length == 1 && simulation[0].hasSimulationData();
+ }
+
+ public void setEditMode() {
+ CardLayout cl = (CardLayout) (cards.getLayout());
+ cl.show(cards, EDITMODE);
+ cards.validate();
+ }
+
+ public void setPlotMode() {
+ if (!allowsPlotMode()) {
+ return;
+ }
+ CardLayout cl = (CardLayout) (cards.getLayout());
+ cl.show(cards, PLOTMODE);
+ cards.validate();
+ }
+
+ private void copyChangesToAllSims() {
+ if (simulation.length > 1) {
+ for (int i = 1; i < simulation.length; i++) {
+ simulation[i].getOptions().copyConditionsFrom(simulation[0].getOptions());
+ simulation[i].getSimulationListeners().clear();
+ simulation[i].getSimulationListeners().addAll(simulation[0].getSimulationListeners());
+ }
+ }
+ }
+
+ private void refreshView() {
+ cards.removeAll();
+ buildEditCard();
+ buildPlotCard();
+ this.validate();
+ }
+
+ private void buildEditCard() {
+ JPanel simEditPanel = new JPanel(new MigLayout("fill"));
+
+ if (isSingleEdit()) {
+ //// Simulation name:
+ simEditPanel.add(new JLabel(trans.get("simedtdlg.lbl.Simname") + " "), "span, split 2, shrink");
+ final JTextField field = new JTextField(simulation[0].getName());
+ field.getDocument().addDocumentListener(new DocumentListener() {
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+ setText();
+ }
+
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ setText();
+ }
+
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ setText();
+ }
+
+ private void setText() {
+ String name = field.getText();
+ if (name == null || name.equals(""))
+ return;
+ //System.out.println("Setting name:" + name);
+ simulation[0].setName(name);
+
+ }
+ });
+ simEditPanel.add(field, "shrinky, growx, wrap");
+
+ //// Flight selector
+ //// Flight configuration:
+ JLabel label = new JLabel(trans.get("simedtdlg.lbl.Flightcfg"));
+ //// Select the motor configuration to use.
+ label.setToolTipText(trans.get("simedtdlg.lbl.ttip.Flightcfg"));
+ simEditPanel.add(label, "span, split 2, shrink");
+
+ JComboBox combo = new JComboBox(new FlightConfigurationModel(configuration));
+ //// Select the motor configuration to use.
+ combo.setToolTipText(trans.get("simedtdlg.combo.ttip.Flightcfg"));
+ combo.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ conditions.setMotorConfigurationID(configuration.getFlightConfigurationID());
+ }
+ });
+ simEditPanel.add(combo, "split 2, shrink");
+
+ //// Edit button
+ JButton button = new JButton(trans.get("simedtdlg.but.FlightcfgEdit"));
+ button.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ JDialog configDialog = new FlightConfigurationDialog(SimulationEditDialog.this.document.getRocket(), SwingUtilities.windowForComponent(SimulationEditDialog.this));
+ configDialog.setVisible(true);
+ }
+ });
+ simEditPanel.add(button, "shrink, align left, wrap");
+ }
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ //// Launch conditions
+ tabbedPane.addTab(trans.get("simedtdlg.tab.Launchcond"), new SimulationConditionsPanel(simulation[0]));
+ //// Simulation options
+ tabbedPane.addTab(trans.get("simedtdlg.tab.Simopt"), new SimulationOptionsPanel(simulation[0]));
+
+ tabbedPane.setSelectedIndex(0);
+
+ simEditPanel.add(tabbedPane, "spanx, grow, wrap");
+
+
+ //// Open Plot button
+ JButton button = new JButton("< getColumnClass(int column) {
+ switch (column) {
+ case SELECTED:
+ return Boolean.class;
+ case NAME:
+ return FlightDataType.class;
+ case UNIT:
+ return Unit.class;
+ default:
+ throw new IndexOutOfBoundsException("column=" + column);
+ }
+ }
+
+ @Override
+ public Object getValueAt(int row, int column) {
+
+ switch (column) {
+ case SELECTED:
+ return selected[row];
+
+ case NAME:
+ return types[row];
+
+ case UNIT:
+ return units[row];
+
+ default:
+ throw new IndexOutOfBoundsException("column=" + column);
+ }
+
+ }
+
+ @Override
+ public void setValueAt(Object value, int row, int column) {
+
+ switch (column) {
+ case SELECTED:
+ selected[row] = (Boolean) value;
+ this.fireTableRowsUpdated(row, row);
+ updateSelectedCount();
+ break;
+
+ case NAME:
+ break;
+
+ case UNIT:
+ units[row] = (Unit) value;
+ break;
+
+ default:
+ throw new IndexOutOfBoundsException("column=" + column);
+ }
+
+ }
+
+ @Override
+ public boolean isCellEditable(int row, int column) {
+ switch (column) {
+ case SELECTED:
+ return true;
+
+ case NAME:
+ return false;
+
+ case UNIT:
+ return types[row].getUnitGroup().getUnitCount() > 1;
+
+ default:
+ throw new IndexOutOfBoundsException("column=" + column);
+ }
+ }
+
+ public void selectAll() {
+ Arrays.fill(selected, true);
+ updateSelectedCount();
+ this.fireTableDataChanged();
+ }
+
+ public void selectNone() {
+ Arrays.fill(selected, false);
+ updateSelectedCount();
+ this.fireTableDataChanged();
+ }
+
+ }
+
+}
diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationOptionsPanel.java b/core/src/net/sf/openrocket/gui/simulation/SimulationOptionsPanel.java
new file mode 100644
index 000000000..c7b0fe023
--- /dev/null
+++ b/core/src/net/sf/openrocket/gui/simulation/SimulationOptionsPanel.java
@@ -0,0 +1,294 @@
+package net.sf.openrocket.gui.simulation;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Arrays;
+
+import javax.swing.AbstractListModel;
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSpinner;
+import javax.swing.ListCellRenderer;
+import javax.swing.SwingUtilities;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.gui.SpinnerEditor;
+import net.sf.openrocket.gui.adaptors.DoubleModel;
+import net.sf.openrocket.gui.adaptors.EnumModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.DescriptionArea;
+import net.sf.openrocket.gui.components.UnitSelector;
+import net.sf.openrocket.gui.util.Icons;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.simulation.RK4SimulationStepper;
+import net.sf.openrocket.simulation.SimulationOptions;
+import net.sf.openrocket.simulation.listeners.SimulationListener;
+import net.sf.openrocket.simulation.listeners.example.CSVSaveListener;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.util.GeodeticComputationStrategy;
+
+class SimulationOptionsPanel extends JPanel {
+
+ private static final Translator trans = Application.getTranslator();
+
+ final Simulation simulation;
+
+ SimulationOptionsPanel(final Simulation simulation) {
+ super(new MigLayout("fill"));
+ this.simulation = simulation;
+
+ final SimulationOptions conditions = simulation.getOptions();
+
+ JPanel sub, subsub;
+ String tip;
+ JLabel label;
+ DoubleModel m;
+ JSpinner spin;
+ UnitSelector unit;
+ BasicSlider slider;
+
+
+ //// Simulation options
+ sub = new JPanel(new MigLayout("fill, gap rel unrel",
+ "[grow][65lp!][30lp!][75lp!]", ""));
+ //// Simulator options
+ sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Simopt")));
+ this.add(sub, "growx, growy, aligny 0");
+
+
+ // Separate panel for computation methods, as they use a different layout
+ subsub = new JPanel(new MigLayout("insets 0, fill"));
+
+
+ //// Calculation method:
+ tip = trans.get("simedtdlg.lbl.ttip.Calcmethod");
+ label = new JLabel(trans.get("simedtdlg.lbl.Calcmethod"));
+ label.setToolTipText(tip);
+ subsub.add(label, "gapright para");
+
+ //// Extended Barrowman
+ label = new JLabel(trans.get("simedtdlg.lbl.ExtBarrowman"));
+ label.setToolTipText(tip);
+ subsub.add(label, "growx, wrap para");
+
+
+ // Simulation method
+ tip = trans.get("simedtdlg.lbl.ttip.Simmethod1") +
+ trans.get("simedtdlg.lbl.ttip.Simmethod2");
+ label = new JLabel(trans.get("simedtdlg.lbl.Simmethod"));
+ label.setToolTipText(tip);
+ subsub.add(label, "gapright para");
+
+ label = new JLabel("6-DOF Runge-Kutta 4");
+ label.setToolTipText(tip);
+ subsub.add(label, "growx, wrap para");
+
+
+ //// Geodetic calculation method:
+ label = new JLabel(trans.get("simedtdlg.lbl.GeodeticMethod"));
+ label.setToolTipText(trans.get("simedtdlg.lbl.ttip.GeodeticMethodTip"));
+ subsub.add(label, "gapright para");
+
+ EnumModel gcsModel = new EnumModel(conditions, "GeodeticComputation");
+ final JComboBox gcsCombo = new JComboBox(gcsModel);
+ ActionListener gcsTTipListener = new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ GeodeticComputationStrategy gcs = (GeodeticComputationStrategy) gcsCombo.getSelectedItem();
+ gcsCombo.setToolTipText(gcs.getDescription());
+ }
+ };
+ gcsCombo.addActionListener(gcsTTipListener);
+ gcsTTipListener.actionPerformed(null);
+ subsub.add(gcsCombo, "growx, wrap para");
+
+ sub.add(subsub, "spanx, wrap para");
+
+
+ //// Time step:
+ label = new JLabel(trans.get("simedtdlg.lbl.Timestep"));
+ tip = trans.get("simedtdlg.lbl.ttip.Timestep1") +
+ trans.get("simedtdlg.lbl.ttip.Timestep2") + " " +
+ UnitGroup.UNITS_TIME_STEP.toStringUnit(RK4SimulationStepper.RECOMMENDED_TIME_STEP) +
+ ".";
+ label.setToolTipText(tip);
+ sub.add(label);
+
+ m = new DoubleModel(conditions, "TimeStep", UnitGroup.UNITS_TIME_STEP, 0, 1);
+
+ spin = new JSpinner(m.getSpinnerModel());
+ spin.setEditor(new SpinnerEditor(spin));
+ spin.setToolTipText(tip);
+ sub.add(spin, "w 65lp!");
+ //sub.add(spin, "nogrid");
+
+ unit = new UnitSelector(m);
+ unit.setToolTipText(tip);
+ sub.add(unit, "w 25");
+ //sub.add(unit, "nogrid");
+ slider = new BasicSlider(m.getSliderModel(0, 0.2));
+ slider.setToolTipText(tip);
+ sub.add(slider, "w 75lp, wrap");
+ //sub.add(slider,"wrap");
+
+
+
+
+ //// Reset to default button
+ JButton button = new JButton(trans.get("simedtdlg.but.resettodefault"));
+ //// Reset the time step to its default value (
+ button.setToolTipText(trans.get("simedtdlg.but.ttip.resettodefault") +
+ UnitGroup.UNITS_SHORT_TIME.toStringUnit(RK4SimulationStepper.RECOMMENDED_TIME_STEP) +
+ ").");
+ button.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ conditions.setTimeStep(RK4SimulationStepper.RECOMMENDED_TIME_STEP);
+ conditions.setGeodeticComputation(GeodeticComputationStrategy.SPHERICAL);
+ }
+ });
+
+ sub.add(button, "align left");
+
+
+
+
+ //// Simulation listeners
+ sub = new JPanel(new MigLayout("fill, gap 0 0"));
+ //// Simulator listeners
+ sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Simlist")));
+ this.add(sub, "growx, growy");
+
+
+ DescriptionArea desc = new DescriptionArea(5);
+ //// Simulation listeners is an advanced feature that allows user-written code to listen to and interact with the simulation.
+ //// For details on writing simulation listeners, see the OpenRocket technical documentation.
+ desc.setText(trans.get("simedtdlg.txt.longA1") +
+ trans.get("simedtdlg.txt.longA2"));
+ sub.add(desc, "aligny 0, growx, wrap para");
+
+ //// Current listeners:
+ label = new JLabel(trans.get("simedtdlg.lbl.Curlist"));
+ sub.add(label, "spanx, wrap rel");
+
+ final ListenerListModel listenerModel = new ListenerListModel();
+ final JList list = new JList(listenerModel);
+ list.setCellRenderer(new ListenerCellRenderer());
+ JScrollPane scroll = new JScrollPane(list);
+ // scroll.setPreferredSize(new Dimension(1,1));
+ sub.add(scroll, "height 1px, grow, wrap rel");
+
+ //// Add button
+ button = new JButton(trans.get("simedtdlg.but.add"));
+ button.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String previous = Application.getPreferences().getString("previousListenerName", "");
+ String input = (String) JOptionPane.showInputDialog(SwingUtilities.getRoot(SimulationOptionsPanel.this),
+ new Object[] {
+ //// Type the full Java class name of the simulation listener, for example:
+ "Type the full Java class name of the simulation listener, for example:",
+ "" + CSVSaveListener.class.getName() + "" },
+ //// Add simulation listener
+ trans.get("simedtdlg.lbl.Addsimlist"),
+ JOptionPane.QUESTION_MESSAGE,
+ null, null,
+ previous
+ );
+ if (input == null || input.equals(""))
+ return;
+
+ Application.getPreferences().putString("previousListenerName", input);
+ simulation.getSimulationListeners().add(input);
+ listenerModel.fireContentsChanged();
+ }
+ });
+ sub.add(button, "split 2, sizegroup buttons, alignx 50%, gapright para");
+
+ //// Remove button
+ button = new JButton(trans.get("simedtdlg.but.remove"));
+ button.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ int[] selected = list.getSelectedIndices();
+ Arrays.sort(selected);
+ for (int i = selected.length - 1; i >= 0; i--) {
+ simulation.getSimulationListeners().remove(selected[i]);
+ }
+ listenerModel.fireContentsChanged();
+ }
+ });
+ sub.add(button, "sizegroup buttons, alignx 50%");
+
+
+ }
+
+ private class ListenerCellRenderer extends JLabel implements ListCellRenderer {
+
+ @Override
+ public Component getListCellRendererComponent(JList list, Object value,
+ int index, boolean isSelected, boolean cellHasFocus) {
+ String s = value.toString();
+ setText(s);
+
+ // Attempt instantiating, catch any exceptions
+ Exception ex = null;
+ try {
+ Class> c = Class.forName(s);
+ @SuppressWarnings("unused")
+ SimulationListener l = (SimulationListener) c.newInstance();
+ } catch (Exception e) {
+ ex = e;
+ }
+
+ if (ex == null) {
+ setIcon(Icons.SIMULATION_LISTENER_OK);
+ //// Listener instantiated successfully.
+ setToolTipText("Listener instantiated successfully.");
+ } else {
+ setIcon(Icons.SIMULATION_LISTENER_ERROR);
+ //// Unable to instantiate listener due to exception:
+ setToolTipText("Unable to instantiate listener due to exception:
" +
+ ex.toString());
+ }
+
+ if (isSelected) {
+ setBackground(list.getSelectionBackground());
+ setForeground(list.getSelectionForeground());
+ } else {
+ setBackground(list.getBackground());
+ setForeground(list.getForeground());
+ }
+ setOpaque(true);
+ return this;
+ }
+ }
+
+ private class ListenerListModel extends AbstractListModel {
+ @Override
+ public String getElementAt(int index) {
+ if (index < 0 || index >= getSize())
+ return null;
+ return simulation.getSimulationListeners().get(index);
+ }
+
+ @Override
+ public int getSize() {
+ return simulation.getSimulationListeners().size();
+ }
+
+ public void fireContentsChanged() {
+ super.fireContentsChanged(this, 0, getSize());
+ }
+ }
+
+}
diff --git a/core/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java b/core/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java
similarity index 91%
rename from core/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java
rename to core/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java
index 5a8787b28..40c3ebba2 100644
--- a/core/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java
+++ b/core/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java
@@ -1,5 +1,6 @@
-package net.sf.openrocket.gui.plot;
+package net.sf.openrocket.gui.simulation;
+import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
@@ -10,12 +11,12 @@ import java.util.EnumSet;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
+import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
-import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
@@ -24,6 +25,8 @@ import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.document.Simulation;
import net.sf.openrocket.gui.components.DescriptionArea;
import net.sf.openrocket.gui.components.UnitSelector;
+import net.sf.openrocket.gui.plot.PlotConfiguration;
+import net.sf.openrocket.gui.plot.SimulationPlotDialog;
import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.gui.util.Icons;
import net.sf.openrocket.l10n.Translator;
@@ -71,18 +74,18 @@ public class SimulationPlotPanel extends JPanel {
PRESET_ARRAY[PRESET_ARRAY.length - 1] = CUSTOM_CONFIGURATION;
}
-
-
+
+
/** The current default configuration, set each time a plot is made. */
private static PlotConfiguration defaultConfiguration =
PlotConfiguration.DEFAULT_CONFIGURATIONS[0].resetUnits();
-
+
private final Simulation simulation;
private final FlightDataType[] types;
private PlotConfiguration configuration;
-
+
private JComboBox configurationSelector;
private JComboBox domainTypeSelector;
@@ -91,7 +94,7 @@ public class SimulationPlotPanel extends JPanel {
private JPanel typeSelectorPanel;
private FlightEventTableModel eventTableModel;
-
+
private int modifying = 0;
@@ -107,7 +110,7 @@ public class SimulationPlotPanel extends JPanel {
types = branch.getTypes();
setConfiguration(defaultConfiguration);
-
+
//// Configuration selector
// Setup the combo box
@@ -126,7 +129,7 @@ public class SimulationPlotPanel extends JPanel {
// the UI when the selected item changes.
// TODO - this should probably be implemented as an ActionListener instead
// of ItemStateListener.
- if ( e.getStateChange() == ItemEvent.DESELECTED) {
+ if (e.getStateChange() == ItemEvent.DESELECTED) {
return;
}
if (modifying > 0)
@@ -144,8 +147,8 @@ public class SimulationPlotPanel extends JPanel {
this.add(new JLabel(trans.get("simplotpanel.lbl.Presetplotconf")), "spanx, split");
this.add(configurationSelector, "growx, wrap 20lp");
-
-
+
+
//// X axis
//// X axis type:
@@ -185,8 +188,8 @@ public class SimulationPlotPanel extends JPanel {
desc.setViewportBorder(BorderFactory.createEmptyBorder());
this.add(desc, "width 1px, growx 1, wrap unrel");
-
-
+
+
//// Y axis selector panel
//// Y axis types:
this.add(new JLabel(trans.get("simplotpanel.lbl.Yaxistypes")));
@@ -197,7 +200,7 @@ public class SimulationPlotPanel extends JPanel {
JScrollPane scroll = new JScrollPane(typeSelectorPanel);
this.add(scroll, "spany 2, height 10px, wmin 400lp, grow 100, gapright para");
-
+
//// Flight events
eventTableModel = new FlightEventTableModel();
JTable table = new JTable(eventTableModel);
@@ -213,9 +216,9 @@ public class SimulationPlotPanel extends JPanel {
col0.setPreferredWidth(w);
col0.setMaxWidth(w);
table.addMouseListener(new GUIUtil.BooleanTableClickListener(table));
- this.add(new JScrollPane(table), "height 10px, width 200lp, grow 1, wrap rel");
+ this.add(new JScrollPane(table), "height 200px, width 200lp, grow 1, wrap rel");
+
-
//// All + None buttons
JButton button = new JButton(trans.get("simplotpanel.but.All"));
button.addActionListener(new ActionListener() {
@@ -240,8 +243,8 @@ public class SimulationPlotPanel extends JPanel {
});
this.add(button, "gapleft para, gapright para, growx, sizegroup buttons, wrap para");
-
-
+
+
//// New Y axis plot type
button = new JButton(trans.get("simplotpanel.but.NewYaxisplottype"));
button.addActionListener(new ActionListener() {
@@ -260,40 +263,41 @@ public class SimulationPlotPanel extends JPanel {
// Select new type smartly
FlightDataType type = null;
for (FlightDataType t :
- simulation.getSimulatedData().getBranch(0).getTypes()) {
-
- boolean used = false;
- if (configuration.getDomainAxisType().equals(t)) {
- used = true;
- } else {
- for (int i = 0; i < configuration.getTypeCount(); i++) {
- if (configuration.getType(i).equals(t)) {
- used = true;
- break;
- }
+ simulation.getSimulatedData().getBranch(0).getTypes()) {
+
+ boolean used = false;
+ if (configuration.getDomainAxisType().equals(t)) {
+ used = true;
+ } else {
+ for (int i = 0; i < configuration.getTypeCount(); i++) {
+ if (configuration.getType(i).equals(t)) {
+ used = true;
+ break;
}
}
-
- if (!used) {
- type = t;
- break;
- }
- }
- if (type == null) {
- type = simulation.getSimulatedData().getBranch(0).getTypes()[0];
}
- // Add new type
- configuration.addPlotDataType(type);
- setToCustom();
- updatePlots();
+ if (!used) {
+ type = t;
+ break;
+ }
}
+ if (type == null) {
+ type = simulation.getSimulatedData().getBranch(0).getTypes()[0];
+ }
+
+ // Add new type
+ configuration.addPlotDataType(type);
+ setToCustom();
+ updatePlots();
+ }
});
this.add(button, "spanx, split");
-
+
this.add(new JPanel(), "growx");
+ /*
//// Plot flight
button = new JButton(trans.get("simplotpanel.but.Plotflight"));
button.addActionListener(new ActionListener() {
@@ -312,10 +316,21 @@ public class SimulationPlotPanel extends JPanel {
}
});
this.add(button, "right");
-
+ */
updatePlots();
}
+ public JDialog doPlot(Window parent) {
+ if (configuration.getTypeCount() == 0) {
+ JOptionPane.showMessageDialog(SimulationPlotPanel.this,
+ trans.get("error.noPlotSelected"),
+ trans.get("error.noPlotSelected.title"),
+ JOptionPane.ERROR_MESSAGE);
+ return null;
+ }
+ defaultConfiguration = configuration.clone();
+ return SimulationPlotDialog.getPlot(parent, simulation, configuration);
+ }
private void setConfiguration(PlotConfiguration conf) {
@@ -366,14 +381,14 @@ public class SimulationPlotPanel extends JPanel {
// In order to consistantly update the ui, we need to validate before repaint.
typeSelectorPanel.validate();
- typeSelectorPanel.repaint();
+ typeSelectorPanel.repaint();
eventTableModel.fireTableDataChanged();
}
-
-
+
+
/**
* A JPanel which configures a single plot of a PlotConfiguration.
*/
@@ -443,7 +458,7 @@ public class SimulationPlotPanel extends JPanel {
});
this.add(axisSelector);
-
+
JButton button = new JButton(Icons.DELETE);
//// Remove this plot
button.setToolTipText(trans.get("simplotpanel.but.ttip.Removethisplot"));
@@ -461,7 +476,7 @@ public class SimulationPlotPanel extends JPanel {
}
-
+
private class FlightEventTableModel extends AbstractTableModel {
private final FlightEvent.Type[] eventTypes;
diff --git a/core/src/net/sf/openrocket/gui/main/SimulationRunDialog.java b/core/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java
similarity index 99%
rename from core/src/net/sf/openrocket/gui/main/SimulationRunDialog.java
rename to core/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java
index 25bb169c1..c770be0dc 100644
--- a/core/src/net/sf/openrocket/gui/main/SimulationRunDialog.java
+++ b/core/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java
@@ -1,4 +1,4 @@
-package net.sf.openrocket.gui.main;
+package net.sf.openrocket.gui.simulation;
import java.awt.Dialog;
@@ -23,9 +23,6 @@ import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.document.Simulation;
@@ -50,6 +47,9 @@ import net.sf.openrocket.unit.Unit;
import net.sf.openrocket.unit.UnitGroup;
import net.sf.openrocket.util.MathUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
public class SimulationRunDialog extends JDialog {
private static final Logger log = LoggerFactory.getLogger(SimulationRunDialog.class);
diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationWarningDialog.java b/core/src/net/sf/openrocket/gui/simulation/SimulationWarningDialog.java
new file mode 100644
index 000000000..45a9bfa80
--- /dev/null
+++ b/core/src/net/sf/openrocket/gui/simulation/SimulationWarningDialog.java
@@ -0,0 +1,32 @@
+package net.sf.openrocket.gui.simulation;
+
+import java.awt.Component;
+import java.util.ArrayList;
+
+import javax.swing.JOptionPane;
+
+import net.sf.openrocket.aerodynamics.Warning;
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.gui.dialogs.DetailDialog;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.startup.Application;
+
+public class SimulationWarningDialog {
+
+ private static final Translator trans = Application.getTranslator();
+
+ public static void showWarningDialog(Component parent, Simulation simulation) {
+
+ if (simulation.getSimulatedWarnings().size() > 0) {
+ ArrayList messages = new ArrayList();
+ messages.add(trans.get("SimuRunDlg.msg.errorOccurred"));
+ for (Warning m : simulation.getSimulatedWarnings()) {
+ messages.add(m.toString());
+ }
+ DetailDialog.showDetailedMessageDialog(parent,
+ messages.toArray(),
+ null, simulation.getName(), JOptionPane.ERROR_MESSAGE);
+ }
+
+ }
+}
diff --git a/core/src/net/sf/openrocket/gui/main/SimulationWorker.java b/core/src/net/sf/openrocket/gui/simulation/SimulationWorker.java
similarity index 98%
rename from core/src/net/sf/openrocket/gui/main/SimulationWorker.java
rename to core/src/net/sf/openrocket/gui/simulation/SimulationWorker.java
index f348fbcdb..201b4f22e 100644
--- a/core/src/net/sf/openrocket/gui/main/SimulationWorker.java
+++ b/core/src/net/sf/openrocket/gui/simulation/SimulationWorker.java
@@ -1,4 +1,4 @@
-package net.sf.openrocket.gui.main;
+package net.sf.openrocket.gui.simulation;
import java.util.Arrays;
@@ -86,7 +86,7 @@ public abstract class SimulationWorker extends SwingWorker {
/**
* The rocket begins to tumble.
*/
- TUMBLE(trans.get("FlightEvent.Type.TUMBLE"));
+ TUMBLE(trans.get("FlightEvent.Type.TUMBLE")),
+
+ /**
+ * Simulation aborted
+ */
+ EXCEPTION(trans.get("FlightEvent.Type.EXCEPTION"));
private final String name;
diff --git a/core/src/net/sf/openrocket/simulation/SimulationOptions.java b/core/src/net/sf/openrocket/simulation/SimulationOptions.java
index d47389b0d..f32c01407 100644
--- a/core/src/net/sf/openrocket/simulation/SimulationOptions.java
+++ b/core/src/net/sf/openrocket/simulation/SimulationOptions.java
@@ -452,6 +452,71 @@ public class SimulationOptions implements ChangeSource, Cloneable {
fireChangeEvent();
}
+ public void copyConditionsFrom(SimulationOptions src) {
+ // Be a little smart about triggering the change event.
+ // only do it if one of the "important" (user specified) parameters has really changed.
+ boolean isChanged = false;
+ if (this.launchAltitude != src.launchAltitude) {
+ isChanged = true;
+ this.launchAltitude = src.launchAltitude;
+ }
+ if (this.launchLatitude != src.launchLatitude) {
+ isChanged = true;
+ this.launchLatitude = src.launchLatitude;
+ }
+ if (this.launchLongitude != src.launchLongitude) {
+ isChanged = true;
+ this.launchLongitude = src.launchLongitude;
+ }
+ if (this.launchPressure != src.launchPressure) {
+ isChanged = true;
+ this.launchPressure = src.launchPressure;
+ }
+ if (this.launchRodAngle != src.launchRodAngle) {
+ isChanged = true;
+ this.launchRodAngle = src.launchRodAngle;
+ }
+ if (this.launchRodDirection != src.launchRodDirection) {
+ isChanged = true;
+ this.launchRodDirection = src.launchRodDirection;
+ }
+ if (this.launchRodLength != src.launchRodLength) {
+ isChanged = true;
+ this.launchRodLength = src.launchRodLength;
+ }
+ if (this.launchTemperature != src.launchTemperature) {
+ isChanged = true;
+ this.launchTemperature = src.launchTemperature;
+ }
+ if (this.maximumAngle != src.maximumAngle) {
+ isChanged = true;
+ this.maximumAngle = src.maximumAngle;
+ }
+ this.maximumAngle = src.maximumAngle;
+ if (this.timeStep != src.timeStep) {
+ isChanged = true;
+ this.timeStep = src.timeStep;
+ }
+ if (this.windAverage != src.windAverage) {
+ isChanged = true;
+ this.windAverage = src.windAverage;
+ }
+ if (this.windTurbulence != src.windTurbulence) {
+ isChanged = true;
+ this.windTurbulence = src.windTurbulence;
+ }
+ if (this.calculateExtras != src.calculateExtras) {
+ isChanged = true;
+ this.calculateExtras = src.calculateExtras;
+ }
+
+ if (isChanged) {
+ // Only copy the randomSeed if something else has changed.
+ // Honestly, I don't really see a need for that.
+ this.randomSeed = src.randomSeed;
+ fireChangeEvent();
+ }
+ }
/**
diff --git a/core/src/net/sf/openrocket/simulation/SimulationStepper.java b/core/src/net/sf/openrocket/simulation/SimulationStepper.java
index 90855c3cb..f218f387e 100644
--- a/core/src/net/sf/openrocket/simulation/SimulationStepper.java
+++ b/core/src/net/sf/openrocket/simulation/SimulationStepper.java
@@ -11,7 +11,7 @@ public interface SimulationStepper {
* @param status the current simulation status.
* @return a SimulationStatus suitable for simulating with this simulation stepper.
*/
- public SimulationStatus initialize(SimulationStatus status) throws SimulationException;
+ public SimulationStatus initialize(SimulationStatus status);
/**
* Perform one simulation time step.