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
|
! Simulation edit dialog
|
||||||
simedtdlg.but.runsimulation = Run simulation
|
simedtdlg.but.runsimulation = Run simulation
|
||||||
simedtdlg.but.resettodefault = Reset to default
|
simedtdlg.but.resettodefault = Reset to default
|
||||||
|
simedtdlg.but.savedefault = Save as default
|
||||||
simedtdlg.but.add = Add
|
simedtdlg.but.add = Add
|
||||||
simedtdlg.but.remove = Remove
|
simedtdlg.but.remove = Remove
|
||||||
simedtdlg.title.Editsim = Edit simulation
|
simedtdlg.title.Editsim = Edit simulation
|
||||||
@ -438,12 +439,6 @@ SimuRunDlg.lbl.Altitude = Altitude:
|
|||||||
SimuRunDlg.lbl.Velocity = Velocity:
|
SimuRunDlg.lbl.Velocity = Velocity:
|
||||||
SimuRunDlg.msg.Unabletosim = Unable to simulate:
|
SimuRunDlg.msg.Unabletosim = Unable to simulate:
|
||||||
SimuRunDlg.msg.errorOccurred = An error occurred during the simulation:
|
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.
|
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.checkbox.ttip.Incflightevents = Include a comment line for every flight event.
|
||||||
SimExpPan.lbl.Commentchar = Comment character:
|
SimExpPan.lbl.Commentchar = Comment character:
|
||||||
SimExpPan.lbl.ttip.Commentchar = The character(s) that mark a comment line.
|
SimExpPan.lbl.ttip.Commentchar = The character(s) that mark a comment line.
|
||||||
SimExpPan.but.Exporttofile = Export to file...
|
|
||||||
SimExpPan.Fileexists.desc1 = File \"
|
SimExpPan.Fileexists.desc1 = File \"
|
||||||
SimExpPan.Fileexists.desc2 = \" exists. Overwrite?
|
SimExpPan.Fileexists.desc2 = \" exists. Overwrite?
|
||||||
SimExpPan.Fileexists.title = File exists
|
SimExpPan.Fileexists.title = File exists
|
||||||
@ -581,7 +575,6 @@ simplotpanel.lbl.Flightevents = Flight events:
|
|||||||
simplotpanel.but.All = All
|
simplotpanel.but.All = All
|
||||||
simplotpanel.but.None = None
|
simplotpanel.but.None = None
|
||||||
simplotpanel.but.NewYaxisplottype = New Y axis plot type
|
simplotpanel.but.NewYaxisplottype = New Y axis plot type
|
||||||
simplotpanel.but.Plotflight = Plot flight
|
|
||||||
simplotpanel.lbl.Axis = Axis:
|
simplotpanel.lbl.Axis = Axis:
|
||||||
simplotpanel.but.ttip.Removethisplot = Remove this plot
|
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.
|
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.SIMULATION_END = Simulation end
|
||||||
FlightEvent.Type.ALTITUDE = Altitude change
|
FlightEvent.Type.ALTITUDE = Altitude change
|
||||||
FlightEvent.Type.TUMBLE = Tumbling
|
FlightEvent.Type.TUMBLE = Tumbling
|
||||||
|
FlightEvent.Type.EXCEPTION = Exception
|
||||||
|
|
||||||
! ThrustCurveMotorColumns
|
! ThrustCurveMotorColumns
|
||||||
TCurveMotorCol.MANUFACTURER = Manufacturer
|
TCurveMotorCol.MANUFACTURER = Manufacturer
|
||||||
|
@ -8,7 +8,7 @@ import net.sf.openrocket.unit.UnitGroup;
|
|||||||
public abstract class Warning {
|
public abstract class Warning {
|
||||||
|
|
||||||
private static final Translator trans = Application.getTranslator();
|
private static final Translator trans = Application.getTranslator();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a Warning with the specific text.
|
* Return a Warning with the specific text.
|
||||||
*/
|
*/
|
||||||
@ -36,8 +36,8 @@ public abstract class Warning {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
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.
|
* A <code>hashCode</code> method compatible with the <code>equals</code> method.
|
||||||
@ -79,21 +79,21 @@ public abstract class Warning {
|
|||||||
return (trans.get("Warning.LargeAOA.str2") +
|
return (trans.get("Warning.LargeAOA.str2") +
|
||||||
UnitGroup.UNITS_ANGLE.getDefaultUnit().toString(aoa) + ").");
|
UnitGroup.UNITS_ANGLE.getDefaultUnit().toString(aoa) + ").");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean replaceBy(Warning other) {
|
public boolean replaceBy(Warning other) {
|
||||||
if (!(other instanceof LargeAOA))
|
if (!(other instanceof LargeAOA))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
LargeAOA o = (LargeAOA)other;
|
LargeAOA o = (LargeAOA) other;
|
||||||
if (Double.isNaN(this.aoa)) // If this has value NaN then replace
|
if (Double.isNaN(this.aoa)) // If this has value NaN then replace
|
||||||
return true;
|
return true;
|
||||||
return (o.aoa > this.aoa);
|
return (o.aoa > this.aoa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MissingMotor extends Warning {
|
public static class MissingMotor extends Warning {
|
||||||
|
|
||||||
private Motor.Type type = null;
|
private Motor.Type type = null;
|
||||||
private String manufacturer = null;
|
private String manufacturer = null;
|
||||||
private String designation = null;
|
private String designation = null;
|
||||||
@ -101,7 +101,7 @@ public abstract class Warning {
|
|||||||
private double diameter = Double.NaN;
|
private double diameter = Double.NaN;
|
||||||
private double length = Double.NaN;
|
private double length = Double.NaN;
|
||||||
private double delay = Double.NaN;
|
private double delay = Double.NaN;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
String str = "No motor with designation '" + designation + "'";
|
String str = "No motor with designation '" + designation + "'";
|
||||||
@ -110,82 +110,82 @@ public abstract class Warning {
|
|||||||
str += " found.";
|
str += " found.";
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Motor.Type getType() {
|
public Motor.Type getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setType(Motor.Type type) {
|
public void setType(Motor.Type type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getManufacturer() {
|
public String getManufacturer() {
|
||||||
return manufacturer;
|
return manufacturer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setManufacturer(String manufacturer) {
|
public void setManufacturer(String manufacturer) {
|
||||||
this.manufacturer = manufacturer;
|
this.manufacturer = manufacturer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getDesignation() {
|
public String getDesignation() {
|
||||||
return designation;
|
return designation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setDesignation(String designation) {
|
public void setDesignation(String designation) {
|
||||||
this.designation = designation;
|
this.designation = designation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getDigest() {
|
public String getDigest() {
|
||||||
return digest;
|
return digest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setDigest(String digest) {
|
public void setDigest(String digest) {
|
||||||
this.digest = digest;
|
this.digest = digest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public double getDiameter() {
|
public double getDiameter() {
|
||||||
return diameter;
|
return diameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setDiameter(double diameter) {
|
public void setDiameter(double diameter) {
|
||||||
this.diameter = diameter;
|
this.diameter = diameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public double getLength() {
|
public double getLength() {
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setLength(double length) {
|
public void setLength(double length) {
|
||||||
this.length = length;
|
this.length = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public double getDelay() {
|
public double getDelay() {
|
||||||
return delay;
|
return delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setDelay(double delay) {
|
public void setDelay(double delay) {
|
||||||
this.delay = delay;
|
this.delay = delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean replaceBy(Warning other) {
|
public boolean replaceBy(Warning other) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
@ -206,7 +206,7 @@ public abstract class Warning {
|
|||||||
result = prime * result + ((type == null) ? 0 : type.hashCode());
|
result = prime * result + ((type == null) ? 0 : type.hashCode());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (this == obj)
|
if (this == obj)
|
||||||
@ -272,7 +272,7 @@ public abstract class Warning {
|
|||||||
if (!(other instanceof Other))
|
if (!(other instanceof Other))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Other o = (Other)other;
|
Other o = (Other) other;
|
||||||
return (o.description.equals(this.description));
|
return (o.description.equals(this.description));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,7 +280,7 @@ public abstract class Warning {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return description.hashCode();
|
return description.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean replaceBy(Warning other) {
|
public boolean replaceBy(Warning other) {
|
||||||
return false;
|
return false;
|
||||||
@ -289,40 +289,40 @@ public abstract class Warning {
|
|||||||
|
|
||||||
|
|
||||||
/** A <code>Warning</code> that the body diameter is discontinuous. */
|
/** 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 =
|
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. */
|
/** 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 =
|
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. */
|
/** 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 =
|
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 */
|
/** 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 =
|
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 =
|
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.
|
//// Invalid parameter encountered, ignoring.
|
||||||
public static final Warning FILE_INVALID_PARAMETER =
|
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 =
|
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 =
|
public static final Warning SUPERSONIC =
|
||||||
new Other(trans.get("Warning.SUPERSONIC"));
|
new Other(trans.get("Warning.SUPERSONIC"));
|
||||||
|
|
||||||
public static final Warning RECOVERY_LAUNCH_ROD =
|
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.Configuration;
|
||||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||||
import net.sf.openrocket.simulation.BasicEventSimulationEngine;
|
import net.sf.openrocket.simulation.BasicEventSimulationEngine;
|
||||||
|
import net.sf.openrocket.simulation.DefaultSimulationOptionFactory;
|
||||||
import net.sf.openrocket.simulation.FlightData;
|
import net.sf.openrocket.simulation.FlightData;
|
||||||
import net.sf.openrocket.simulation.RK4SimulationStepper;
|
import net.sf.openrocket.simulation.RK4SimulationStepper;
|
||||||
import net.sf.openrocket.simulation.SimulationConditions;
|
import net.sf.openrocket.simulation.SimulationConditions;
|
||||||
@ -105,8 +106,11 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
this.status = Status.NOT_SIMULATED;
|
this.status = Status.NOT_SIMULATED;
|
||||||
|
|
||||||
options = new SimulationOptions(rocket);
|
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());
|
options.addChangeListener(new ConditionListener());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,7 +378,21 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
return simulatedData;
|
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.
|
* 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.miginfocom.swing.MigLayout;
|
||||||
import net.sf.openrocket.document.OpenRocketDocument;
|
import net.sf.openrocket.document.OpenRocketDocument;
|
||||||
|
import net.sf.openrocket.document.Simulation;
|
||||||
import net.sf.openrocket.gui.adaptors.FlightConfigurationModel;
|
import net.sf.openrocket.gui.adaptors.FlightConfigurationModel;
|
||||||
import net.sf.openrocket.gui.main.BasicFrame;
|
import net.sf.openrocket.gui.main.BasicFrame;
|
||||||
import net.sf.openrocket.gui.util.GUIUtil;
|
import net.sf.openrocket.gui.util.GUIUtil;
|
||||||
@ -170,6 +171,10 @@ public class FlightConfigurationDialog extends JDialog {
|
|||||||
private void addConfiguration() {
|
private void addConfiguration() {
|
||||||
String newId = rocket.newFlightConfigurationID();
|
String newId = rocket.newFlightConfigurationID();
|
||||||
rocket.getDefaultConfiguration().setFlightConfigurationID(newId);
|
rocket.getDefaultConfiguration().setFlightConfigurationID(newId);
|
||||||
|
|
||||||
|
// Create a new simulation for this configuration.
|
||||||
|
createSimulationForNewConfiguration();
|
||||||
|
|
||||||
configurationChanged();
|
configurationChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,9 +193,22 @@ public class FlightConfigurationDialog extends JDialog {
|
|||||||
rocket.setFlightConfigurationName(currentId, oldName);
|
rocket.setFlightConfigurationName(currentId, oldName);
|
||||||
rocket.getDefaultConfiguration().setFlightConfigurationID(newConfigId);
|
rocket.getDefaultConfiguration().setFlightConfigurationID(newConfigId);
|
||||||
|
|
||||||
|
// Create a new simulation for this configuration.
|
||||||
|
createSimulationForNewConfiguration();
|
||||||
|
|
||||||
configurationChanged();
|
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() {
|
private void renameConfiguration() {
|
||||||
new RenameConfigDialog(this, rocket).setVisible(true);
|
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.Column;
|
||||||
import net.sf.openrocket.gui.adaptors.ColumnTableModel;
|
import net.sf.openrocket.gui.adaptors.ColumnTableModel;
|
||||||
import net.sf.openrocket.gui.components.StyledLabel;
|
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.gui.util.Icons;
|
||||||
import net.sf.openrocket.l10n.Translator;
|
import net.sf.openrocket.l10n.Translator;
|
||||||
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
|
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
|
||||||
@ -68,13 +71,14 @@ public class SimulationPanel extends JPanel {
|
|||||||
private final ColumnTableModel simulationTableModel;
|
private final ColumnTableModel simulationTableModel;
|
||||||
private final JTable simulationTable;
|
private final JTable simulationTable;
|
||||||
|
|
||||||
|
private final JButton editButton;
|
||||||
|
private final JButton runButton;
|
||||||
|
private final JButton deleteButton;
|
||||||
|
private final JButton plotButton;
|
||||||
|
|
||||||
public SimulationPanel(OpenRocketDocument doc) {
|
public SimulationPanel(OpenRocketDocument doc) {
|
||||||
super(new MigLayout("fill", "[grow][][][][][][grow]"));
|
super(new MigLayout("fill", "[grow][][][][][][grow]"));
|
||||||
|
|
||||||
JButton button;
|
|
||||||
|
|
||||||
|
|
||||||
this.document = doc;
|
this.document = doc;
|
||||||
|
|
||||||
|
|
||||||
@ -82,59 +86,60 @@ public class SimulationPanel extends JPanel {
|
|||||||
//////// The simulation action buttons
|
//////// The simulation action buttons
|
||||||
|
|
||||||
//// New simulation button
|
//// New simulation button
|
||||||
button = new JButton(trans.get("simpanel.but.newsimulation"));
|
{
|
||||||
//// Add a new simulation
|
JButton button = new JButton(trans.get("simpanel.but.newsimulation"));
|
||||||
button.setToolTipText(trans.get("simpanel.but.ttip.newsimulation"));
|
//// Add a new simulation
|
||||||
button.addActionListener(new ActionListener() {
|
button.setToolTipText(trans.get("simpanel.but.ttip.newsimulation"));
|
||||||
@Override
|
button.addActionListener(new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent e) {
|
@Override
|
||||||
Simulation sim = new Simulation(document.getRocket());
|
public void actionPerformed(ActionEvent e) {
|
||||||
sim.setName(document.getNextSimulationName());
|
Simulation sim = new Simulation(document.getRocket());
|
||||||
|
sim.setName(document.getNextSimulationName());
|
||||||
int n = document.getSimulationCount();
|
|
||||||
document.addSimulation(sim);
|
int n = document.getSimulationCount();
|
||||||
simulationTableModel.fireTableDataChanged();
|
document.addSimulation(sim);
|
||||||
simulationTable.clearSelection();
|
simulationTableModel.fireTableDataChanged();
|
||||||
simulationTable.addRowSelectionInterval(n, n);
|
simulationTable.clearSelection();
|
||||||
|
simulationTable.addRowSelectionInterval(n, n);
|
||||||
openDialog(sim, SimulationEditDialog.EDIT);
|
|
||||||
}
|
openDialog(false, sim);
|
||||||
});
|
}
|
||||||
this.add(button, "skip 1, gapright para");
|
});
|
||||||
|
this.add(button, "skip 1, gapright para");
|
||||||
|
}
|
||||||
|
|
||||||
//// Edit simulation button
|
//// Edit simulation button
|
||||||
button = new JButton(trans.get("simpanel.but.editsimulation"));
|
editButton = new JButton(trans.get("simpanel.but.editsimulation"));
|
||||||
//// Edit the selected simulation
|
//// Edit the selected simulation
|
||||||
button.setToolTipText(trans.get("simpanel.but.ttip.editsim"));
|
editButton.setToolTipText(trans.get("simpanel.but.ttip.editsim"));
|
||||||
button.addActionListener(new ActionListener() {
|
editButton.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() {
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
int[] selection = simulationTable.getSelectedRows();
|
int[] selection = simulationTable.getSelectedRows();
|
||||||
if (selection.length == 0) {
|
if (selection.length == 0)
|
||||||
JOptionPane.showMessageDialog(simulationTable, "No simulations selected.");
|
return; // TODO: LOW: "None selected" dialog
|
||||||
return;
|
|
||||||
|
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];
|
Simulation[] sims = new Simulation[selection.length];
|
||||||
for (int i = 0; i < selection.length; i++) {
|
for (int i = 0; i < selection.length; i++) {
|
||||||
selection[i] = simulationTable.convertRowIndexToModel(selection[i]);
|
selection[i] = simulationTable.convertRowIndexToModel(selection[i]);
|
||||||
@ -148,13 +153,13 @@ public class SimulationPanel extends JPanel {
|
|||||||
fireMaintainSelection();
|
fireMaintainSelection();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.add(button, "gapright para");
|
this.add(runButton, "gapright para");
|
||||||
|
|
||||||
//// Delete simulations button
|
//// Delete simulations button
|
||||||
button = new JButton(trans.get("simpanel.but.deletesimulations"));
|
deleteButton = new JButton(trans.get("simpanel.but.deletesimulations"));
|
||||||
//// Delete the selected simulations
|
//// Delete the selected simulations
|
||||||
button.setToolTipText(trans.get("simpanel.but.ttip.deletesim"));
|
deleteButton.setToolTipText(trans.get("simpanel.but.ttip.deletesim"));
|
||||||
button.addActionListener(new ActionListener() {
|
deleteButton.addActionListener(new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
int[] selection = simulationTable.getSelectedRows();
|
int[] selection = simulationTable.getSelectedRows();
|
||||||
@ -203,12 +208,12 @@ public class SimulationPanel extends JPanel {
|
|||||||
simulationTableModel.fireTableDataChanged();
|
simulationTableModel.fireTableDataChanged();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.add(button, "gapright para");
|
this.add(deleteButton, "gapright para");
|
||||||
|
|
||||||
//// Plot / export button
|
//// 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 = new JButton("Plot flight");
|
||||||
button.addActionListener(new ActionListener() {
|
plotButton.addActionListener(new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
int selected = simulationTable.getSelectedRow();
|
int selected = simulationTable.getSelectedRow();
|
||||||
@ -219,10 +224,21 @@ public class SimulationPanel extends JPanel {
|
|||||||
simulationTable.clearSelection();
|
simulationTable.clearSelection();
|
||||||
simulationTable.addRowSelectionInterval(selected, selected);
|
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();
|
int selected = simulationTable.getSelectedRow();
|
||||||
if (selected < 0)
|
if (selected < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
selected = simulationTable.convertRowIndexToModel(selected);
|
selected = simulationTable.convertRowIndexToModel(selected);
|
||||||
simulationTable.clearSelection();
|
|
||||||
simulationTable.addRowSelectionInterval(selected, selected);
|
|
||||||
|
|
||||||
openDialog(document.getSimulations().get(selected),
|
int column = simulationTable.columnAtPoint(e.getPoint());
|
||||||
SimulationEditDialog.DEFAULT);
|
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);
|
JScrollPane scrollpane = new JScrollPane(simulationTable);
|
||||||
this.add(scrollpane, "spanx, grow, wrap rel");
|
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();
|
return simulationTable.getSelectionModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openDialog(final Simulation sim, int position) {
|
private void openDialog(boolean plotMode, final Simulation... sims) {
|
||||||
new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, sim, position)
|
SimulationEditDialog d = new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, sims);
|
||||||
.setVisible(true);
|
if (plotMode) {
|
||||||
|
d.setPlotMode();
|
||||||
|
}
|
||||||
|
d.setVisible(true);
|
||||||
fireMaintainSelection();
|
fireMaintainSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void openDialog(final Simulation sim) {
|
||||||
|
boolean plotMode = false;
|
||||||
|
if (sim.hasSimulationData()) {
|
||||||
|
plotMode = true;
|
||||||
|
}
|
||||||
|
openDialog(plotMode, sim);
|
||||||
|
}
|
||||||
|
|
||||||
private void fireMaintainSelection() {
|
private void fireMaintainSelection() {
|
||||||
int[] selection = simulationTable.getSelectedRows();
|
int[] selection = simulationTable.getSelectedRows();
|
||||||
simulationTableModel.fireTableDataChanged();
|
simulationTableModel.fireTableDataChanged();
|
||||||
|
@ -37,6 +37,7 @@ public class PlotConfiguration implements Cloneable {
|
|||||||
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
||||||
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
||||||
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
||||||
|
config.setEvent(FlightEvent.Type.EXCEPTION, true);
|
||||||
configs.add(config);
|
configs.add(config);
|
||||||
|
|
||||||
//// Total motion vs. time
|
//// Total motion vs. time
|
||||||
@ -51,6 +52,7 @@ public class PlotConfiguration implements Cloneable {
|
|||||||
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
||||||
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
||||||
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
||||||
|
config.setEvent(FlightEvent.Type.EXCEPTION, true);
|
||||||
configs.add(config);
|
configs.add(config);
|
||||||
|
|
||||||
//// Flight side profile
|
//// Flight side profile
|
||||||
@ -63,6 +65,7 @@ public class PlotConfiguration implements Cloneable {
|
|||||||
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
||||||
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
||||||
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
||||||
|
config.setEvent(FlightEvent.Type.EXCEPTION, true);
|
||||||
configs.add(config);
|
configs.add(config);
|
||||||
|
|
||||||
//// Stability vs. time
|
//// Stability vs. time
|
||||||
@ -77,6 +80,7 @@ public class PlotConfiguration implements Cloneable {
|
|||||||
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
||||||
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
||||||
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
||||||
|
config.setEvent(FlightEvent.Type.EXCEPTION, true);
|
||||||
configs.add(config);
|
configs.add(config);
|
||||||
|
|
||||||
//// Drag coefficients vs. Mach number
|
//// 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_FRICTION_DRAG_COEFF, 0);
|
||||||
config.addPlotDataType(FlightDataType.TYPE_BASE_DRAG_COEFF, 0);
|
config.addPlotDataType(FlightDataType.TYPE_BASE_DRAG_COEFF, 0);
|
||||||
config.addPlotDataType(FlightDataType.TYPE_PRESSURE_DRAG_COEFF, 0);
|
config.addPlotDataType(FlightDataType.TYPE_PRESSURE_DRAG_COEFF, 0);
|
||||||
|
config.setEvent(FlightEvent.Type.EXCEPTION, true);
|
||||||
configs.add(config);
|
configs.add(config);
|
||||||
|
|
||||||
//// Roll characteristics
|
//// Roll characteristics
|
||||||
@ -102,6 +107,7 @@ public class PlotConfiguration implements Cloneable {
|
|||||||
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
||||||
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
||||||
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
||||||
|
config.setEvent(FlightEvent.Type.EXCEPTION, true);
|
||||||
configs.add(config);
|
configs.add(config);
|
||||||
|
|
||||||
//// Angle of attack and orientation vs. time
|
//// 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.STAGE_SEPARATION, true);
|
||||||
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
||||||
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
||||||
|
config.setEvent(FlightEvent.Type.EXCEPTION, true);
|
||||||
configs.add(config);
|
configs.add(config);
|
||||||
|
|
||||||
//// Simulation time step and computation time
|
//// 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.STAGE_SEPARATION, true);
|
||||||
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
||||||
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
||||||
|
config.setEvent(FlightEvent.Type.EXCEPTION, true);
|
||||||
configs.add(config);
|
configs.add(config);
|
||||||
|
|
||||||
DEFAULT_CONFIGURATIONS = configs.toArray(new PlotConfiguration[0]);
|
DEFAULT_CONFIGURATIONS = configs.toArray(new PlotConfiguration[0]);
|
||||||
|
@ -20,6 +20,7 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import net.sf.openrocket.document.Simulation;
|
import net.sf.openrocket.document.Simulation;
|
||||||
|
import net.sf.openrocket.gui.simulation.SimulationPlotPanel;
|
||||||
import net.sf.openrocket.simulation.FlightDataBranch;
|
import net.sf.openrocket.simulation.FlightDataBranch;
|
||||||
import net.sf.openrocket.simulation.FlightDataType;
|
import net.sf.openrocket.simulation.FlightDataType;
|
||||||
import net.sf.openrocket.simulation.FlightEvent;
|
import net.sf.openrocket.simulation.FlightEvent;
|
||||||
@ -152,7 +153,6 @@ public class SimulationPlot {
|
|||||||
Unit unit = filled.getUnit(i);
|
Unit unit = filled.getUnit(i);
|
||||||
int axis = filled.getAxis(i);
|
int axis = filled.getAxis(i);
|
||||||
String name = getLabel(type, unit);
|
String name = getLabel(type, unit);
|
||||||
this.legendItems.lineLabels.add(name);
|
|
||||||
|
|
||||||
List<String> seriesNames = Util.generateSeriesLabels(simulation);
|
List<String> seriesNames = Util.generateSeriesLabels(simulation);
|
||||||
|
|
||||||
@ -166,7 +166,7 @@ public class SimulationPlot {
|
|||||||
List<Double> plotx = thisBranch.get(domainType);
|
List<Double> plotx = thisBranch.get(domainType);
|
||||||
List<Double> ploty = thisBranch.get(type);
|
List<Double> ploty = thisBranch.get(type);
|
||||||
XYSeries series = new XYSeries(seriesNames.get(branchIndex) + ": " + name, false, true);
|
XYSeries series = new XYSeries(seriesNames.get(branchIndex) + ": " + name, false, true);
|
||||||
series.setDescription(thisBranch.getBranchName() + ": " + name);
|
series.setDescription(name);
|
||||||
int pointCount = plotx.size();
|
int pointCount = plotx.size();
|
||||||
for (int j = 0; j < pointCount; j++) {
|
for (int j = 0; j < pointCount; j++) {
|
||||||
series.add(domainUnit.toUnit(plotx.get(j)), unit.toUnit(ploty.get(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.
|
// Now we pull the colors for the legend.
|
||||||
for (int j = 0; j < data[i].getSeriesCount(); j += branchCount) {
|
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);
|
Paint linePaint = r.lookupSeriesPaint(j);
|
||||||
this.legendItems.linePaints.add(linePaint);
|
this.legendItems.linePaints.add(linePaint);
|
||||||
Shape itemShape = r.lookupSeriesShape(j);
|
Shape itemShape = r.lookupSeriesShape(j);
|
||||||
|
@ -7,8 +7,6 @@ import java.awt.event.InputEvent;
|
|||||||
import java.awt.event.ItemEvent;
|
import java.awt.event.ItemEvent;
|
||||||
import java.awt.event.ItemListener;
|
import java.awt.event.ItemListener;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JCheckBox;
|
import javax.swing.JCheckBox;
|
||||||
@ -113,8 +111,8 @@ public class SimulationPlotDialog extends JDialog {
|
|||||||
//// Add series selection box
|
//// Add series selection box
|
||||||
ArrayList<String> stages = new ArrayList<String>();
|
ArrayList<String> stages = new ArrayList<String>();
|
||||||
stages.add("All");
|
stages.add("All");
|
||||||
stages.addAll( Util.generateSeriesLabels(simulation));
|
stages.addAll(Util.generateSeriesLabels(simulation));
|
||||||
|
|
||||||
final JComboBox stageSelection = new JComboBox(stages.toArray(new String[0]));
|
final JComboBox stageSelection = new JComboBox(stages.toArray(new String[0]));
|
||||||
stageSelection.addItemListener(new ItemListener() {
|
stageSelection.addItemListener(new ItemListener() {
|
||||||
|
|
||||||
@ -159,8 +157,8 @@ public class SimulationPlotDialog extends JDialog {
|
|||||||
* @param simulation the simulation to plot.
|
* @param simulation the simulation to plot.
|
||||||
* @param config the configuration of the plot.
|
* @param config the configuration of the plot.
|
||||||
*/
|
*/
|
||||||
public static void showPlot(Window parent, Simulation simulation, PlotConfiguration config) {
|
public static SimulationPlotDialog getPlot(Window parent, Simulation simulation, PlotConfiguration config) {
|
||||||
new SimulationPlotDialog(parent, simulation, config).setVisible(true);
|
return new SimulationPlotDialog(parent, simulation, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
package net.sf.openrocket.gui.print;
|
package net.sf.openrocket.gui.print;
|
||||||
|
|
||||||
import net.sf.openrocket.document.Simulation;
|
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;
|
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.CPCaret;
|
||||||
import net.sf.openrocket.gui.figureelements.Caret;
|
import net.sf.openrocket.gui.figureelements.Caret;
|
||||||
import net.sf.openrocket.gui.figureelements.RocketInfo;
|
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.main.componenttree.ComponentTreeModel;
|
||||||
|
import net.sf.openrocket.gui.simulation.SimulationWorker;
|
||||||
import net.sf.openrocket.gui.util.SwingPreferences;
|
import net.sf.openrocket.gui.util.SwingPreferences;
|
||||||
import net.sf.openrocket.l10n.Translator;
|
import net.sf.openrocket.l10n.Translator;
|
||||||
import net.sf.openrocket.masscalc.BasicMassCalculator;
|
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.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.ItemEvent;
|
import java.awt.event.ItemEvent;
|
||||||
@ -10,12 +11,12 @@ import java.util.EnumSet;
|
|||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
|
import javax.swing.JDialog;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
import javax.swing.table.AbstractTableModel;
|
import javax.swing.table.AbstractTableModel;
|
||||||
import javax.swing.table.TableColumn;
|
import javax.swing.table.TableColumn;
|
||||||
import javax.swing.table.TableColumnModel;
|
import javax.swing.table.TableColumnModel;
|
||||||
@ -24,6 +25,8 @@ import net.miginfocom.swing.MigLayout;
|
|||||||
import net.sf.openrocket.document.Simulation;
|
import net.sf.openrocket.document.Simulation;
|
||||||
import net.sf.openrocket.gui.components.DescriptionArea;
|
import net.sf.openrocket.gui.components.DescriptionArea;
|
||||||
import net.sf.openrocket.gui.components.UnitSelector;
|
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.GUIUtil;
|
||||||
import net.sf.openrocket.gui.util.Icons;
|
import net.sf.openrocket.gui.util.Icons;
|
||||||
import net.sf.openrocket.l10n.Translator;
|
import net.sf.openrocket.l10n.Translator;
|
||||||
@ -71,18 +74,18 @@ public class SimulationPlotPanel extends JPanel {
|
|||||||
PRESET_ARRAY[PRESET_ARRAY.length - 1] = CUSTOM_CONFIGURATION;
|
PRESET_ARRAY[PRESET_ARRAY.length - 1] = CUSTOM_CONFIGURATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** The current default configuration, set each time a plot is made. */
|
/** The current default configuration, set each time a plot is made. */
|
||||||
private static PlotConfiguration defaultConfiguration =
|
private static PlotConfiguration defaultConfiguration =
|
||||||
PlotConfiguration.DEFAULT_CONFIGURATIONS[0].resetUnits();
|
PlotConfiguration.DEFAULT_CONFIGURATIONS[0].resetUnits();
|
||||||
|
|
||||||
|
|
||||||
private final Simulation simulation;
|
private final Simulation simulation;
|
||||||
private final FlightDataType[] types;
|
private final FlightDataType[] types;
|
||||||
private PlotConfiguration configuration;
|
private PlotConfiguration configuration;
|
||||||
|
|
||||||
|
|
||||||
private JComboBox configurationSelector;
|
private JComboBox configurationSelector;
|
||||||
|
|
||||||
private JComboBox domainTypeSelector;
|
private JComboBox domainTypeSelector;
|
||||||
@ -91,7 +94,7 @@ public class SimulationPlotPanel extends JPanel {
|
|||||||
private JPanel typeSelectorPanel;
|
private JPanel typeSelectorPanel;
|
||||||
private FlightEventTableModel eventTableModel;
|
private FlightEventTableModel eventTableModel;
|
||||||
|
|
||||||
|
|
||||||
private int modifying = 0;
|
private int modifying = 0;
|
||||||
|
|
||||||
|
|
||||||
@ -107,7 +110,7 @@ public class SimulationPlotPanel extends JPanel {
|
|||||||
types = branch.getTypes();
|
types = branch.getTypes();
|
||||||
|
|
||||||
setConfiguration(defaultConfiguration);
|
setConfiguration(defaultConfiguration);
|
||||||
|
|
||||||
//// Configuration selector
|
//// Configuration selector
|
||||||
|
|
||||||
// Setup the combo box
|
// Setup the combo box
|
||||||
@ -126,7 +129,7 @@ public class SimulationPlotPanel extends JPanel {
|
|||||||
// the UI when the selected item changes.
|
// the UI when the selected item changes.
|
||||||
// TODO - this should probably be implemented as an ActionListener instead
|
// TODO - this should probably be implemented as an ActionListener instead
|
||||||
// of ItemStateListener.
|
// of ItemStateListener.
|
||||||
if ( e.getStateChange() == ItemEvent.DESELECTED) {
|
if (e.getStateChange() == ItemEvent.DESELECTED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (modifying > 0)
|
if (modifying > 0)
|
||||||
@ -144,8 +147,8 @@ public class SimulationPlotPanel extends JPanel {
|
|||||||
this.add(new JLabel(trans.get("simplotpanel.lbl.Presetplotconf")), "spanx, split");
|
this.add(new JLabel(trans.get("simplotpanel.lbl.Presetplotconf")), "spanx, split");
|
||||||
this.add(configurationSelector, "growx, wrap 20lp");
|
this.add(configurationSelector, "growx, wrap 20lp");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//// X axis
|
//// X axis
|
||||||
|
|
||||||
//// X axis type:
|
//// X axis type:
|
||||||
@ -185,8 +188,8 @@ public class SimulationPlotPanel extends JPanel {
|
|||||||
desc.setViewportBorder(BorderFactory.createEmptyBorder());
|
desc.setViewportBorder(BorderFactory.createEmptyBorder());
|
||||||
this.add(desc, "width 1px, growx 1, wrap unrel");
|
this.add(desc, "width 1px, growx 1, wrap unrel");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//// Y axis selector panel
|
//// Y axis selector panel
|
||||||
//// Y axis types:
|
//// Y axis types:
|
||||||
this.add(new JLabel(trans.get("simplotpanel.lbl.Yaxistypes")));
|
this.add(new JLabel(trans.get("simplotpanel.lbl.Yaxistypes")));
|
||||||
@ -197,7 +200,7 @@ public class SimulationPlotPanel extends JPanel {
|
|||||||
JScrollPane scroll = new JScrollPane(typeSelectorPanel);
|
JScrollPane scroll = new JScrollPane(typeSelectorPanel);
|
||||||
this.add(scroll, "spany 2, height 10px, wmin 400lp, grow 100, gapright para");
|
this.add(scroll, "spany 2, height 10px, wmin 400lp, grow 100, gapright para");
|
||||||
|
|
||||||
|
|
||||||
//// Flight events
|
//// Flight events
|
||||||
eventTableModel = new FlightEventTableModel();
|
eventTableModel = new FlightEventTableModel();
|
||||||
JTable table = new JTable(eventTableModel);
|
JTable table = new JTable(eventTableModel);
|
||||||
@ -213,9 +216,9 @@ public class SimulationPlotPanel extends JPanel {
|
|||||||
col0.setPreferredWidth(w);
|
col0.setPreferredWidth(w);
|
||||||
col0.setMaxWidth(w);
|
col0.setMaxWidth(w);
|
||||||
table.addMouseListener(new GUIUtil.BooleanTableClickListener(table));
|
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
|
//// All + None buttons
|
||||||
JButton button = new JButton(trans.get("simplotpanel.but.All"));
|
JButton button = new JButton(trans.get("simplotpanel.but.All"));
|
||||||
button.addActionListener(new ActionListener() {
|
button.addActionListener(new ActionListener() {
|
||||||
@ -240,8 +243,8 @@ public class SimulationPlotPanel extends JPanel {
|
|||||||
});
|
});
|
||||||
this.add(button, "gapleft para, gapright para, growx, sizegroup buttons, wrap para");
|
this.add(button, "gapleft para, gapright para, growx, sizegroup buttons, wrap para");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//// New Y axis plot type
|
//// New Y axis plot type
|
||||||
button = new JButton(trans.get("simplotpanel.but.NewYaxisplottype"));
|
button = new JButton(trans.get("simplotpanel.but.NewYaxisplottype"));
|
||||||
button.addActionListener(new ActionListener() {
|
button.addActionListener(new ActionListener() {
|
||||||
@ -260,40 +263,41 @@ public class SimulationPlotPanel extends JPanel {
|
|||||||
// Select new type smartly
|
// Select new type smartly
|
||||||
FlightDataType type = null;
|
FlightDataType type = null;
|
||||||
for (FlightDataType t :
|
for (FlightDataType t :
|
||||||
simulation.getSimulatedData().getBranch(0).getTypes()) {
|
simulation.getSimulatedData().getBranch(0).getTypes()) {
|
||||||
|
|
||||||
boolean used = false;
|
boolean used = false;
|
||||||
if (configuration.getDomainAxisType().equals(t)) {
|
if (configuration.getDomainAxisType().equals(t)) {
|
||||||
used = true;
|
used = true;
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < configuration.getTypeCount(); i++) {
|
for (int i = 0; i < configuration.getTypeCount(); i++) {
|
||||||
if (configuration.getType(i).equals(t)) {
|
if (configuration.getType(i).equals(t)) {
|
||||||
used = true;
|
used = true;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!used) {
|
|
||||||
type = t;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (type == null) {
|
|
||||||
type = simulation.getSimulatedData().getBranch(0).getTypes()[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add new type
|
if (!used) {
|
||||||
configuration.addPlotDataType(type);
|
type = t;
|
||||||
setToCustom();
|
break;
|
||||||
updatePlots();
|
}
|
||||||
}
|
}
|
||||||
|
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(button, "spanx, split");
|
||||||
|
|
||||||
|
|
||||||
this.add(new JPanel(), "growx");
|
this.add(new JPanel(), "growx");
|
||||||
|
|
||||||
|
/*
|
||||||
//// Plot flight
|
//// Plot flight
|
||||||
button = new JButton(trans.get("simplotpanel.but.Plotflight"));
|
button = new JButton(trans.get("simplotpanel.but.Plotflight"));
|
||||||
button.addActionListener(new ActionListener() {
|
button.addActionListener(new ActionListener() {
|
||||||
@ -312,10 +316,21 @@ public class SimulationPlotPanel extends JPanel {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.add(button, "right");
|
this.add(button, "right");
|
||||||
|
*/
|
||||||
updatePlots();
|
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) {
|
private void setConfiguration(PlotConfiguration conf) {
|
||||||
|
|
||||||
@ -366,14 +381,14 @@ public class SimulationPlotPanel extends JPanel {
|
|||||||
|
|
||||||
// In order to consistantly update the ui, we need to validate before repaint.
|
// In order to consistantly update the ui, we need to validate before repaint.
|
||||||
typeSelectorPanel.validate();
|
typeSelectorPanel.validate();
|
||||||
typeSelectorPanel.repaint();
|
typeSelectorPanel.repaint();
|
||||||
|
|
||||||
eventTableModel.fireTableDataChanged();
|
eventTableModel.fireTableDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A JPanel which configures a single plot of a PlotConfiguration.
|
* A JPanel which configures a single plot of a PlotConfiguration.
|
||||||
*/
|
*/
|
||||||
@ -443,7 +458,7 @@ public class SimulationPlotPanel extends JPanel {
|
|||||||
});
|
});
|
||||||
this.add(axisSelector);
|
this.add(axisSelector);
|
||||||
|
|
||||||
|
|
||||||
JButton button = new JButton(Icons.DELETE);
|
JButton button = new JButton(Icons.DELETE);
|
||||||
//// Remove this plot
|
//// Remove this plot
|
||||||
button.setToolTipText(trans.get("simplotpanel.but.ttip.Removethisplot"));
|
button.setToolTipText(trans.get("simplotpanel.but.ttip.Removethisplot"));
|
||||||
@ -461,7 +476,7 @@ public class SimulationPlotPanel extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private class FlightEventTableModel extends AbstractTableModel {
|
private class FlightEventTableModel extends AbstractTableModel {
|
||||||
private final FlightEvent.Type[] eventTypes;
|
private final FlightEvent.Type[] eventTypes;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package net.sf.openrocket.gui.main;
|
package net.sf.openrocket.gui.simulation;
|
||||||
|
|
||||||
|
|
||||||
import java.awt.Dialog;
|
import java.awt.Dialog;
|
||||||
@ -23,9 +23,6 @@ import javax.swing.JOptionPane;
|
|||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JProgressBar;
|
import javax.swing.JProgressBar;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import net.sf.openrocket.document.OpenRocketDocument;
|
import net.sf.openrocket.document.OpenRocketDocument;
|
||||||
import net.sf.openrocket.document.Simulation;
|
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.unit.UnitGroup;
|
||||||
import net.sf.openrocket.util.MathUtil;
|
import net.sf.openrocket.util.MathUtil;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|
||||||
public class SimulationRunDialog extends JDialog {
|
public class SimulationRunDialog extends JDialog {
|
||||||
private static final Logger log = LoggerFactory.getLogger(SimulationRunDialog.class);
|
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;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ public abstract class SimulationWorker extends SwingWorker<FlightData, Simulatio
|
|||||||
protected abstract void simulationInterrupted(Throwable t);
|
protected abstract void simulationInterrupted(Throwable t);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks this simulation as done and calls the progress update.
|
* Marks this simulation as done and calls the progress update.
|
||||||
*/
|
*/
|
||||||
@ -99,7 +99,7 @@ public abstract class SimulationWorker extends SwingWorker<FlightData, Simulatio
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simulation listener that throws a {@link SimulationCancelledException} if
|
* A simulation listener that throws a {@link SimulationCancelledException} if
|
||||||
* this SwingWorker has been cancelled. The conditions is checked every time a step
|
* this SwingWorker has been cancelled. The conditions is checked every time a step
|
@ -42,9 +42,9 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
private SimulationStepper landingStepper = new BasicLandingStepper();
|
private SimulationStepper landingStepper = new BasicLandingStepper();
|
||||||
private SimulationStepper tumbleStepper = new BasicTumbleStepper();
|
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.
|
// 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;
|
private SimulationStepper currentStepper;
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
return flightData;
|
return flightData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private FlightDataBranch simulateLoop() throws SimulationException {
|
private FlightDataBranch simulateLoop() {
|
||||||
|
|
||||||
// Initialize the simulation
|
// Initialize the simulation
|
||||||
currentStepper = flightStepper;
|
currentStepper = flightStepper;
|
||||||
@ -222,7 +222,9 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
|
|
||||||
} catch (SimulationException e) {
|
} catch (SimulationException e) {
|
||||||
SimulationListenerHelper.fireEndSimulation(status, 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();
|
return status.getFlightData();
|
||||||
|
@ -13,7 +13,7 @@ public class BasicLandingStepper extends AbstractSimulationStepper {
|
|||||||
private static final double RECOVERY_TIME_STEP = 0.5;
|
private static final double RECOVERY_TIME_STEP = 0.5;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SimulationStatus initialize(SimulationStatus status) throws SimulationException {
|
public SimulationStatus initialize(SimulationStatus status) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ public class BasicTumbleStepper extends AbstractSimulationStepper {
|
|||||||
private static final double RECOVERY_TIME_STEP = 0.5;
|
private static final double RECOVERY_TIME_STEP = 0.5;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SimulationStatus initialize(SimulationStatus status) throws SimulationException {
|
public SimulationStatus initialize(SimulationStatus status) {
|
||||||
return new BasicTumbleStatus(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.
|
* 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;
|
private final String name;
|
||||||
|
|
||||||
|
@ -452,6 +452,71 @@ public class SimulationOptions implements ChangeSource, Cloneable {
|
|||||||
fireChangeEvent();
|
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.
|
* @param status the current simulation status.
|
||||||
* @return a SimulationStatus suitable for simulating with this simulation stepper.
|
* @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.
|
* Perform one simulation time step.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user