Merge remote-tracking branch 'kruland/sims'
This commit is contained in:
commit
92ae04f85a
Binary file not shown.
@ -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
|
||||
|
@ -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 <code>hashCode</code> method compatible with the <code>equals</code> method.
|
||||
@ -85,8 +85,8 @@ public abstract class Warning {
|
||||
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);
|
||||
}
|
||||
@ -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));
|
||||
}
|
||||
|
||||
@ -289,40 +289,40 @@ public abstract class Warning {
|
||||
|
||||
|
||||
/** A <code>Warning</code> that the body diameter is discontinuous. */
|
||||
////Discontinuity in rocket body diameter.
|
||||
////Discontinuity in rocket body diameter.
|
||||
public static final Warning DISCONTINUITY =
|
||||
new Other(trans.get("Warning.DISCONTINUITY"));
|
||||
new Other(trans.get("Warning.DISCONTINUITY"));
|
||||
|
||||
/** A <code>Warning</code> 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 <code>Warning</code> 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 <code>Warning</code> 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"));
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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,58 +86,59 @@ 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());
|
||||
{
|
||||
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);
|
||||
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");
|
||||
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++) {
|
||||
@ -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();
|
||||
|
@ -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]);
|
||||
|
@ -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<String> seriesNames = Util.generateSeriesLabels(simulation);
|
||||
|
||||
@ -166,7 +166,7 @@ public class SimulationPlot {
|
||||
List<Double> plotx = thisBranch.get(domainType);
|
||||
List<Double> 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);
|
||||
|
@ -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,7 +111,7 @@ public class SimulationPlotDialog extends JDialog {
|
||||
//// Add series selection box
|
||||
ArrayList<String> stages = new ArrayList<String>();
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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"));
|
||||
//// <html>The standard deviation of the windspeed.<br>
|
||||
//// The windspeed is within twice the standard deviation from the average for 95% of the time.
|
||||
tip = trans.get("simedtdlg.lbl.ttip.Stddeviation");
|
||||
label.setToolTipText(tip);
|
||||
sub.add(label);
|
||||
|
||||
m = new DoubleModel(conditions, "WindSpeedDeviation", UnitGroup.UNITS_WINDSPEED, 0);
|
||||
DoubleModel m2 = new DoubleModel(conditions, "WindSpeedAverage", 0.25,
|
||||
UnitGroup.UNITS_COEFFICIENT, 0);
|
||||
|
||||
spin = new JSpinner(m.getSpinnerModel());
|
||||
spin.setEditor(new SpinnerEditor(spin));
|
||||
spin.setToolTipText(tip);
|
||||
sub.add(spin, "w 65lp!");
|
||||
|
||||
unit = new UnitSelector(m);
|
||||
unit.setToolTipText(tip);
|
||||
sub.add(unit, "growx");
|
||||
slider = new BasicSlider(m.getSliderModel(new DoubleModel(0), m2));
|
||||
slider.setToolTipText(tip);
|
||||
sub.add(slider, "w 75lp, wrap");
|
||||
|
||||
|
||||
// Wind turbulence intensity
|
||||
//// Turbulence intensity:
|
||||
label = new JLabel(trans.get("simedtdlg.lbl.Turbulenceintensity"));
|
||||
//// <html>The turbulence intensity is the standard deviation divided by the average windspeed.<br>
|
||||
//// Typical values range from
|
||||
//// to
|
||||
tip = trans.get("simedtdlg.lbl.ttip.Turbulenceintensity1") +
|
||||
trans.get("simedtdlg.lbl.ttip.Turbulenceintensity2") + " " +
|
||||
UnitGroup.UNITS_RELATIVE.getDefaultUnit().toStringUnit(0.05) +
|
||||
" " + trans.get("simedtdlg.lbl.ttip.Turbulenceintensity3") + " " +
|
||||
UnitGroup.UNITS_RELATIVE.getDefaultUnit().toStringUnit(0.20) + ".";
|
||||
label.setToolTipText(tip);
|
||||
sub.add(label);
|
||||
|
||||
m = new DoubleModel(conditions, "WindTurbulenceIntensity", UnitGroup.UNITS_RELATIVE, 0);
|
||||
|
||||
spin = new JSpinner(m.getSpinnerModel());
|
||||
spin.setEditor(new SpinnerEditor(spin));
|
||||
spin.setToolTipText(tip);
|
||||
sub.add(spin, "w 65lp!");
|
||||
|
||||
unit = new UnitSelector(m);
|
||||
unit.setToolTipText(tip);
|
||||
sub.add(unit, "growx");
|
||||
|
||||
final JLabel intensityLabel = new JLabel(
|
||||
getIntensityDescription(conditions.getWindTurbulenceIntensity()));
|
||||
intensityLabel.setToolTipText(tip);
|
||||
sub.add(intensityLabel, "w 75lp, wrap");
|
||||
m.addChangeListener(new ChangeListener() {
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
intensityLabel.setText(
|
||||
getIntensityDescription(conditions.getWindTurbulenceIntensity()));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//// 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"));
|
||||
//// <html>Select to use the International Standard Atmosphere model.
|
||||
//// <br>This model has a temperature of
|
||||
//// and a pressure of
|
||||
//// at sea level.
|
||||
check.setToolTipText(trans.get("simedtdlg.checkbox.ttip.InterStdAtmosphere1") + " " +
|
||||
UnitGroup.UNITS_TEMPERATURE.toStringUnit(ExtendedISAModel.STANDARD_TEMPERATURE) +
|
||||
" " + trans.get("simedtdlg.checkbox.ttip.InterStdAtmosphere2") + " " +
|
||||
UnitGroup.UNITS_PRESSURE.toStringUnit(ExtendedISAModel.STANDARD_PRESSURE) +
|
||||
" " + trans.get("simedtdlg.checkbox.ttip.InterStdAtmosphere3"));
|
||||
sub.add(check, "spanx, wrap unrel");
|
||||
|
||||
// Temperature:
|
||||
label = new JLabel(trans.get("simedtdlg.lbl.Temperature"));
|
||||
//// The temperature at the launch site.
|
||||
tip = trans.get("simedtdlg.lbl.ttip.Temperature");
|
||||
label.setToolTipText(tip);
|
||||
isa.addEnableComponent(label, false);
|
||||
sub.add(label);
|
||||
|
||||
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"));
|
||||
//// <html>The launch site latitude affects the gravitational pull of Earth.<br>
|
||||
//// Positive values are on the Northern hemisphere, negative values on the Southern hemisphere.
|
||||
tip = trans.get("simedtdlg.lbl.ttip.Latitude");
|
||||
label.setToolTipText(tip);
|
||||
sub.add(label);
|
||||
|
||||
m = new DoubleModel(conditions, "LaunchLatitude", UnitGroup.UNITS_NONE, -90, 90);
|
||||
|
||||
spin = new JSpinner(m.getSpinnerModel());
|
||||
spin.setEditor(new SpinnerEditor(spin));
|
||||
spin.setToolTipText(tip);
|
||||
sub.add(spin, "w 65lp!");
|
||||
|
||||
label = new JLabel(Chars.DEGREE + " N");
|
||||
label.setToolTipText(tip);
|
||||
sub.add(label, "growx");
|
||||
slider = new BasicSlider(m.getSliderModel(-90, 90));
|
||||
slider.setToolTipText(tip);
|
||||
sub.add(slider, "w 75lp, wrap");
|
||||
|
||||
|
||||
// Longitude:
|
||||
label = new JLabel(trans.get("simedtdlg.lbl.Longitude"));
|
||||
tip = trans.get("simedtdlg.lbl.ttip.Longitude");
|
||||
label.setToolTipText(tip);
|
||||
sub.add(label);
|
||||
|
||||
m = new DoubleModel(conditions, "LaunchLongitude", UnitGroup.UNITS_NONE, -180, 180);
|
||||
|
||||
spin = new JSpinner(m.getSpinnerModel());
|
||||
spin.setEditor(new SpinnerEditor(spin));
|
||||
spin.setToolTipText(tip);
|
||||
sub.add(spin, "w 65lp!");
|
||||
|
||||
label = new JLabel(Chars.DEGREE + " E");
|
||||
label.setToolTipText(tip);
|
||||
sub.add(label, "growx");
|
||||
slider = new BasicSlider(m.getSliderModel(-180, 180));
|
||||
slider.setToolTipText(tip);
|
||||
sub.add(slider, "w 75lp, wrap");
|
||||
|
||||
|
||||
// Altitude:
|
||||
label = new JLabel(trans.get("simedtdlg.lbl.Altitude"));
|
||||
//// <html>The launch altitude above mean sea level.<br>
|
||||
//// This affects the position of the rocket in the atmospheric model.
|
||||
tip = trans.get("simedtdlg.lbl.ttip.Altitude");
|
||||
label.setToolTipText(tip);
|
||||
sub.add(label);
|
||||
|
||||
m = new DoubleModel(conditions, "LaunchAltitude", UnitGroup.UNITS_DISTANCE, 0);
|
||||
|
||||
spin = new JSpinner(m.getSpinnerModel());
|
||||
spin.setEditor(new SpinnerEditor(spin));
|
||||
spin.setToolTipText(tip);
|
||||
sub.add(spin, "w 65lp!");
|
||||
|
||||
unit = new UnitSelector(m);
|
||||
unit.setToolTipText(tip);
|
||||
sub.add(unit, "growx");
|
||||
slider = new BasicSlider(m.getSliderModel(0, 250, 1000));
|
||||
slider.setToolTipText(tip);
|
||||
sub.add(slider, "w 75lp, wrap");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//// Launch rod
|
||||
sub = new JPanel(new MigLayout("fill, gap rel unrel",
|
||||
"[grow][65lp!][30lp!][75lp!]", ""));
|
||||
//// Launch rod
|
||||
sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Launchrod")));
|
||||
this.add(sub, "growx, aligny 0, wrap");
|
||||
|
||||
|
||||
// Length:
|
||||
label = new JLabel(trans.get("simedtdlg.lbl.Length"));
|
||||
//// The length of the launch rod.
|
||||
tip = trans.get("simedtdlg.lbl.ttip.Length");
|
||||
label.setToolTipText(tip);
|
||||
sub.add(label);
|
||||
|
||||
m = new DoubleModel(conditions, "LaunchRodLength", UnitGroup.UNITS_LENGTH, 0);
|
||||
|
||||
spin = new JSpinner(m.getSpinnerModel());
|
||||
spin.setEditor(new SpinnerEditor(spin));
|
||||
spin.setToolTipText(tip);
|
||||
sub.add(spin, "w 65lp!");
|
||||
|
||||
unit = new UnitSelector(m);
|
||||
unit.setToolTipText(tip);
|
||||
sub.add(unit, "growx");
|
||||
slider = new BasicSlider(m.getSliderModel(0, 1, 5));
|
||||
slider.setToolTipText(tip);
|
||||
sub.add(slider, "w 75lp, wrap");
|
||||
|
||||
|
||||
|
||||
// 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"));
|
||||
//// <html>Direction of the launch rod relative to the wind.<br>
|
||||
//// = 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");
|
||||
}
|
||||
|
||||
}
|
@ -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("<<Plot");
|
||||
button.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
SimulationEditDialog.this.setPlotMode();
|
||||
}
|
||||
|
||||
});
|
||||
simEditPanel.add(button, "spanx, split 3, align left");
|
||||
if (allowsPlotMode()) {
|
||||
button.setVisible(true);
|
||||
} else {
|
||||
button.setVisible(false);
|
||||
}
|
||||
|
||||
//// Run simulation button
|
||||
button = new JButton(trans.get("simedtdlg.but.runsimulation"));
|
||||
button.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
copyChangesToAllSims();
|
||||
SimulationRunDialog.runSimulations(parentWindow, SimulationEditDialog.this.document, simulation);
|
||||
refreshView();
|
||||
if (allowsPlotMode()) {
|
||||
setPlotMode();
|
||||
}
|
||||
}
|
||||
});
|
||||
simEditPanel.add(button, " align right, tag ok");
|
||||
|
||||
//// Close button
|
||||
JButton close = new JButton(trans.get("dlg.but.close"));
|
||||
close.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
copyChangesToAllSims();
|
||||
SimulationEditDialog.this.dispose();
|
||||
}
|
||||
});
|
||||
simEditPanel.add(close, "tag ok");
|
||||
|
||||
cards.add(simEditPanel, EDITMODE);
|
||||
}
|
||||
|
||||
private void buildPlotCard() {
|
||||
if (allowsPlotMode()) {
|
||||
JPanel plotExportPanel = new JPanel(new MigLayout("fill"));
|
||||
|
||||
//// Simulation name:
|
||||
plotExportPanel.add(new JLabel(trans.get("simedtdlg.lbl.Simname") + " "), "span, split 2, shrink");
|
||||
final JTextField field = new JTextField(simulation[0].getName());
|
||||
field.setEditable(false);
|
||||
plotExportPanel.add(field, "shrinky, growx, wrap");
|
||||
|
||||
final JTabbedPane tabbedPane = new JTabbedPane();
|
||||
|
||||
//// Plot data
|
||||
final SimulationPlotPanel plotTab = new SimulationPlotPanel(simulation[0]);
|
||||
tabbedPane.addTab(trans.get("simedtdlg.tab.Plotdata"), plotTab);
|
||||
//// Export data
|
||||
final SimulationExportPanel exportTab = new SimulationExportPanel(simulation[0]);
|
||||
tabbedPane.addTab(trans.get("simedtdlg.tab.Exportdata"), exportTab);
|
||||
|
||||
plotExportPanel.add(tabbedPane, "grow, wrap");
|
||||
|
||||
JButton button = new JButton("<<Edit");
|
||||
button.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
SimulationEditDialog.this.setEditMode();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
plotExportPanel.add(button, "spanx, split 3, align left");
|
||||
|
||||
JButton ok = new JButton(trans.get("dlg.but.ok"));
|
||||
ok.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
// If the simulation is out of date, run the simulation.
|
||||
if (simulation[0].getStatus() != Simulation.Status.UPTODATE) {
|
||||
new SimulationRunDialog(SimulationEditDialog.this.parentWindow, document, simulation[0]).setVisible(true);
|
||||
}
|
||||
|
||||
if (tabbedPane.getSelectedIndex() == 0) {
|
||||
JDialog plot = plotTab.doPlot(SimulationEditDialog.this.parentWindow);
|
||||
if (plot != null) {
|
||||
plot.setVisible(true);
|
||||
}
|
||||
} else {
|
||||
if (exportTab.doExport()) {
|
||||
SimulationEditDialog.this.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
plotExportPanel.add(ok, "tag ok, split 2");
|
||||
|
||||
//// Close button
|
||||
JButton close = new JButton(trans.get("dlg.but.close"));
|
||||
close.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
SimulationEditDialog.this.dispose();
|
||||
}
|
||||
});
|
||||
plotExportPanel.add(close, "tag cancel");
|
||||
//plotExportPanel.validate();
|
||||
cards.add(plotExportPanel, PLOTMODE);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,436 @@
|
||||
package net.sf.openrocket.gui.simulation;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JLabel;
|
||||
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.TableCellRenderer;
|
||||
import javax.swing.table.TableColumn;
|
||||
import javax.swing.table.TableColumnModel;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import net.sf.openrocket.document.Simulation;
|
||||
import net.sf.openrocket.gui.components.CsvOptionPanel;
|
||||
import net.sf.openrocket.gui.components.UnitCellEditor;
|
||||
import net.sf.openrocket.gui.util.FileHelper;
|
||||
import net.sf.openrocket.gui.util.GUIUtil;
|
||||
import net.sf.openrocket.gui.util.SaveCSVWorker;
|
||||
import net.sf.openrocket.gui.util.SwingPreferences;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.simulation.FlightData;
|
||||
import net.sf.openrocket.simulation.FlightDataBranch;
|
||||
import net.sf.openrocket.simulation.FlightDataType;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.unit.Unit;
|
||||
import net.sf.openrocket.unit.UnitGroup;
|
||||
|
||||
public class SimulationExportPanel extends JPanel {
|
||||
|
||||
private static final String SPACE = "SPACE";
|
||||
private static final String TAB = "TAB";
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
|
||||
private static final int OPTION_SIMULATION_COMMENTS = 0;
|
||||
private static final int OPTION_FIELD_DESCRIPTIONS = 1;
|
||||
private static final int OPTION_FLIGHT_EVENTS = 2;
|
||||
|
||||
private final JTable table;
|
||||
private final SelectionTableModel tableModel;
|
||||
private final JLabel selectedCountLabel;
|
||||
|
||||
private final Simulation simulation;
|
||||
private final FlightDataBranch branch;
|
||||
|
||||
private final boolean[] selected;
|
||||
private final FlightDataType[] types;
|
||||
private final Unit[] units;
|
||||
|
||||
private final CsvOptionPanel csvOptions;
|
||||
|
||||
|
||||
public SimulationExportPanel(Simulation sim) {
|
||||
super(new MigLayout("fill, flowy"));
|
||||
|
||||
JPanel panel;
|
||||
JButton button;
|
||||
|
||||
|
||||
this.simulation = sim;
|
||||
|
||||
// TODO: MEDIUM: Only exports primary branch
|
||||
|
||||
final FlightData data = simulation.getSimulatedData();
|
||||
|
||||
// Check that data exists
|
||||
if (data == null || data.getBranchCount() == 0 ||
|
||||
data.getBranch(0).getTypes().length == 0) {
|
||||
throw new IllegalArgumentException("No data for panel");
|
||||
}
|
||||
|
||||
|
||||
// Create the data model
|
||||
branch = data.getBranch(0);
|
||||
|
||||
types = branch.getTypes();
|
||||
Arrays.sort(types);
|
||||
|
||||
selected = new boolean[types.length];
|
||||
units = new Unit[types.length];
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
selected[i] = ((SwingPreferences) Application.getPreferences()).isExportSelected(types[i]);
|
||||
units[i] = types[i].getUnitGroup().getDefaultUnit();
|
||||
}
|
||||
|
||||
|
||||
//// Create the panel
|
||||
|
||||
|
||||
// Set up the variable selection table
|
||||
tableModel = new SelectionTableModel();
|
||||
table = new JTable(tableModel);
|
||||
table.setDefaultRenderer(Object.class,
|
||||
new SelectionBackgroundCellRenderer(table.getDefaultRenderer(Object.class)));
|
||||
table.setDefaultRenderer(Boolean.class,
|
||||
new SelectionBackgroundCellRenderer(table.getDefaultRenderer(Boolean.class)));
|
||||
table.setRowSelectionAllowed(false);
|
||||
table.setColumnSelectionAllowed(false);
|
||||
|
||||
table.setDefaultEditor(Unit.class, new UnitCellEditor() {
|
||||
@Override
|
||||
protected UnitGroup getUnitGroup(Unit value, int row, int column) {
|
||||
return types[row].getUnitGroup();
|
||||
}
|
||||
});
|
||||
|
||||
// Set column widths
|
||||
TableColumnModel columnModel = table.getColumnModel();
|
||||
TableColumn col = columnModel.getColumn(0);
|
||||
int w = table.getRowHeight();
|
||||
col.setMinWidth(w);
|
||||
col.setPreferredWidth(w);
|
||||
col.setMaxWidth(w);
|
||||
|
||||
col = columnModel.getColumn(1);
|
||||
col.setPreferredWidth(200);
|
||||
|
||||
col = columnModel.getColumn(2);
|
||||
col.setPreferredWidth(100);
|
||||
|
||||
table.addMouseListener(new GUIUtil.BooleanTableClickListener(table));
|
||||
|
||||
// Add table
|
||||
panel = new JPanel(new MigLayout("fill"));
|
||||
panel.setBorder(BorderFactory.createTitledBorder(trans.get("SimExpPan.border.Vartoexport")));
|
||||
|
||||
panel.add(new JScrollPane(table), "wmin 300lp, width 300lp, height 1, grow 100, wrap");
|
||||
|
||||
// Select all/none buttons
|
||||
button = new JButton(trans.get("SimExpPan.but.Selectall"));
|
||||
button.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
tableModel.selectAll();
|
||||
}
|
||||
});
|
||||
panel.add(button, "split 2, growx 1, sizegroup selectbutton");
|
||||
|
||||
button = new JButton(trans.get("SimExpPan.but.Selectnone"));
|
||||
button.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
tableModel.selectNone();
|
||||
}
|
||||
});
|
||||
panel.add(button, "growx 1, sizegroup selectbutton, wrap");
|
||||
|
||||
|
||||
selectedCountLabel = new JLabel();
|
||||
updateSelectedCount();
|
||||
panel.add(selectedCountLabel);
|
||||
|
||||
this.add(panel, "grow 100, wrap");
|
||||
|
||||
|
||||
// These need to be in the order of the OPTIONS_XXX indices
|
||||
csvOptions = new CsvOptionPanel(SimulationExportPanel.class,
|
||||
trans.get("SimExpPan.checkbox.Includesimudesc"),
|
||||
trans.get("SimExpPan.checkbox.ttip.Includesimudesc"),
|
||||
trans.get("SimExpPan.checkbox.Includefielddesc"),
|
||||
trans.get("SimExpPan.checkbox.ttip.Includefielddesc"),
|
||||
trans.get("SimExpPan.checkbox.Incflightevents"),
|
||||
trans.get("SimExpPan.checkbox.ttip.Incflightevents"));
|
||||
|
||||
this.add(csvOptions, "spany, split, growx 1");
|
||||
|
||||
|
||||
// Space-filling panel
|
||||
panel = new JPanel();
|
||||
this.add(panel, "width 1, height 1, grow 1");
|
||||
|
||||
/*
|
||||
// Export button
|
||||
button = new JButton(trans.get("SimExpPan.but.Exporttofile"));
|
||||
button.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
doExport();
|
||||
}
|
||||
});
|
||||
this.add(button, "gapbottom para, gapright para, right");
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
public boolean doExport() {
|
||||
JFileChooser chooser = new JFileChooser();
|
||||
chooser.setFileFilter(FileHelper.CSV_FILE_FILTER);
|
||||
chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory());
|
||||
|
||||
if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION)
|
||||
return false;
|
||||
|
||||
File file = chooser.getSelectedFile();
|
||||
if (file == null)
|
||||
return false;
|
||||
|
||||
file = FileHelper.ensureExtension(file, "csv");
|
||||
if (!FileHelper.confirmWrite(file, this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
String commentChar = csvOptions.getCommentCharacter();
|
||||
String fieldSep = csvOptions.getFieldSeparator();
|
||||
boolean simulationComment = csvOptions.getSelectionOption(OPTION_SIMULATION_COMMENTS);
|
||||
boolean fieldComment = csvOptions.getSelectionOption(OPTION_FIELD_DESCRIPTIONS);
|
||||
boolean eventComment = csvOptions.getSelectionOption(OPTION_FLIGHT_EVENTS);
|
||||
csvOptions.storePreferences();
|
||||
|
||||
// Store preferences and export
|
||||
int n = 0;
|
||||
((SwingPreferences) Application.getPreferences()).setDefaultDirectory(chooser.getCurrentDirectory());
|
||||
for (int i = 0; i < selected.length; i++) {
|
||||
((SwingPreferences) Application.getPreferences()).setExportSelected(types[i], selected[i]);
|
||||
if (selected[i])
|
||||
n++;
|
||||
}
|
||||
|
||||
|
||||
FlightDataType[] fieldTypes = new FlightDataType[n];
|
||||
Unit[] fieldUnits = new Unit[n];
|
||||
int pos = 0;
|
||||
for (int i = 0; i < selected.length; i++) {
|
||||
if (selected[i]) {
|
||||
fieldTypes[pos] = types[i];
|
||||
fieldUnits[pos] = units[i];
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldSep.equals(SPACE)) {
|
||||
fieldSep = " ";
|
||||
} else if (fieldSep.equals(TAB)) {
|
||||
fieldSep = "\t";
|
||||
}
|
||||
|
||||
|
||||
SaveCSVWorker.export(file, simulation, branch, fieldTypes, fieldUnits, fieldSep,
|
||||
commentChar, simulationComment, fieldComment, eventComment,
|
||||
SwingUtilities.getWindowAncestor(this));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void updateSelectedCount() {
|
||||
int total = selected.length;
|
||||
int n = 0;
|
||||
String str;
|
||||
|
||||
for (int i = 0; i < selected.length; i++) {
|
||||
if (selected[i])
|
||||
n++;
|
||||
}
|
||||
|
||||
if (n == 1) {
|
||||
//// Exporting 1 variable out of
|
||||
str = trans.get("SimExpPan.ExportingVar.desc1") + " " + total + ".";
|
||||
} else {
|
||||
//// Exporting
|
||||
//// variables out of
|
||||
str = trans.get("SimExpPan.ExportingVar.desc2") + " " + n + " " +
|
||||
trans.get("SimExpPan.ExportingVar.desc3") + " " + total + ".";
|
||||
}
|
||||
|
||||
selectedCountLabel.setText(str);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A table cell renderer that uses another renderer and sets the background and
|
||||
* foreground of the returned component based on the selection of the variable.
|
||||
*/
|
||||
private class SelectionBackgroundCellRenderer implements TableCellRenderer {
|
||||
|
||||
private final TableCellRenderer renderer;
|
||||
|
||||
public SelectionBackgroundCellRenderer(TableCellRenderer renderer) {
|
||||
this.renderer = renderer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(JTable myTable, Object value,
|
||||
boolean isSelected, boolean hasFocus, int row, int column) {
|
||||
|
||||
Component component = renderer.getTableCellRendererComponent(myTable,
|
||||
value, isSelected, hasFocus, row, column);
|
||||
|
||||
if (selected[row]) {
|
||||
component.setBackground(myTable.getSelectionBackground());
|
||||
component.setForeground(myTable.getSelectionForeground());
|
||||
} else {
|
||||
component.setBackground(myTable.getBackground());
|
||||
component.setForeground(myTable.getForeground());
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The table model for the variable selection.
|
||||
*/
|
||||
private class SelectionTableModel extends AbstractTableModel {
|
||||
private static final int SELECTED = 0;
|
||||
private static final int NAME = 1;
|
||||
private static final int UNIT = 2;
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return types.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int column) {
|
||||
switch (column) {
|
||||
case SELECTED:
|
||||
return "";
|
||||
case NAME:
|
||||
//// Variable
|
||||
return trans.get("SimExpPan.Col.Variable");
|
||||
case UNIT:
|
||||
//// Unit
|
||||
return trans.get("SimExpPan.Col.Unit");
|
||||
default:
|
||||
throw new IndexOutOfBoundsException("column=" + column);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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<GeodeticComputationStrategy> gcsModel = new EnumModel<GeodeticComputationStrategy>(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);
|
||||
//// <html><i>Simulation listeners</i> 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:",
|
||||
"<html><tt>" + CSVSaveListener.class.getName() + "</tt>" },
|
||||
//// 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);
|
||||
//// <html>Unable to instantiate listener due to exception:<br>
|
||||
setToolTipText("<html>Unable to instantiate listener due to exception:<br>" +
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
@ -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)
|
||||
@ -213,7 +216,7 @@ 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
|
||||
@ -260,40 +263,41 @@ public class SimulationPlotPanel extends JPanel {
|
||||
// Select new type smartly
|
||||
FlightDataType type = null;
|
||||
for (FlightDataType t :
|
||||
simulation.getSimulatedData().getBranch(0).getTypes()) {
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
|
@ -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);
|
@ -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<String> messages = new ArrayList<String>();
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package net.sf.openrocket.gui.main;
|
||||
package net.sf.openrocket.gui.simulation;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
@ -42,9 +42,9 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
private SimulationStepper landingStepper = new BasicLandingStepper();
|
||||
private SimulationStepper tumbleStepper = new BasicTumbleStepper();
|
||||
|
||||
// Constant holding 30 degress in radians. This is the AOA condition
|
||||
// Constant holding 10 degress in radians. This is the AOA condition
|
||||
// necessary to transistion to tumbling.
|
||||
private final static double AOA_TUMBLE_CONDITION = Math.PI / 3.0;
|
||||
private final static double AOA_TUMBLE_CONDITION = Math.PI / 9.0;
|
||||
|
||||
private SimulationStepper currentStepper;
|
||||
|
||||
@ -105,7 +105,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
return flightData;
|
||||
}
|
||||
|
||||
private FlightDataBranch simulateLoop() throws SimulationException {
|
||||
private FlightDataBranch simulateLoop() {
|
||||
|
||||
// Initialize the simulation
|
||||
currentStepper = flightStepper;
|
||||
@ -222,7 +222,9 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
|
||||
} catch (SimulationException e) {
|
||||
SimulationListenerHelper.fireEndSimulation(status, e);
|
||||
throw e;
|
||||
// Add FlightEvent for Abort.
|
||||
status.getFlightData().addEvent(new FlightEvent(FlightEvent.Type.EXCEPTION, status.getSimulationTime(), status.getConfiguration().getRocket(), e.getLocalizedMessage()));
|
||||
status.getWarnings().add(e.getLocalizedMessage());
|
||||
}
|
||||
|
||||
return status.getFlightData();
|
||||
|
@ -13,7 +13,7 @@ public class BasicLandingStepper extends AbstractSimulationStepper {
|
||||
private static final double RECOVERY_TIME_STEP = 0.5;
|
||||
|
||||
@Override
|
||||
public SimulationStatus initialize(SimulationStatus status) throws SimulationException {
|
||||
public SimulationStatus initialize(SimulationStatus status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ public class BasicTumbleStepper extends AbstractSimulationStepper {
|
||||
private static final double RECOVERY_TIME_STEP = 0.5;
|
||||
|
||||
@Override
|
||||
public SimulationStatus initialize(SimulationStatus status) throws SimulationException {
|
||||
public SimulationStatus initialize(SimulationStatus status) {
|
||||
return new BasicTumbleStatus(status);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,73 @@
|
||||
package net.sf.openrocket.simulation;
|
||||
|
||||
|
||||
import net.sf.openrocket.startup.Preferences;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class DefaultSimulationOptionFactory {
|
||||
|
||||
@Inject
|
||||
private Preferences prefs;
|
||||
|
||||
public static final String SIMCONDITION_WIND_SPEED = "SimConditionWindSpeed";
|
||||
public static final String SIMCONDITION_WIND_STDDEV = "SimConditionWindStdDev";
|
||||
public static final String SIMCONDITION_WIND_TURB = "SimConditionWindTurb";
|
||||
public static final String SIMCONDITION_SITE_LAT = "SimConditionSiteLat";
|
||||
public static final String SIMCONDITION_SITE_LON = "SimConditionSiteLon";
|
||||
public static final String SIMCONDITION_SITE_ALT = "SimConditionSiteAlt";
|
||||
public static final String SIMCONDITION_ATMOS_STD = "SimConditionsAtmosStd";
|
||||
public static final String SIMCONDITION_ATMOS_TEMP = "SimConditionsAtmosTemp";
|
||||
public static final String SIMCONDITION_ATMOS_PRESSURE = "SimConditionsAtmosPres";
|
||||
public static final String SIMCONDITION_ROD_LENGTH = "SimConditionsRodLength";
|
||||
public static final String SIMCONDITION_ROD_ANGLE = "SimConditionsRodAngle";
|
||||
public static final String SIMCONDITION_ROD_DIRECTION = "SimConditionsRodDirection";
|
||||
|
||||
public DefaultSimulationOptionFactory(Preferences prefs) {
|
||||
this.prefs = prefs;
|
||||
}
|
||||
|
||||
public DefaultSimulationOptionFactory() {
|
||||
prefs = null;
|
||||
}
|
||||
|
||||
public SimulationOptions getDefault() {
|
||||
SimulationOptions defaults = new SimulationOptions(null);
|
||||
if (prefs != null) {
|
||||
|
||||
defaults.setWindSpeedAverage(prefs.getDouble(SIMCONDITION_WIND_SPEED, defaults.getWindSpeedAverage()));
|
||||
defaults.setWindSpeedDeviation(prefs.getDouble(SIMCONDITION_WIND_STDDEV, defaults.getWindSpeedDeviation()));
|
||||
defaults.setWindTurbulenceIntensity(prefs.getDouble(SIMCONDITION_WIND_TURB, defaults.getWindTurbulenceIntensity()));
|
||||
|
||||
defaults.setLaunchLatitude(prefs.getDouble(SIMCONDITION_SITE_LAT, defaults.getLaunchLatitude()));
|
||||
defaults.setLaunchLongitude(prefs.getDouble(SIMCONDITION_SITE_LON, defaults.getLaunchLongitude()));
|
||||
defaults.setLaunchAltitude(prefs.getDouble(SIMCONDITION_SITE_ALT, defaults.getLaunchAltitude()));
|
||||
|
||||
defaults.setISAAtmosphere(prefs.getBoolean(SIMCONDITION_ATMOS_STD, defaults.isISAAtmosphere()));
|
||||
defaults.setLaunchTemperature(prefs.getDouble(SIMCONDITION_ATMOS_TEMP, defaults.getLaunchTemperature()));
|
||||
|
||||
defaults.setLaunchRodLength(prefs.getDouble(SIMCONDITION_ROD_LENGTH, defaults.getLaunchRodLength()));
|
||||
defaults.setLaunchRodAngle(prefs.getDouble(SIMCONDITION_ROD_ANGLE, defaults.getLaunchRodAngle()));
|
||||
defaults.setLaunchRodDirection(prefs.getDouble(SIMCONDITION_ROD_DIRECTION, defaults.getLaunchRodDirection()));
|
||||
}
|
||||
return defaults;
|
||||
}
|
||||
|
||||
public void saveDefault(SimulationOptions newDefaults) {
|
||||
|
||||
prefs.putDouble(SIMCONDITION_WIND_SPEED, newDefaults.getWindSpeedAverage());
|
||||
prefs.putDouble(SIMCONDITION_WIND_STDDEV, newDefaults.getWindSpeedDeviation());
|
||||
prefs.putDouble(SIMCONDITION_WIND_TURB, newDefaults.getWindTurbulenceIntensity());
|
||||
|
||||
prefs.putDouble(SIMCONDITION_SITE_LAT, newDefaults.getLaunchLatitude());
|
||||
prefs.putDouble(SIMCONDITION_SITE_LON, newDefaults.getLaunchLongitude());
|
||||
prefs.putDouble(SIMCONDITION_SITE_ALT, newDefaults.getLaunchAltitude());
|
||||
|
||||
prefs.putBoolean(SIMCONDITION_ATMOS_STD, newDefaults.isISAAtmosphere());
|
||||
prefs.putDouble(SIMCONDITION_ATMOS_TEMP, newDefaults.getLaunchTemperature());
|
||||
|
||||
prefs.putDouble(SIMCONDITION_ROD_LENGTH, newDefaults.getLaunchRodLength());
|
||||
prefs.putDouble(SIMCONDITION_ROD_ANGLE, newDefaults.getLaunchRodAngle());
|
||||
prefs.putDouble(SIMCONDITION_ROD_DIRECTION, newDefaults.getLaunchRodDirection());
|
||||
}
|
||||
}
|
@ -77,7 +77,12 @@ public class FlightEvent implements Comparable<FlightEvent> {
|
||||
/**
|
||||
* 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;
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user