Implement feature to compute the optimum delay for a simulation.
This commit is contained in:
parent
4565cdcd86
commit
a34d41d6af
@ -430,6 +430,8 @@ simpanel.col.Motors = Motors
|
|||||||
simpanel.col.Configuration = Configuration
|
simpanel.col.Configuration = Configuration
|
||||||
simpanel.col.Velocityoffrod = Velocity off rod
|
simpanel.col.Velocityoffrod = Velocity off rod
|
||||||
simpanel.col.Velocityatdeploy = Velocity at deployment
|
simpanel.col.Velocityatdeploy = Velocity at deployment
|
||||||
|
simpanel.col.OptimumCoastTime = Optimum delay
|
||||||
|
simpanel.col.OptimumCoastTime.ttip = The time between last motor burnout and maximum possible altitude.
|
||||||
simpanel.col.Apogee = Apogee
|
simpanel.col.Apogee = Apogee
|
||||||
simpanel.col.Maxvelocity = Max. velocity
|
simpanel.col.Maxvelocity = Max. velocity
|
||||||
simpanel.col.Maxacceleration = Max. acceleration
|
simpanel.col.Maxacceleration = Max. acceleration
|
||||||
|
@ -536,6 +536,7 @@ public class OpenRocketSaver extends RocketSaver {
|
|||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("<databranch name=\"");
|
sb.append("<databranch name=\"");
|
||||||
sb.append(TextUtil.escapeXML(branch.getBranchName()));
|
sb.append(TextUtil.escapeXML(branch.getBranchName()));
|
||||||
|
sb.append("\" ");
|
||||||
|
|
||||||
// Kevins version where typekeys are used
|
// Kevins version where typekeys are used
|
||||||
/*
|
/*
|
||||||
@ -547,7 +548,19 @@ public class OpenRocketSaver extends RocketSaver {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
sb.append("\" types=\"");
|
if (!Double.isNaN(branch.getOptimumAltitude())) {
|
||||||
|
sb.append("optimumAltitude=\"");
|
||||||
|
sb.append(branch.getOptimumAltitude());
|
||||||
|
sb.append("\" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Double.isNaN(branch.getTimeToOptimumAltitude())) {
|
||||||
|
sb.append("timeToOptimumAltitude=\"");
|
||||||
|
sb.append(branch.getTimeToOptimumAltitude());
|
||||||
|
sb.append("\" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.append("types=\"");
|
||||||
for (int i = 0; i < types.length; i++) {
|
for (int i = 0; i < types.length; i++) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.append(",");
|
sb.append(",");
|
||||||
@ -590,8 +603,6 @@ public class OpenRocketSaver extends RocketSaver {
|
|||||||
writeln("</databranch>");
|
writeln("</databranch>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* TODO: LOW: This is largely duplicated from above! */
|
/* TODO: LOW: This is largely duplicated from above! */
|
||||||
private int countFlightDataBranchPoints(FlightDataBranch branch, double timeSkip) {
|
private int countFlightDataBranchPoints(FlightDataBranch branch, double timeSkip) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
@ -42,6 +42,22 @@ class FlightDataBranchHandler extends AbstractElementHandler {
|
|||||||
branch = new FlightDataBranch(name, types);
|
branch = new FlightDataBranch(name, types);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param timeToOptimumAltitude
|
||||||
|
* @see net.sf.openrocket.simulation.FlightDataBranch#setTimeToOptimumAltitude(double)
|
||||||
|
*/
|
||||||
|
public void setTimeToOptimumAltitude(double timeToOptimumAltitude) {
|
||||||
|
branch.setTimeToOptimumAltitude(timeToOptimumAltitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param optimumAltitude
|
||||||
|
* @see net.sf.openrocket.simulation.FlightDataBranch#setOptimumAltitude(double)
|
||||||
|
*/
|
||||||
|
public void setOptimumAltitude(double optimumAltitude) {
|
||||||
|
branch.setOptimumAltitude(optimumAltitude);
|
||||||
|
}
|
||||||
|
|
||||||
// Find the full flight data type given name only
|
// Find the full flight data type given name only
|
||||||
// Note: this way of doing it requires that custom expressions always come before flight data in the file,
|
// Note: this way of doing it requires that custom expressions always come before flight data in the file,
|
||||||
// not the nicest but this is always the case anyway.
|
// not the nicest but this is always the case anyway.
|
||||||
|
@ -48,6 +48,23 @@ class FlightDataHandler extends AbstractElementHandler {
|
|||||||
dataHandler = new FlightDataBranchHandler(attributes.get("name"),
|
dataHandler = new FlightDataBranchHandler(attributes.get("name"),
|
||||||
attributes.get("types"),
|
attributes.get("types"),
|
||||||
simHandler, context);
|
simHandler, context);
|
||||||
|
|
||||||
|
if (attributes.get("optimumAltitude") != null) {
|
||||||
|
double optimumAltitude = Double.NaN;
|
||||||
|
try {
|
||||||
|
optimumAltitude = Double.parseDouble(attributes.get("optimumAltitude"));
|
||||||
|
} catch (NumberFormatException ignore) {
|
||||||
|
}
|
||||||
|
dataHandler.setOptimumAltitude(optimumAltitude);
|
||||||
|
}
|
||||||
|
if (attributes.get("timeToOptimumAltitude") != null) {
|
||||||
|
double timeToOptimumAltitude = Double.NaN;
|
||||||
|
try {
|
||||||
|
timeToOptimumAltitude = Double.parseDouble(attributes.get("timeToOptimumAltitude"));
|
||||||
|
} catch (NumberFormatException ignore) {
|
||||||
|
}
|
||||||
|
dataHandler.setTimeToOptimumAltitude(timeToOptimumAltitude);
|
||||||
|
}
|
||||||
return dataHandler;
|
return dataHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import net.sf.openrocket.simulation.exception.MotorIgnitionException;
|
|||||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||||
import net.sf.openrocket.simulation.exception.SimulationLaunchException;
|
import net.sf.openrocket.simulation.exception.SimulationLaunchException;
|
||||||
import net.sf.openrocket.simulation.listeners.SimulationListenerHelper;
|
import net.sf.openrocket.simulation.listeners.SimulationListenerHelper;
|
||||||
|
import net.sf.openrocket.simulation.listeners.system.OptimumCoastListener;
|
||||||
import net.sf.openrocket.startup.Application;
|
import net.sf.openrocket.startup.Application;
|
||||||
import net.sf.openrocket.unit.UnitGroup;
|
import net.sf.openrocket.unit.UnitGroup;
|
||||||
import net.sf.openrocket.util.Coordinate;
|
import net.sf.openrocket.util.Coordinate;
|
||||||
@ -120,8 +121,6 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
Coordinate originVelocity = status.getRocketVelocity();
|
Coordinate originVelocity = status.getRocketVelocity();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
double maxAlt = Double.NEGATIVE_INFINITY;
|
|
||||||
|
|
||||||
// Start the simulation
|
// Start the simulation
|
||||||
while (handleEvents()) {
|
while (handleEvents()) {
|
||||||
|
|
||||||
@ -149,8 +148,8 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
status.getConfiguration().getRocket(),
|
status.getConfiguration().getRocket(),
|
||||||
new Pair<Double, Double>(oldAlt, status.getRocketPosition().z)));
|
new Pair<Double, Double>(oldAlt, status.getRocketPosition().z)));
|
||||||
|
|
||||||
if (status.getRocketPosition().z > maxAlt) {
|
if (status.getRocketPosition().z > status.getMaxAlt()) {
|
||||||
maxAlt = status.getRocketPosition().z;
|
status.setMaxAlt(status.getRocketPosition().z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -189,7 +188,8 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
|
|
||||||
|
|
||||||
// Check for apogee
|
// Check for apogee
|
||||||
if (!status.isApogeeReached() && status.getRocketPosition().z < maxAlt - 0.01) {
|
if (!status.isApogeeReached() && status.getRocketPosition().z < status.getMaxAlt() - 0.01) {
|
||||||
|
status.setMaxAltTime(status.getSimulationTime());
|
||||||
addEvent(new FlightEvent(FlightEvent.Type.APOGEE, status.getSimulationTime(),
|
addEvent(new FlightEvent(FlightEvent.Type.APOGEE, status.getSimulationTime(),
|
||||||
status.getConfiguration().getRocket()));
|
status.getConfiguration().getRocket()));
|
||||||
}
|
}
|
||||||
@ -464,6 +464,11 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
// Mark apogee as reached
|
// Mark apogee as reached
|
||||||
status.setApogeeReached(true);
|
status.setApogeeReached(true);
|
||||||
status.getFlightData().addEvent(event);
|
status.getFlightData().addEvent(event);
|
||||||
|
// This apogee event might be the optimum if recovery has not already happened.
|
||||||
|
if (status.getSimulationConditions().isCalculateExtras() && status.getDeployedRecoveryDevices().size() == 0) {
|
||||||
|
status.getFlightData().setOptimumAltitude(status.getMaxAlt());
|
||||||
|
status.getFlightData().setTimeToOptimumAltitude(status.getMaxAltTime());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RECOVERY_DEVICE_DEPLOYMENT:
|
case RECOVERY_DEVICE_DEPLOYMENT:
|
||||||
@ -501,6 +506,14 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
status.setLiftoff(true);
|
status.setLiftoff(true);
|
||||||
status.getDeployedRecoveryDevices().add((RecoveryDevice) c);
|
status.getDeployedRecoveryDevices().add((RecoveryDevice) c);
|
||||||
|
|
||||||
|
// If we haven't already reached apogee, then we need to compute the actual coast time
|
||||||
|
// to determine the optimum altitude.
|
||||||
|
if (status.getSimulationConditions().isCalculateExtras() && !status.isApogeeReached()) {
|
||||||
|
FlightData coastStatus = computeCoastTime();
|
||||||
|
status.getFlightData().setOptimumAltitude(coastStatus.getMaxAltitude());
|
||||||
|
status.getFlightData().setTimeToOptimumAltitude(coastStatus.getTimeToApogee());
|
||||||
|
}
|
||||||
|
|
||||||
this.currentStepper = this.landingStepper;
|
this.currentStepper = this.landingStepper;
|
||||||
this.status = currentStepper.initialize(status);
|
this.status = currentStepper.initialize(status);
|
||||||
|
|
||||||
@ -601,5 +614,17 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FlightData computeCoastTime() {
|
||||||
|
try {
|
||||||
|
SimulationConditions conds = status.getSimulationConditions().clone();
|
||||||
|
conds.getSimulationListenerList().add(OptimumCoastListener.INSTANCE);
|
||||||
|
BasicEventSimulationEngine e = new BasicEventSimulationEngine();
|
||||||
|
|
||||||
|
FlightData d = e.simulate(conds);
|
||||||
|
return d;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Exception computing coast time: ", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,15 @@ public class FlightDataBranch implements Monitorable {
|
|||||||
private final Map<FlightDataType, Double> maxValues = new HashMap<FlightDataType, Double>();
|
private final Map<FlightDataType, Double> maxValues = new HashMap<FlightDataType, Double>();
|
||||||
private final Map<FlightDataType, Double> minValues = new HashMap<FlightDataType, Double>();
|
private final Map<FlightDataType, Double> minValues = new HashMap<FlightDataType, Double>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* time for the rocket to reach apogee if the flight had been no recovery deployment
|
||||||
|
*/
|
||||||
|
private double timeToOptimumAltitude = Double.NaN;
|
||||||
|
/**
|
||||||
|
* Altitude the rocket would reach if there had been no recovery deployment.
|
||||||
|
*/
|
||||||
|
private double optimumAltitude = Double.NaN;
|
||||||
|
|
||||||
private final ArrayList<FlightEvent> events = new ArrayList<FlightEvent>();
|
private final ArrayList<FlightEvent> events = new ArrayList<FlightEvent>();
|
||||||
|
|
||||||
private Mutable mutable = new Mutable();
|
private Mutable mutable = new Mutable();
|
||||||
@ -73,12 +81,12 @@ public class FlightDataBranch implements Monitorable {
|
|||||||
*/
|
*/
|
||||||
public FlightDataBranch() {
|
public FlightDataBranch() {
|
||||||
branchName = "Empty branch";
|
branchName = "Empty branch";
|
||||||
for (FlightDataType type : FlightDataType.ALL_TYPES){
|
for (FlightDataType type : FlightDataType.ALL_TYPES) {
|
||||||
this.setValue(type, Double.NaN);
|
this.setValue(type, Double.NaN);
|
||||||
}
|
}
|
||||||
this.immute();
|
this.immute();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new point into the data branch. The value for all types is set to NaN by default.
|
* Adds a new point into the data branch. The value for all types is set to NaN by default.
|
||||||
*
|
*
|
||||||
@ -115,10 +123,10 @@ public class FlightDataBranch implements Monitorable {
|
|||||||
}
|
}
|
||||||
values.put(type, list);
|
values.put(type, list);
|
||||||
minValues.put(type, value);
|
minValues.put(type, value);
|
||||||
maxValues.put(type, value);
|
maxValues.put(type, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list.size() > 0){
|
if (list.size() > 0) {
|
||||||
list.set(list.size() - 1, value);
|
list.set(list.size() - 1, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,6 +227,50 @@ public class FlightDataBranch implements Monitorable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the timeToOptimumAltitude
|
||||||
|
*/
|
||||||
|
public double getTimeToOptimumAltitude() {
|
||||||
|
return timeToOptimumAltitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param timeToOptimumAltitude the timeToOptimumAltitude to set
|
||||||
|
*/
|
||||||
|
public void setTimeToOptimumAltitude(double timeToOptimumAltitude) {
|
||||||
|
this.timeToOptimumAltitude = timeToOptimumAltitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the optimumAltitude
|
||||||
|
*/
|
||||||
|
public double getOptimumAltitude() {
|
||||||
|
return optimumAltitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param optimumAltitude the optimumAltitude to set
|
||||||
|
*/
|
||||||
|
public void setOptimumAltitude(double optimumAltitude) {
|
||||||
|
this.optimumAltitude = optimumAltitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getOptimumDelay() {
|
||||||
|
|
||||||
|
if (Double.isNaN(timeToOptimumAltitude)) {
|
||||||
|
return Double.NaN;
|
||||||
|
}
|
||||||
|
// TODO - we really want the first burnout of this stage. which
|
||||||
|
// could be computed as the first burnout after the last stage separation event.
|
||||||
|
// however, that's not quite so concise
|
||||||
|
FlightEvent e = getLastEvent(FlightEvent.Type.BURNOUT);
|
||||||
|
if (e != null) {
|
||||||
|
return timeToOptimumAltitude - e.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Double.NaN;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a flight event to this branch.
|
* Add a flight event to this branch.
|
||||||
*
|
*
|
||||||
@ -241,6 +293,34 @@ public class FlightDataBranch implements Monitorable {
|
|||||||
return events.clone();
|
return events.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the first event of the given type.
|
||||||
|
* @param type
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public FlightEvent getFirstEvent(FlightEvent.Type type) {
|
||||||
|
for (FlightEvent e : events) {
|
||||||
|
if (e.getType() == type) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the last event of the given type.
|
||||||
|
* @param type
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public FlightEvent getLastEvent(FlightEvent.Type type) {
|
||||||
|
FlightEvent retval = null;
|
||||||
|
for (FlightEvent e : events) {
|
||||||
|
if (e.getType() == type) {
|
||||||
|
retval = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make this FlightDataBranch immutable. Any calls to the set methods that would
|
* Make this FlightDataBranch immutable. Any calls to the set methods that would
|
||||||
|
@ -29,7 +29,7 @@ public class SimulationConditions implements Monitorable, Cloneable {
|
|||||||
private String motorID = null;
|
private String motorID = null;
|
||||||
|
|
||||||
private Simulation simulation; // The parent simulation
|
private Simulation simulation; // The parent simulation
|
||||||
|
|
||||||
private double launchRodLength = 1;
|
private double launchRodLength = 1;
|
||||||
|
|
||||||
/** Launch rod angle >= 0, radians from vertical */
|
/** Launch rod angle >= 0, radians from vertical */
|
||||||
@ -45,7 +45,7 @@ public class SimulationConditions implements Monitorable, Cloneable {
|
|||||||
private WorldCoordinate launchSite = new WorldCoordinate(0, 0, 0);
|
private WorldCoordinate launchSite = new WorldCoordinate(0, 0, 0);
|
||||||
private GeodeticComputationStrategy geodeticComputation = GeodeticComputationStrategy.SPHERICAL;
|
private GeodeticComputationStrategy geodeticComputation = GeodeticComputationStrategy.SPHERICAL;
|
||||||
|
|
||||||
|
|
||||||
private WindModel windModel;
|
private WindModel windModel;
|
||||||
private AtmosphericModel atmosphericModel;
|
private AtmosphericModel atmosphericModel;
|
||||||
private GravityModel gravityModel;
|
private GravityModel gravityModel;
|
||||||
@ -53,25 +53,25 @@ public class SimulationConditions implements Monitorable, Cloneable {
|
|||||||
private AerodynamicCalculator aerodynamicCalculator;
|
private AerodynamicCalculator aerodynamicCalculator;
|
||||||
private MassCalculator massCalculator;
|
private MassCalculator massCalculator;
|
||||||
|
|
||||||
|
|
||||||
private double timeStep = RK4SimulationStepper.RECOMMENDED_TIME_STEP;
|
private double timeStep = RK4SimulationStepper.RECOMMENDED_TIME_STEP;
|
||||||
private double maximumAngleStep = RK4SimulationStepper.RECOMMENDED_ANGLE_STEP;
|
private double maximumAngleStep = RK4SimulationStepper.RECOMMENDED_ANGLE_STEP;
|
||||||
|
|
||||||
/* Whether to calculate additional data or only primary simulation figures */
|
/* Whether to calculate additional data or only primary simulation figures */
|
||||||
private boolean calculateExtras = true;
|
private boolean calculateExtras = true;
|
||||||
|
|
||||||
|
|
||||||
private List<SimulationListener> simulationListeners = new ArrayList<SimulationListener>();
|
private List<SimulationListener> simulationListeners = new ArrayList<SimulationListener>();
|
||||||
|
|
||||||
|
|
||||||
private int randomSeed = 0;
|
private int randomSeed = 0;
|
||||||
|
|
||||||
private int modID = 0;
|
private int modID = 0;
|
||||||
private int modIDadd = 0;
|
private int modIDadd = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public AerodynamicCalculator getAerodynamicCalculator() {
|
public AerodynamicCalculator getAerodynamicCalculator() {
|
||||||
return aerodynamicCalculator;
|
return aerodynamicCalculator;
|
||||||
}
|
}
|
||||||
@ -253,7 +253,7 @@ public class SimulationConditions implements Monitorable, Cloneable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public int getRandomSeed() {
|
public int getRandomSeed() {
|
||||||
return randomSeed;
|
return randomSeed;
|
||||||
}
|
}
|
||||||
@ -267,8 +267,8 @@ public class SimulationConditions implements Monitorable, Cloneable {
|
|||||||
public void setSimulation(Simulation sim) {
|
public void setSimulation(Simulation sim) {
|
||||||
this.simulation = sim;
|
this.simulation = sim;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Simulation getSimulation(){
|
public Simulation getSimulation() {
|
||||||
return this.simulation;
|
return this.simulation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,7 +291,12 @@ public class SimulationConditions implements Monitorable, Cloneable {
|
|||||||
public SimulationConditions clone() {
|
public SimulationConditions clone() {
|
||||||
try {
|
try {
|
||||||
// TODO: HIGH: Deep clone models
|
// TODO: HIGH: Deep clone models
|
||||||
return (SimulationConditions) super.clone();
|
SimulationConditions clone = (SimulationConditions) super.clone();
|
||||||
|
clone.simulationListeners = new ArrayList<SimulationListener>(this.simulationListeners.size());
|
||||||
|
for (SimulationListener listener : this.simulationListeners) {
|
||||||
|
clone.simulationListeners.add(listener.clone());
|
||||||
|
}
|
||||||
|
return clone;
|
||||||
} catch (CloneNotSupportedException e) {
|
} catch (CloneNotSupportedException e) {
|
||||||
throw new BugException(e);
|
throw new BugException(e);
|
||||||
}
|
}
|
||||||
|
@ -27,10 +27,6 @@ import net.sf.openrocket.util.WorldCoordinate;
|
|||||||
*/
|
*/
|
||||||
public class SimulationStatus implements Monitorable {
|
public class SimulationStatus implements Monitorable {
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE! All fields must be added to copyFrom() method!!
|
|
||||||
*/
|
|
||||||
|
|
||||||
private SimulationConditions simulationConditions;
|
private SimulationConditions simulationConditions;
|
||||||
private Configuration configuration;
|
private Configuration configuration;
|
||||||
private MotorInstanceConfiguration motorConfiguration;
|
private MotorInstanceConfiguration motorConfiguration;
|
||||||
@ -51,12 +47,12 @@ public class SimulationStatus implements Monitorable {
|
|||||||
|
|
||||||
// Set of burnt out motors
|
// Set of burnt out motors
|
||||||
Set<MotorId> motorBurntOut = new HashSet<MotorId>();
|
Set<MotorId> motorBurntOut = new HashSet<MotorId>();
|
||||||
|
|
||||||
|
|
||||||
/** Nanosecond time when the simulation was started. */
|
/** Nanosecond time when the simulation was started. */
|
||||||
private long simulationStartWallTime = Long.MIN_VALUE;
|
private long simulationStartWallTime = Long.MIN_VALUE;
|
||||||
|
|
||||||
|
|
||||||
/** Set to true when a motor has ignited. */
|
/** Set to true when a motor has ignited. */
|
||||||
private boolean motorIgnited = false;
|
private boolean motorIgnited = false;
|
||||||
|
|
||||||
@ -83,38 +79,40 @@ public class SimulationStatus implements Monitorable {
|
|||||||
/** Available for special purposes by the listeners. */
|
/** Available for special purposes by the listeners. */
|
||||||
private final Map<String, Object> extraData = new HashMap<String, Object>();
|
private final Map<String, Object> extraData = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
double maxAlt = Double.NEGATIVE_INFINITY;
|
||||||
|
double maxAltTime = 0;
|
||||||
|
|
||||||
private int modID = 0;
|
private int modID = 0;
|
||||||
private int modIDadd = 0;
|
private int modIDadd = 0;
|
||||||
|
|
||||||
public SimulationStatus( Configuration configuration,
|
public SimulationStatus(Configuration configuration,
|
||||||
MotorInstanceConfiguration motorConfiguration,
|
MotorInstanceConfiguration motorConfiguration,
|
||||||
SimulationConditions simulationConditions ) {
|
SimulationConditions simulationConditions) {
|
||||||
|
|
||||||
this.simulationConditions = simulationConditions;
|
this.simulationConditions = simulationConditions;
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
this.motorConfiguration = motorConfiguration;
|
this.motorConfiguration = motorConfiguration;
|
||||||
|
|
||||||
this.time = 0;
|
this.time = 0;
|
||||||
this.previousTimeStep = this.simulationConditions.getTimeStep();
|
this.previousTimeStep = this.simulationConditions.getTimeStep();
|
||||||
this.position = Coordinate.NUL;
|
this.position = Coordinate.NUL;
|
||||||
this.velocity = Coordinate.NUL;
|
this.velocity = Coordinate.NUL;
|
||||||
this.worldPosition = this.simulationConditions.getLaunchSite();
|
this.worldPosition = this.simulationConditions.getLaunchSite();
|
||||||
|
|
||||||
// Initialize to roll angle with least stability w.r.t. the wind
|
// Initialize to roll angle with least stability w.r.t. the wind
|
||||||
Quaternion o;
|
Quaternion o;
|
||||||
FlightConditions cond = new FlightConditions(this.configuration);
|
FlightConditions cond = new FlightConditions(this.configuration);
|
||||||
this.simulationConditions.getAerodynamicCalculator().getWorstCP(this.configuration, cond, null);
|
this.simulationConditions.getAerodynamicCalculator().getWorstCP(this.configuration, cond, null);
|
||||||
double angle = -cond.getTheta() - this.simulationConditions.getLaunchRodDirection();
|
double angle = -cond.getTheta() - this.simulationConditions.getLaunchRodDirection();
|
||||||
o = Quaternion.rotation(new Coordinate(0, 0, angle));
|
o = Quaternion.rotation(new Coordinate(0, 0, angle));
|
||||||
|
|
||||||
// Launch rod angle and direction
|
// Launch rod angle and direction
|
||||||
o = o.multiplyLeft(Quaternion.rotation(new Coordinate(0, this.simulationConditions.getLaunchRodAngle(), 0)));
|
o = o.multiplyLeft(Quaternion.rotation(new Coordinate(0, this.simulationConditions.getLaunchRodAngle(), 0)));
|
||||||
o = o.multiplyLeft(Quaternion.rotation(new Coordinate(0, 0, this.simulationConditions.getLaunchRodDirection())));
|
o = o.multiplyLeft(Quaternion.rotation(new Coordinate(0, 0, this.simulationConditions.getLaunchRodDirection())));
|
||||||
|
|
||||||
this.orientation = o;
|
this.orientation = o;
|
||||||
this.rotationVelocity = Coordinate.NUL;
|
this.rotationVelocity = Coordinate.NUL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate the effective launch rod length taking into account launch lugs.
|
* Calculate the effective launch rod length taking into account launch lugs.
|
||||||
* If no lugs are found, assume a tower launcher of full length.
|
* If no lugs are found, assume a tower launcher of full length.
|
||||||
@ -140,16 +138,16 @@ public class SimulationStatus implements Monitorable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.effectiveLaunchRodLength = length;
|
this.effectiveLaunchRodLength = length;
|
||||||
|
|
||||||
this.simulationStartWallTime = System.nanoTime();
|
this.simulationStartWallTime = System.nanoTime();
|
||||||
|
|
||||||
this.motorIgnited = false;
|
this.motorIgnited = false;
|
||||||
this.liftoff = false;
|
this.liftoff = false;
|
||||||
this.launchRodCleared = false;
|
this.launchRodCleared = false;
|
||||||
this.apogeeReached = false;
|
this.apogeeReached = false;
|
||||||
|
|
||||||
this.warnings = new WarningSet();
|
this.warnings = new WarningSet();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -163,7 +161,7 @@ public class SimulationStatus implements Monitorable {
|
|||||||
*
|
*
|
||||||
* @param orig the object from which to copy
|
* @param orig the object from which to copy
|
||||||
*/
|
*/
|
||||||
public SimulationStatus( SimulationStatus orig ) {
|
public SimulationStatus(SimulationStatus orig) {
|
||||||
this.simulationConditions = orig.simulationConditions.clone();
|
this.simulationConditions = orig.simulationConditions.clone();
|
||||||
this.configuration = orig.configuration.clone();
|
this.configuration = orig.configuration.clone();
|
||||||
this.motorConfiguration = orig.motorConfiguration.clone();
|
this.motorConfiguration = orig.motorConfiguration.clone();
|
||||||
@ -292,11 +290,11 @@ public class SimulationStatus implements Monitorable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean addBurntOutMotor( MotorId motor ) {
|
public boolean addBurntOutMotor(MotorId motor) {
|
||||||
return motorBurntOut.add(motor);
|
return motorBurntOut.add(motor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Quaternion getRocketOrientationQuaternion() {
|
public Quaternion getRocketOrientationQuaternion() {
|
||||||
return orientation;
|
return orientation;
|
||||||
}
|
}
|
||||||
@ -384,7 +382,7 @@ public class SimulationStatus implements Monitorable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setTumbling( boolean tumbling ) {
|
public void setTumbling(boolean tumbling) {
|
||||||
this.tumbling = tumbling;
|
this.tumbling = tumbling;
|
||||||
this.modID++;
|
this.modID++;
|
||||||
}
|
}
|
||||||
@ -393,6 +391,24 @@ public class SimulationStatus implements Monitorable {
|
|||||||
return tumbling;
|
return tumbling;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double getMaxAlt() {
|
||||||
|
return maxAlt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxAlt(double maxAlt) {
|
||||||
|
this.maxAlt = maxAlt;
|
||||||
|
this.modID++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getMaxAltTime() {
|
||||||
|
return maxAltTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxAltTime(double maxAltTime) {
|
||||||
|
this.maxAltTime = maxAltTime;
|
||||||
|
this.modID++;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<RecoveryDevice> getDeployedRecoveryDevices() {
|
public Set<RecoveryDevice> getDeployedRecoveryDevices() {
|
||||||
return deployedRecoveryDevices;
|
return deployedRecoveryDevices;
|
||||||
}
|
}
|
||||||
@ -477,5 +493,5 @@ public class SimulationStatus implements Monitorable {
|
|||||||
eventQueue.getModID() + warnings.getModID());
|
eventQueue.getModID() + warnings.getModID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ public class AbstractSimulationListener implements SimulationListener, Simulatio
|
|||||||
* Return an array of any flight data types this listener creates.
|
* Return an array of any flight data types this listener creates.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public FlightDataType[] getFlightDataTypes(){
|
public FlightDataType[] getFlightDataTypes() {
|
||||||
return new FlightDataType[] {};
|
return new FlightDataType[] {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,4 +183,9 @@ public class AbstractSimulationListener implements SimulationListener, Simulatio
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractSimulationListener clone() throws CloneNotSupportedException {
|
||||||
|
return (AbstractSimulationListener) super.clone();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,13 @@ import net.sf.openrocket.simulation.FlightDataType;
|
|||||||
import net.sf.openrocket.simulation.SimulationStatus;
|
import net.sf.openrocket.simulation.SimulationStatus;
|
||||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to simulation events and possibly take action.
|
||||||
public interface SimulationListener {
|
*
|
||||||
|
* If the implementation maintains any state, it should be properly cloned.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface SimulationListener extends Cloneable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the name of this simulation listener. Ideally this should be localized, as
|
* Get the name of this simulation listener. Ideally this should be localized, as
|
||||||
@ -83,5 +87,5 @@ public interface SimulationListener {
|
|||||||
*/
|
*/
|
||||||
public FlightDataType[] getFlightDataTypes();
|
public FlightDataType[] getFlightDataTypes();
|
||||||
|
|
||||||
|
public SimulationListener clone() throws CloneNotSupportedException;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
package net.sf.openrocket.simulation.listeners.system;
|
||||||
|
|
||||||
|
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
|
||||||
|
import net.sf.openrocket.simulation.FlightEvent;
|
||||||
|
import net.sf.openrocket.simulation.SimulationStatus;
|
||||||
|
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||||
|
import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simulation listener which ignores recovery deployment events and ends the simulation
|
||||||
|
* when apogee is reached.
|
||||||
|
*
|
||||||
|
* @author kevin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class OptimumCoastListener extends AbstractSimulationListener {
|
||||||
|
|
||||||
|
public static final OptimumCoastListener INSTANCE = new OptimumCoastListener();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handleFlightEvent(SimulationStatus status, FlightEvent event) {
|
||||||
|
if (event.getType() == FlightEvent.Type.APOGEE) {
|
||||||
|
status.getEventQueue().add(new FlightEvent(FlightEvent.Type.SIMULATION_END, status.getSimulationTime()));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean recoveryDeviceDeployment(SimulationStatus status, RecoveryDevice recoveryDevice) throws SimulationException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSystemListener() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -6,6 +6,7 @@ import javax.swing.table.TableColumnModel;
|
|||||||
|
|
||||||
public abstract class Column {
|
public abstract class Column {
|
||||||
private final String name;
|
private final String name;
|
||||||
|
private final String toolTip;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new column with specified name. Additionally, the {@link #getValueAt(int)}
|
* Create a new column with specified name. Additionally, the {@link #getValueAt(int)}
|
||||||
@ -15,6 +16,17 @@ public abstract class Column {
|
|||||||
*/
|
*/
|
||||||
public Column(String name) {
|
public Column(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.toolTip = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new column with specified name and toolTip.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public Column(String name, String toolTip ) {
|
||||||
|
this.name = name;
|
||||||
|
this.toolTip = toolTip;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -87,5 +99,9 @@ public abstract class Column {
|
|||||||
public Comparator getComparator() {
|
public Comparator getComparator() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getToolTip() {
|
||||||
|
return toolTip;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
28
swing/src/net/sf/openrocket/gui/adaptors/ColumnTable.java
Normal file
28
swing/src/net/sf/openrocket/gui/adaptors/ColumnTable.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package net.sf.openrocket.gui.adaptors;
|
||||||
|
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
|
||||||
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.table.JTableHeader;
|
||||||
|
|
||||||
|
public class ColumnTable extends JTable {
|
||||||
|
|
||||||
|
public ColumnTable( ColumnTableModel model ) {
|
||||||
|
super(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JTableHeader createDefaultTableHeader() {
|
||||||
|
return new JTableHeader( columnModel ) {
|
||||||
|
public String getToolTipText(MouseEvent e) {
|
||||||
|
String tip = null;
|
||||||
|
java.awt.Point p = e.getPoint();
|
||||||
|
int index = columnModel.getColumnIndexAtX(p.x);
|
||||||
|
int realIndex = columnModel.getColumn(index).getModelIndex();
|
||||||
|
tip = ((ColumnTableModel) getModel()).getColumn(realIndex).getToolTip();
|
||||||
|
return tip;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -15,6 +15,11 @@ public abstract class ValueColumn extends Column {
|
|||||||
this.unit = unit;
|
this.unit = unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ValueColumn( String name, String toolTip, UnitGroup unit ) {
|
||||||
|
super( name, toolTip );
|
||||||
|
this.unit = unit;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getValueAt(int row) {
|
public Object getValueAt(int row) {
|
||||||
Double d = valueAt(row);
|
Double d = valueAt(row);
|
||||||
|
@ -43,6 +43,7 @@ import net.sf.openrocket.aerodynamics.FlightConditions;
|
|||||||
import net.sf.openrocket.aerodynamics.Warning;
|
import net.sf.openrocket.aerodynamics.Warning;
|
||||||
import net.sf.openrocket.aerodynamics.WarningSet;
|
import net.sf.openrocket.aerodynamics.WarningSet;
|
||||||
import net.sf.openrocket.gui.adaptors.Column;
|
import net.sf.openrocket.gui.adaptors.Column;
|
||||||
|
import net.sf.openrocket.gui.adaptors.ColumnTable;
|
||||||
import net.sf.openrocket.gui.adaptors.ColumnTableModel;
|
import net.sf.openrocket.gui.adaptors.ColumnTableModel;
|
||||||
import net.sf.openrocket.gui.adaptors.DoubleModel;
|
import net.sf.openrocket.gui.adaptors.DoubleModel;
|
||||||
import net.sf.openrocket.gui.adaptors.FlightConfigurationModel;
|
import net.sf.openrocket.gui.adaptors.FlightConfigurationModel;
|
||||||
@ -243,7 +244,7 @@ public class ComponentAnalysisDialog extends JDialog implements StateChangeListe
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
table = new JTable(cpTableModel);
|
table = new ColumnTable(cpTableModel);
|
||||||
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||||
table.setSelectionBackground(Color.LIGHT_GRAY);
|
table.setSelectionBackground(Color.LIGHT_GRAY);
|
||||||
table.setSelectionForeground(Color.BLACK);
|
table.setSelectionForeground(Color.BLACK);
|
||||||
|
@ -40,6 +40,7 @@ import javax.swing.table.TableRowSorter;
|
|||||||
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import net.sf.openrocket.gui.adaptors.Column;
|
import net.sf.openrocket.gui.adaptors.Column;
|
||||||
|
import net.sf.openrocket.gui.adaptors.ColumnTable;
|
||||||
import net.sf.openrocket.gui.adaptors.ColumnTableModel;
|
import net.sf.openrocket.gui.adaptors.ColumnTableModel;
|
||||||
import net.sf.openrocket.gui.components.SelectableLabel;
|
import net.sf.openrocket.gui.components.SelectableLabel;
|
||||||
import net.sf.openrocket.gui.util.GUIUtil;
|
import net.sf.openrocket.gui.util.GUIUtil;
|
||||||
@ -266,7 +267,7 @@ public class DebugLogDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
table = new JTable(model);
|
table = new ColumnTable(model);
|
||||||
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
||||||
table.setSelectionBackground(Color.LIGHT_GRAY);
|
table.setSelectionBackground(Color.LIGHT_GRAY);
|
||||||
table.setSelectionForeground(Color.BLACK);
|
table.setSelectionForeground(Color.BLACK);
|
||||||
|
@ -23,6 +23,7 @@ import net.miginfocom.swing.MigLayout;
|
|||||||
import net.sf.openrocket.database.Database;
|
import net.sf.openrocket.database.Database;
|
||||||
import net.sf.openrocket.database.Databases;
|
import net.sf.openrocket.database.Databases;
|
||||||
import net.sf.openrocket.gui.adaptors.Column;
|
import net.sf.openrocket.gui.adaptors.Column;
|
||||||
|
import net.sf.openrocket.gui.adaptors.ColumnTable;
|
||||||
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.components.StyledLabel.Style;
|
import net.sf.openrocket.gui.components.StyledLabel.Style;
|
||||||
@ -108,7 +109,7 @@ public class MaterialEditPanel extends JPanel {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
table = new JTable(model);
|
table = new ColumnTable(model);
|
||||||
model.setColumnWidths(table.getColumnModel());
|
model.setColumnWidths(table.getColumnModel());
|
||||||
table.setAutoCreateRowSorter(true);
|
table.setAutoCreateRowSorter(true);
|
||||||
table.setDefaultRenderer(Object.class, new MaterialCellRenderer());
|
table.setDefaultRenderer(Object.class, new MaterialCellRenderer());
|
||||||
|
@ -35,6 +35,7 @@ import net.sf.openrocket.document.events.DocumentChangeListener;
|
|||||||
import net.sf.openrocket.document.events.SimulationChangeEvent;
|
import net.sf.openrocket.document.events.SimulationChangeEvent;
|
||||||
import net.sf.openrocket.formatting.RocketDescriptor;
|
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.ColumnTable;
|
||||||
import net.sf.openrocket.gui.adaptors.ColumnTableModel;
|
import net.sf.openrocket.gui.adaptors.ColumnTableModel;
|
||||||
import net.sf.openrocket.gui.adaptors.ColumnTableRowSorter;
|
import net.sf.openrocket.gui.adaptors.ColumnTableRowSorter;
|
||||||
import net.sf.openrocket.gui.adaptors.ValueColumn;
|
import net.sf.openrocket.gui.adaptors.ValueColumn;
|
||||||
@ -48,6 +49,7 @@ import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
|
|||||||
import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
|
import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
|
||||||
import net.sf.openrocket.rocketcomponent.Configuration;
|
import net.sf.openrocket.rocketcomponent.Configuration;
|
||||||
import net.sf.openrocket.simulation.FlightData;
|
import net.sf.openrocket.simulation.FlightData;
|
||||||
|
import net.sf.openrocket.simulation.FlightEvent;
|
||||||
import net.sf.openrocket.startup.Application;
|
import net.sf.openrocket.startup.Application;
|
||||||
import net.sf.openrocket.startup.Preferences;
|
import net.sf.openrocket.startup.Preferences;
|
||||||
import net.sf.openrocket.unit.UnitGroup;
|
import net.sf.openrocket.unit.UnitGroup;
|
||||||
@ -59,37 +61,37 @@ import org.slf4j.LoggerFactory;
|
|||||||
public class SimulationPanel extends JPanel {
|
public class SimulationPanel extends JPanel {
|
||||||
private static final Logger log = LoggerFactory.getLogger(SimulationPanel.class);
|
private static final Logger log = LoggerFactory.getLogger(SimulationPanel.class);
|
||||||
private static final Translator trans = Application.getTranslator();
|
private static final Translator trans = Application.getTranslator();
|
||||||
|
|
||||||
|
|
||||||
private static final Color WARNING_COLOR = Color.RED;
|
private static final Color WARNING_COLOR = Color.RED;
|
||||||
private static final String WARNING_TEXT = "\uFF01"; // Fullwidth exclamation mark
|
private static final String WARNING_TEXT = "\uFF01"; // Fullwidth exclamation mark
|
||||||
|
|
||||||
private static final Color OK_COLOR = new Color(60, 150, 0);
|
private static final Color OK_COLOR = new Color(60, 150, 0);
|
||||||
private static final String OK_TEXT = "\u2714"; // Heavy check mark
|
private static final String OK_TEXT = "\u2714"; // Heavy check mark
|
||||||
|
|
||||||
|
|
||||||
private RocketDescriptor descriptor = Application.getInjector().getInstance(RocketDescriptor.class);
|
private RocketDescriptor descriptor = Application.getInjector().getInstance(RocketDescriptor.class);
|
||||||
|
|
||||||
|
|
||||||
private final OpenRocketDocument document;
|
private final OpenRocketDocument document;
|
||||||
|
|
||||||
private final ColumnTableModel simulationTableModel;
|
private final ColumnTableModel simulationTableModel;
|
||||||
private final JTable simulationTable;
|
private final JTable simulationTable;
|
||||||
|
|
||||||
private final JButton editButton;
|
private final JButton editButton;
|
||||||
private final JButton runButton;
|
private final JButton runButton;
|
||||||
private final JButton deleteButton;
|
private final JButton deleteButton;
|
||||||
private final JButton plotButton;
|
private final JButton plotButton;
|
||||||
|
|
||||||
public SimulationPanel(OpenRocketDocument doc) {
|
public SimulationPanel(OpenRocketDocument doc) {
|
||||||
super(new MigLayout("fill", "[grow][][][][][][grow]"));
|
super(new MigLayout("fill", "[grow][][][][][][grow]"));
|
||||||
|
|
||||||
this.document = doc;
|
this.document = doc;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//////// The simulation action buttons
|
//////// The simulation action buttons
|
||||||
|
|
||||||
//// New simulation button
|
//// New simulation button
|
||||||
{
|
{
|
||||||
JButton button = new JButton(trans.get("simpanel.but.newsimulation"));
|
JButton button = new JButton(trans.get("simpanel.but.newsimulation"));
|
||||||
@ -100,19 +102,19 @@ public class SimulationPanel extends JPanel {
|
|||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
Simulation sim = new Simulation(document.getRocket());
|
Simulation sim = new Simulation(document.getRocket());
|
||||||
sim.setName(document.getNextSimulationName());
|
sim.setName(document.getNextSimulationName());
|
||||||
|
|
||||||
int n = document.getSimulationCount();
|
int n = document.getSimulationCount();
|
||||||
document.addSimulation(sim);
|
document.addSimulation(sim);
|
||||||
simulationTableModel.fireTableDataChanged();
|
simulationTableModel.fireTableDataChanged();
|
||||||
simulationTable.clearSelection();
|
simulationTable.clearSelection();
|
||||||
simulationTable.addRowSelectionInterval(n, n);
|
simulationTable.addRowSelectionInterval(n, n);
|
||||||
|
|
||||||
openDialog(false, sim);
|
openDialog(false, sim);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.add(button, "skip 1, gapright para");
|
this.add(button, "skip 1, gapright para");
|
||||||
}
|
}
|
||||||
|
|
||||||
//// Edit simulation button
|
//// Edit simulation button
|
||||||
editButton = new JButton(trans.get("simpanel.but.editsimulation"));
|
editButton = new JButton(trans.get("simpanel.but.editsimulation"));
|
||||||
//// Edit the selected simulation
|
//// Edit the selected simulation
|
||||||
@ -133,7 +135,7 @@ public class SimulationPanel extends JPanel {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.add(editButton, "gapright para");
|
this.add(editButton, "gapright para");
|
||||||
|
|
||||||
//// Run simulations
|
//// Run simulations
|
||||||
runButton = new JButton(trans.get("simpanel.but.runsimulations"));
|
runButton = new JButton(trans.get("simpanel.but.runsimulations"));
|
||||||
//// Re-run the selected simulations
|
//// Re-run the selected simulations
|
||||||
@ -150,7 +152,7 @@ public class SimulationPanel extends JPanel {
|
|||||||
selection[i] = simulationTable.convertRowIndexToModel(selection[i]);
|
selection[i] = simulationTable.convertRowIndexToModel(selection[i]);
|
||||||
sims[i] = document.getSimulation(selection[i]);
|
sims[i] = document.getSimulation(selection[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
long t = System.currentTimeMillis();
|
long t = System.currentTimeMillis();
|
||||||
new SimulationRunDialog(SwingUtilities.getWindowAncestor(
|
new SimulationRunDialog(SwingUtilities.getWindowAncestor(
|
||||||
SimulationPanel.this), document, sims).setVisible(true);
|
SimulationPanel.this), document, sims).setVisible(true);
|
||||||
@ -159,7 +161,7 @@ public class SimulationPanel extends JPanel {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.add(runButton, "gapright para");
|
this.add(runButton, "gapright para");
|
||||||
|
|
||||||
//// Delete simulations button
|
//// Delete simulations button
|
||||||
deleteButton = new JButton(trans.get("simpanel.but.deletesimulations"));
|
deleteButton = new JButton(trans.get("simpanel.but.deletesimulations"));
|
||||||
//// Delete the selected simulations
|
//// Delete the selected simulations
|
||||||
@ -174,34 +176,34 @@ public class SimulationPanel extends JPanel {
|
|||||||
// Verify deletion
|
// Verify deletion
|
||||||
boolean verify = Application.getPreferences().getBoolean(Preferences.CONFIRM_DELETE_SIMULATION, true);
|
boolean verify = Application.getPreferences().getBoolean(Preferences.CONFIRM_DELETE_SIMULATION, true);
|
||||||
if (verify) {
|
if (verify) {
|
||||||
|
|
||||||
JPanel panel = new JPanel(new MigLayout());
|
JPanel panel = new JPanel(new MigLayout());
|
||||||
//// Do not ask me again
|
//// Do not ask me again
|
||||||
JCheckBox dontAsk = new JCheckBox(trans.get("simpanel.checkbox.donotask"));
|
JCheckBox dontAsk = new JCheckBox(trans.get("simpanel.checkbox.donotask"));
|
||||||
panel.add(dontAsk, "wrap");
|
panel.add(dontAsk, "wrap");
|
||||||
//// You can change the default operation in the preferences.
|
//// You can change the default operation in the preferences.
|
||||||
panel.add(new StyledLabel(trans.get("simpanel.lbl.defpref"), -2));
|
panel.add(new StyledLabel(trans.get("simpanel.lbl.defpref"), -2));
|
||||||
|
|
||||||
int ret = JOptionPane.showConfirmDialog(SimulationPanel.this,
|
int ret = JOptionPane.showConfirmDialog(SimulationPanel.this,
|
||||||
new Object[] {
|
new Object[] {
|
||||||
//// Delete the selected simulations?
|
//// Delete the selected simulations?
|
||||||
trans.get("simpanel.dlg.lbl.DeleteSim1"),
|
trans.get("simpanel.dlg.lbl.DeleteSim1"),
|
||||||
//// <html><i>This operation cannot be undone.</i>
|
//// <html><i>This operation cannot be undone.</i>
|
||||||
trans.get("simpanel.dlg.lbl.DeleteSim2"),
|
trans.get("simpanel.dlg.lbl.DeleteSim2"),
|
||||||
"",
|
"",
|
||||||
panel },
|
panel },
|
||||||
//// Delete simulations
|
//// Delete simulations
|
||||||
trans.get("simpanel.dlg.lbl.DeleteSim3"),
|
trans.get("simpanel.dlg.lbl.DeleteSim3"),
|
||||||
JOptionPane.OK_CANCEL_OPTION,
|
JOptionPane.OK_CANCEL_OPTION,
|
||||||
JOptionPane.WARNING_MESSAGE);
|
JOptionPane.WARNING_MESSAGE);
|
||||||
if (ret != JOptionPane.OK_OPTION)
|
if (ret != JOptionPane.OK_OPTION)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (dontAsk.isSelected()) {
|
if (dontAsk.isSelected()) {
|
||||||
Application.getPreferences().putBoolean(Preferences.CONFIRM_DELETE_SIMULATION, false);
|
Application.getPreferences().putBoolean(Preferences.CONFIRM_DELETE_SIMULATION, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete simulations
|
// Delete simulations
|
||||||
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]);
|
||||||
@ -214,7 +216,7 @@ public class SimulationPanel extends JPanel {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.add(deleteButton, "gapright para");
|
this.add(deleteButton, "gapright para");
|
||||||
|
|
||||||
//// Plot / export button
|
//// Plot / export button
|
||||||
plotButton = 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");
|
||||||
@ -228,58 +230,58 @@ public class SimulationPanel extends JPanel {
|
|||||||
selected = simulationTable.convertRowIndexToModel(selected);
|
selected = simulationTable.convertRowIndexToModel(selected);
|
||||||
simulationTable.clearSelection();
|
simulationTable.clearSelection();
|
||||||
simulationTable.addRowSelectionInterval(selected, selected);
|
simulationTable.addRowSelectionInterval(selected, selected);
|
||||||
|
|
||||||
|
|
||||||
Simulation sim = document.getSimulations().get(selected);
|
Simulation sim = document.getSimulations().get(selected);
|
||||||
|
|
||||||
if (!sim.hasSimulationData()) {
|
if (!sim.hasSimulationData()) {
|
||||||
new SimulationRunDialog(SwingUtilities.getWindowAncestor(
|
new SimulationRunDialog(SwingUtilities.getWindowAncestor(
|
||||||
SimulationPanel.this), document, sim).setVisible(true);
|
SimulationPanel.this), document, sim).setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
fireMaintainSelection();
|
fireMaintainSelection();
|
||||||
|
|
||||||
openDialog(true, sim);
|
openDialog(true, sim);
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.add(plotButton, "wrap para");
|
this.add(plotButton, "wrap para");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//////// The simulation table
|
//////// The simulation table
|
||||||
|
|
||||||
simulationTableModel = new ColumnTableModel(
|
simulationTableModel = new ColumnTableModel(
|
||||||
|
|
||||||
//// Status and warning column
|
//// Status and warning column
|
||||||
new Column("") {
|
new Column("") {
|
||||||
private JLabel label = null;
|
private JLabel label = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getValueAt(int row) {
|
public Object getValueAt(int row) {
|
||||||
if (row < 0 || row >= document.getSimulationCount())
|
if (row < 0 || row >= document.getSimulationCount())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Initialize the label
|
// Initialize the label
|
||||||
if (label == null) {
|
if (label == null) {
|
||||||
label = new StyledLabel(2f);
|
label = new StyledLabel(2f);
|
||||||
label.setIconTextGap(1);
|
label.setIconTextGap(1);
|
||||||
// label.setFont(label.getFont().deriveFont(Font.BOLD));
|
// label.setFont(label.getFont().deriveFont(Font.BOLD));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set simulation status icon
|
// Set simulation status icon
|
||||||
Simulation.Status status = document.getSimulation(row).getStatus();
|
Simulation.Status status = document.getSimulation(row).getStatus();
|
||||||
label.setIcon(Icons.SIMULATION_STATUS_ICON_MAP.get(status));
|
label.setIcon(Icons.SIMULATION_STATUS_ICON_MAP.get(status));
|
||||||
|
|
||||||
|
|
||||||
// Set warning marker
|
// Set warning marker
|
||||||
if (status == Simulation.Status.NOT_SIMULATED ||
|
if (status == Simulation.Status.NOT_SIMULATED ||
|
||||||
status == Simulation.Status.EXTERNAL) {
|
status == Simulation.Status.EXTERNAL) {
|
||||||
|
|
||||||
label.setText("");
|
label.setText("");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
WarningSet w = document.getSimulation(row).getSimulatedWarnings();
|
WarningSet w = document.getSimulation(row).getSimulatedWarnings();
|
||||||
if (w == null) {
|
if (w == null) {
|
||||||
label.setText("");
|
label.setText("");
|
||||||
@ -291,21 +293,21 @@ public class SimulationPanel extends JPanel {
|
|||||||
label.setText(WARNING_TEXT);
|
label.setText(WARNING_TEXT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getExactWidth() {
|
public int getExactWidth() {
|
||||||
return 36;
|
return 36;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<?> getColumnClass() {
|
public Class<?> getColumnClass() {
|
||||||
return JLabel.class;
|
return JLabel.class;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
//// Simulation name
|
//// Simulation name
|
||||||
//// Name
|
//// Name
|
||||||
new Column(trans.get("simpanel.col.Name")) {
|
new Column(trans.get("simpanel.col.Name")) {
|
||||||
@ -315,18 +317,18 @@ public class SimulationPanel extends JPanel {
|
|||||||
return null;
|
return null;
|
||||||
return document.getSimulation(row).getName();
|
return document.getSimulation(row).getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getDefaultWidth() {
|
public int getDefaultWidth() {
|
||||||
return 125;
|
return 125;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Comparator getComparator() {
|
public Comparator getComparator() {
|
||||||
return new AlphanumComparator();
|
return new AlphanumComparator();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
//// Simulation configuration
|
//// Simulation configuration
|
||||||
new Column(trans.get("simpanel.col.Configuration")) {
|
new Column(trans.get("simpanel.col.Configuration")) {
|
||||||
@Override
|
@Override
|
||||||
@ -336,144 +338,165 @@ public class SimulationPanel extends JPanel {
|
|||||||
Configuration c = document.getSimulation(row).getConfiguration();
|
Configuration c = document.getSimulation(row).getConfiguration();
|
||||||
return descriptor.format(c.getRocket(), c.getFlightConfigurationID());
|
return descriptor.format(c.getRocket(), c.getFlightConfigurationID());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getDefaultWidth() {
|
public int getDefaultWidth() {
|
||||||
return 125;
|
return 125;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
//// Launch rod velocity
|
//// Launch rod velocity
|
||||||
new ValueColumn(trans.get("simpanel.col.Velocityoffrod"), UnitGroup.UNITS_VELOCITY) {
|
new ValueColumn(trans.get("simpanel.col.Velocityoffrod"), UnitGroup.UNITS_VELOCITY) {
|
||||||
@Override
|
@Override
|
||||||
public Double valueAt(int row) {
|
public Double valueAt(int row) {
|
||||||
if (row < 0 || row >= document.getSimulationCount())
|
if (row < 0 || row >= document.getSimulationCount())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
FlightData data = document.getSimulation(row).getSimulatedData();
|
FlightData data = document.getSimulation(row).getSimulatedData();
|
||||||
if (data == null)
|
if (data == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return data.getLaunchRodVelocity();
|
return data.getLaunchRodVelocity();
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
//// Apogee
|
//// Apogee
|
||||||
new ValueColumn(trans.get("simpanel.col.Apogee"), UnitGroup.UNITS_DISTANCE) {
|
new ValueColumn(trans.get("simpanel.col.Apogee"), UnitGroup.UNITS_DISTANCE) {
|
||||||
@Override
|
@Override
|
||||||
public Double valueAt(int row) {
|
public Double valueAt(int row) {
|
||||||
if (row < 0 || row >= document.getSimulationCount())
|
if (row < 0 || row >= document.getSimulationCount())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
FlightData data = document.getSimulation(row).getSimulatedData();
|
FlightData data = document.getSimulation(row).getSimulatedData();
|
||||||
if (data == null)
|
if (data == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return data.getMaxAltitude();
|
return data.getMaxAltitude();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
//// Velocity at deployment
|
//// Velocity at deployment
|
||||||
new ValueColumn(trans.get("simpanel.col.Velocityatdeploy"), UnitGroup.UNITS_VELOCITY) {
|
new ValueColumn(trans.get("simpanel.col.Velocityatdeploy"), UnitGroup.UNITS_VELOCITY) {
|
||||||
@Override
|
@Override
|
||||||
public Double valueAt(int row) {
|
public Double valueAt(int row) {
|
||||||
if (row < 0 || row >= document.getSimulationCount())
|
if (row < 0 || row >= document.getSimulationCount())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
FlightData data = document.getSimulation(row).getSimulatedData();
|
FlightData data = document.getSimulation(row).getSimulatedData();
|
||||||
if (data == null)
|
if (data == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return data.getDeploymentVelocity();
|
return data.getDeploymentVelocity();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
//// Deployment Time from Apogee
|
||||||
|
new ValueColumn(trans.get("simpanel.col.OptimumCoastTime"),
|
||||||
|
trans.get("simpanel.col.OptimumCoastTime.ttip"),
|
||||||
|
UnitGroup.UNITS_SHORT_TIME) {
|
||||||
|
@Override
|
||||||
|
public Double valueAt(int row) {
|
||||||
|
if (row < 0 || row >= document.getSimulationCount())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
FlightData data = document.getSimulation(row).getSimulatedData();
|
||||||
|
if (data == null || data.getBranchCount() == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
double val = data.getBranch(0).getOptimumDelay();
|
||||||
|
if ( Double.isNaN(val) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
//// Maximum velocity
|
//// Maximum velocity
|
||||||
new ValueColumn(trans.get("simpanel.col.Maxvelocity"), UnitGroup.UNITS_VELOCITY) {
|
new ValueColumn(trans.get("simpanel.col.Maxvelocity"), UnitGroup.UNITS_VELOCITY) {
|
||||||
@Override
|
@Override
|
||||||
public Double valueAt(int row) {
|
public Double valueAt(int row) {
|
||||||
if (row < 0 || row >= document.getSimulationCount())
|
if (row < 0 || row >= document.getSimulationCount())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
FlightData data = document.getSimulation(row).getSimulatedData();
|
FlightData data = document.getSimulation(row).getSimulatedData();
|
||||||
if (data == null)
|
if (data == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return data.getMaxVelocity();
|
return data.getMaxVelocity();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
//// Maximum acceleration
|
//// Maximum acceleration
|
||||||
new ValueColumn(trans.get("simpanel.col.Maxacceleration"), UnitGroup.UNITS_ACCELERATION) {
|
new ValueColumn(trans.get("simpanel.col.Maxacceleration"), UnitGroup.UNITS_ACCELERATION) {
|
||||||
@Override
|
@Override
|
||||||
public Double valueAt(int row) {
|
public Double valueAt(int row) {
|
||||||
if (row < 0 || row >= document.getSimulationCount())
|
if (row < 0 || row >= document.getSimulationCount())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
FlightData data = document.getSimulation(row).getSimulatedData();
|
FlightData data = document.getSimulation(row).getSimulatedData();
|
||||||
if (data == null)
|
if (data == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return data.getMaxAcceleration();
|
return data.getMaxAcceleration();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
//// Time to apogee
|
//// Time to apogee
|
||||||
new ValueColumn(trans.get("simpanel.col.Timetoapogee"), UnitGroup.UNITS_FLIGHT_TIME) {
|
new ValueColumn(trans.get("simpanel.col.Timetoapogee"), UnitGroup.UNITS_FLIGHT_TIME) {
|
||||||
@Override
|
@Override
|
||||||
public Double valueAt(int row) {
|
public Double valueAt(int row) {
|
||||||
if (row < 0 || row >= document.getSimulationCount())
|
if (row < 0 || row >= document.getSimulationCount())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
FlightData data = document.getSimulation(row).getSimulatedData();
|
FlightData data = document.getSimulation(row).getSimulatedData();
|
||||||
if (data == null)
|
if (data == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return data.getTimeToApogee();
|
return data.getTimeToApogee();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
//// Flight time
|
//// Flight time
|
||||||
new ValueColumn(trans.get("simpanel.col.Flighttime"), UnitGroup.UNITS_FLIGHT_TIME) {
|
new ValueColumn(trans.get("simpanel.col.Flighttime"), UnitGroup.UNITS_FLIGHT_TIME) {
|
||||||
@Override
|
@Override
|
||||||
public Double valueAt(int row) {
|
public Double valueAt(int row) {
|
||||||
if (row < 0 || row >= document.getSimulationCount())
|
if (row < 0 || row >= document.getSimulationCount())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
FlightData data = document.getSimulation(row).getSimulatedData();
|
FlightData data = document.getSimulation(row).getSimulatedData();
|
||||||
if (data == null)
|
if (data == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return data.getFlightTime();
|
return data.getFlightTime();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
//// Ground hit velocity
|
//// Ground hit velocity
|
||||||
new ValueColumn(trans.get("simpanel.col.Groundhitvelocity"), UnitGroup.UNITS_VELOCITY) {
|
new ValueColumn(trans.get("simpanel.col.Groundhitvelocity"), UnitGroup.UNITS_VELOCITY) {
|
||||||
@Override
|
@Override
|
||||||
public Double valueAt(int row) {
|
public Double valueAt(int row) {
|
||||||
if (row < 0 || row >= document.getSimulationCount())
|
if (row < 0 || row >= document.getSimulationCount())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
FlightData data = document.getSimulation(row).getSimulatedData();
|
FlightData data = document.getSimulation(row).getSimulatedData();
|
||||||
if (data == null)
|
if (data == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return data.getGroundHitVelocity();
|
return data.getGroundHitVelocity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
) {
|
) {
|
||||||
@Override
|
@Override
|
||||||
public int getRowCount() {
|
public int getRowCount() {
|
||||||
return document.getSimulationCount();
|
return document.getSimulationCount();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Override processKeyBinding so that the JTable does not catch
|
// Override processKeyBinding so that the JTable does not catch
|
||||||
// key bindings used in menu accelerators
|
// key bindings used in menu accelerators
|
||||||
simulationTable = new JTable(simulationTableModel) {
|
simulationTable = new ColumnTable(simulationTableModel) {
|
||||||
@Override
|
@Override
|
||||||
protected boolean processKeyBinding(KeyStroke ks,
|
protected boolean processKeyBinding(KeyStroke ks,
|
||||||
KeyEvent e,
|
KeyEvent e,
|
||||||
@ -487,8 +510,8 @@ public class SimulationPanel extends JPanel {
|
|||||||
simulationTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
|
simulationTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
|
||||||
simulationTable.setDefaultRenderer(Object.class, new JLabelRenderer());
|
simulationTable.setDefaultRenderer(Object.class, new JLabelRenderer());
|
||||||
simulationTableModel.setColumnWidths(simulationTable.getColumnModel());
|
simulationTableModel.setColumnWidths(simulationTable.getColumnModel());
|
||||||
|
|
||||||
|
|
||||||
// Mouse listener to act on double-clicks
|
// Mouse listener to act on double-clicks
|
||||||
simulationTable.addMouseListener(new MouseAdapter() {
|
simulationTable.addMouseListener(new MouseAdapter() {
|
||||||
@Override
|
@Override
|
||||||
@ -499,15 +522,15 @@ public class SimulationPanel extends JPanel {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int selected = simulationTable.convertRowIndexToModel(selectedRow);
|
int selected = simulationTable.convertRowIndexToModel(selectedRow);
|
||||||
|
|
||||||
int column = simulationTable.columnAtPoint(e.getPoint());
|
int column = simulationTable.columnAtPoint(e.getPoint());
|
||||||
if (column == 0) {
|
if (column == 0) {
|
||||||
SimulationWarningDialog.showWarningDialog(SimulationPanel.this, document.getSimulations().get(selected));
|
SimulationWarningDialog.showWarningDialog(SimulationPanel.this, document.getSimulations().get(selected));
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
simulationTable.clearSelection();
|
simulationTable.clearSelection();
|
||||||
simulationTable.addRowSelectionInterval(selectedRow, selectedRow);
|
simulationTable.addRowSelectionInterval(selectedRow, selectedRow);
|
||||||
|
|
||||||
openDialog(document.getSimulations().get(selected));
|
openDialog(document.getSimulations().get(selected));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -515,7 +538,7 @@ public class SimulationPanel extends JPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addDocumentChangeListener(new DocumentChangeListener() {
|
document.addDocumentChangeListener(new DocumentChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void documentChanged(DocumentChangeEvent event) {
|
public void documentChanged(DocumentChangeEvent event) {
|
||||||
@ -524,10 +547,10 @@ public class SimulationPanel extends JPanel {
|
|||||||
simulationTableModel.fireTableDataChanged();
|
simulationTableModel.fireTableDataChanged();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Fire table change event when the rocket changes
|
// Fire table change event when the rocket changes
|
||||||
document.getRocket().addComponentChangeListener(new ComponentChangeListener() {
|
document.getRocket().addComponentChangeListener(new ComponentChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -535,14 +558,14 @@ public class SimulationPanel extends JPanel {
|
|||||||
fireMaintainSelection();
|
fireMaintainSelection();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
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();
|
updateButtonStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateButtonStates() {
|
private void updateButtonStates() {
|
||||||
int[] selection = simulationTable.getSelectedRows();
|
int[] selection = simulationTable.getSelectedRows();
|
||||||
if (selection.length == 0) {
|
if (selection.length == 0) {
|
||||||
@ -560,13 +583,13 @@ public class SimulationPanel extends JPanel {
|
|||||||
runButton.setEnabled(true);
|
runButton.setEnabled(true);
|
||||||
deleteButton.setEnabled(true);
|
deleteButton.setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListSelectionModel getSimulationListSelectionModel() {
|
public ListSelectionModel getSimulationListSelectionModel() {
|
||||||
return simulationTable.getSelectionModel();
|
return simulationTable.getSelectionModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openDialog(boolean plotMode, final Simulation... sims) {
|
private void openDialog(boolean plotMode, final Simulation... sims) {
|
||||||
SimulationEditDialog d = new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, sims);
|
SimulationEditDialog d = new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, sims);
|
||||||
if (plotMode) {
|
if (plotMode) {
|
||||||
@ -575,7 +598,7 @@ public class SimulationPanel extends JPanel {
|
|||||||
d.setVisible(true);
|
d.setVisible(true);
|
||||||
fireMaintainSelection();
|
fireMaintainSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openDialog(final Simulation sim) {
|
private void openDialog(final Simulation sim) {
|
||||||
boolean plotMode = false;
|
boolean plotMode = false;
|
||||||
if (sim.hasSimulationData() && (sim.getStatus() == Status.UPTODATE || sim.getStatus() == Status.EXTERNAL)) {
|
if (sim.hasSimulationData() && (sim.getStatus() == Status.UPTODATE || sim.getStatus() == Status.EXTERNAL)) {
|
||||||
@ -583,7 +606,7 @@ public class SimulationPanel extends JPanel {
|
|||||||
}
|
}
|
||||||
openDialog(plotMode, sim);
|
openDialog(plotMode, sim);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fireMaintainSelection() {
|
private void fireMaintainSelection() {
|
||||||
int[] selection = simulationTable.getSelectedRows();
|
int[] selection = simulationTable.getSelectedRows();
|
||||||
simulationTableModel.fireTableDataChanged();
|
simulationTableModel.fireTableDataChanged();
|
||||||
@ -593,24 +616,24 @@ public class SimulationPanel extends JPanel {
|
|||||||
simulationTable.addRowSelectionInterval(row, row);
|
simulationTable.addRowSelectionInterval(row, row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum SimulationTableColumns {
|
private enum SimulationTableColumns {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class JLabelRenderer extends DefaultTableCellRenderer {
|
private class JLabelRenderer extends DefaultTableCellRenderer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component getTableCellRendererComponent(JTable table,
|
public Component getTableCellRendererComponent(JTable table,
|
||||||
Object value, boolean isSelected, boolean hasFocus, int row,
|
Object value, boolean isSelected, boolean hasFocus, int row,
|
||||||
int column) {
|
int column) {
|
||||||
|
|
||||||
if (row < 0 || row >= document.getSimulationCount())
|
if (row < 0 || row >= document.getSimulationCount())
|
||||||
return super.getTableCellRendererComponent(table, value,
|
return super.getTableCellRendererComponent(table, value,
|
||||||
isSelected, hasFocus, row, column);
|
isSelected, hasFocus, row, column);
|
||||||
|
|
||||||
row = table.getRowSorter().convertRowIndexToModel(row);
|
row = table.getRowSorter().convertRowIndexToModel(row);
|
||||||
|
|
||||||
// A JLabel is self-contained and has set its own tool tip
|
// A JLabel is self-contained and has set its own tool tip
|
||||||
if (value instanceof JLabel) {
|
if (value instanceof JLabel) {
|
||||||
JLabel label = (JLabel) value;
|
JLabel label = (JLabel) value;
|
||||||
@ -619,66 +642,66 @@ public class SimulationPanel extends JPanel {
|
|||||||
else
|
else
|
||||||
label.setBackground(table.getBackground());
|
label.setBackground(table.getBackground());
|
||||||
label.setOpaque(true);
|
label.setOpaque(true);
|
||||||
|
|
||||||
label.setToolTipText(getSimulationToolTip(document.getSimulation(row)));
|
label.setToolTipText(getSimulationToolTip(document.getSimulation(row)));
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
Component component = super.getTableCellRendererComponent(table, value,
|
Component component = super.getTableCellRendererComponent(table, value,
|
||||||
isSelected, hasFocus, row, column);
|
isSelected, hasFocus, row, column);
|
||||||
|
|
||||||
if (component instanceof JComponent) {
|
if (component instanceof JComponent) {
|
||||||
((JComponent) component).setToolTipText(getSimulationToolTip(
|
((JComponent) component).setToolTipText(getSimulationToolTip(
|
||||||
document.getSimulation(row)));
|
document.getSimulation(row)));
|
||||||
}
|
}
|
||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getSimulationToolTip(Simulation sim) {
|
private String getSimulationToolTip(Simulation sim) {
|
||||||
String tip;
|
String tip;
|
||||||
FlightData data = sim.getSimulatedData();
|
FlightData data = sim.getSimulatedData();
|
||||||
|
|
||||||
tip = "<html><b>" + sim.getName() + "</b><br>";
|
tip = "<html><b>" + sim.getName() + "</b><br>";
|
||||||
switch (sim.getStatus()) {
|
switch (sim.getStatus()) {
|
||||||
case UPTODATE:
|
case UPTODATE:
|
||||||
tip += trans.get("simpanel.ttip.uptodate") + "<br>";
|
tip += trans.get("simpanel.ttip.uptodate") + "<br>";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LOADED:
|
case LOADED:
|
||||||
tip += trans.get("simpanel.ttip.loaded") + "<br>";
|
tip += trans.get("simpanel.ttip.loaded") + "<br>";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OUTDATED:
|
case OUTDATED:
|
||||||
tip += trans.get("simpanel.ttip.outdated") + "<br>";
|
tip += trans.get("simpanel.ttip.outdated") + "<br>";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXTERNAL:
|
case EXTERNAL:
|
||||||
tip += trans.get("simpanel.ttip.external") + "<br>";
|
tip += trans.get("simpanel.ttip.external") + "<br>";
|
||||||
return tip;
|
return tip;
|
||||||
|
|
||||||
case NOT_SIMULATED:
|
case NOT_SIMULATED:
|
||||||
tip += trans.get("simpanel.ttip.notSimulated");
|
tip += trans.get("simpanel.ttip.notSimulated");
|
||||||
return tip;
|
return tip;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
tip += trans.get("simpanel.ttip.noData");
|
tip += trans.get("simpanel.ttip.noData");
|
||||||
return tip;
|
return tip;
|
||||||
}
|
}
|
||||||
WarningSet warnings = data.getWarningSet();
|
WarningSet warnings = data.getWarningSet();
|
||||||
|
|
||||||
if (warnings.isEmpty()) {
|
if (warnings.isEmpty()) {
|
||||||
tip += trans.get("simpanel.ttip.noWarnings");
|
tip += trans.get("simpanel.ttip.noWarnings");
|
||||||
return tip;
|
return tip;
|
||||||
}
|
}
|
||||||
|
|
||||||
tip += trans.get("simpanel.ttip.warnings");
|
tip += trans.get("simpanel.ttip.warnings");
|
||||||
for (Warning w : warnings) {
|
for (Warning w : warnings) {
|
||||||
tip += "<br>" + w.toString();
|
tip += "<br>" + w.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
return tip;
|
return tip;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,6 +125,7 @@ public class DesignReport {
|
|||||||
private static final String SIZE = "Size";
|
private static final String SIZE = "Size";
|
||||||
private static final String ALTITUDE = "Altitude";
|
private static final String ALTITUDE = "Altitude";
|
||||||
private static final String FLIGHT_TIME = "Flight Time";
|
private static final String FLIGHT_TIME = "Flight Time";
|
||||||
|
private static final String OPTIMUM_DELAY = "Optimum Delay";
|
||||||
private static final String TIME_TO_APOGEE = "Time to Apogee";
|
private static final String TIME_TO_APOGEE = "Time to Apogee";
|
||||||
private static final String VELOCITY_OFF_PAD = "Velocity off Pad";
|
private static final String VELOCITY_OFF_PAD = "Velocity off Pad";
|
||||||
private static final String MAX_VELOCITY = "Max Velocity";
|
private static final String MAX_VELOCITY = "Max Velocity";
|
||||||
@ -468,6 +469,9 @@ public class DesignReport {
|
|||||||
labelTable.addCell(ITextHelper.createCell(TIME_TO_APOGEE, 2, 2));
|
labelTable.addCell(ITextHelper.createCell(TIME_TO_APOGEE, 2, 2));
|
||||||
labelTable.addCell(ITextHelper.createCell(flightTimeUnit.toStringUnit(flight.getTimeToApogee()), 2, 2));
|
labelTable.addCell(ITextHelper.createCell(flightTimeUnit.toStringUnit(flight.getTimeToApogee()), 2, 2));
|
||||||
|
|
||||||
|
labelTable.addCell(ITextHelper.createCell(OPTIMUM_DELAY, 2, 2));
|
||||||
|
labelTable.addCell(ITextHelper.createCell(flightTimeUnit.toStringUnit(flight.getBranch(0).getOptimumDelay()), 2, 2));
|
||||||
|
|
||||||
labelTable.addCell(ITextHelper.createCell(VELOCITY_OFF_PAD, 2, 2));
|
labelTable.addCell(ITextHelper.createCell(VELOCITY_OFF_PAD, 2, 2));
|
||||||
labelTable.addCell(ITextHelper.createCell(velocityUnit.toStringUnit(flight.getLaunchRodVelocity()), 2, 2));
|
labelTable.addCell(ITextHelper.createCell(velocityUnit.toStringUnit(flight.getLaunchRodVelocity()), 2, 2));
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user