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.Velocityoffrod = Velocity off rod
|
||||
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.Maxvelocity = Max. velocity
|
||||
simpanel.col.Maxacceleration = Max. acceleration
|
||||
|
@ -536,6 +536,7 @@ public class OpenRocketSaver extends RocketSaver {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("<databranch name=\"");
|
||||
sb.append(TextUtil.escapeXML(branch.getBranchName()));
|
||||
sb.append("\" ");
|
||||
|
||||
// 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++) {
|
||||
if (i > 0)
|
||||
sb.append(",");
|
||||
@ -590,8 +603,6 @@ public class OpenRocketSaver extends RocketSaver {
|
||||
writeln("</databranch>");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* TODO: LOW: This is largely duplicated from above! */
|
||||
private int countFlightDataBranchPoints(FlightDataBranch branch, double timeSkip) {
|
||||
int count = 0;
|
||||
|
@ -42,6 +42,22 @@ class FlightDataBranchHandler extends AbstractElementHandler {
|
||||
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
|
||||
// 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.
|
||||
|
@ -48,6 +48,23 @@ class FlightDataHandler extends AbstractElementHandler {
|
||||
dataHandler = new FlightDataBranchHandler(attributes.get("name"),
|
||||
attributes.get("types"),
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ import net.sf.openrocket.simulation.exception.MotorIgnitionException;
|
||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||
import net.sf.openrocket.simulation.exception.SimulationLaunchException;
|
||||
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.unit.UnitGroup;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
@ -120,8 +121,6 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
Coordinate originVelocity = status.getRocketVelocity();
|
||||
|
||||
try {
|
||||
double maxAlt = Double.NEGATIVE_INFINITY;
|
||||
|
||||
// Start the simulation
|
||||
while (handleEvents()) {
|
||||
|
||||
@ -149,8 +148,8 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
status.getConfiguration().getRocket(),
|
||||
new Pair<Double, Double>(oldAlt, status.getRocketPosition().z)));
|
||||
|
||||
if (status.getRocketPosition().z > maxAlt) {
|
||||
maxAlt = status.getRocketPosition().z;
|
||||
if (status.getRocketPosition().z > status.getMaxAlt()) {
|
||||
status.setMaxAlt(status.getRocketPosition().z);
|
||||
}
|
||||
|
||||
|
||||
@ -189,7 +188,8 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
|
||||
|
||||
// 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(),
|
||||
status.getConfiguration().getRocket()));
|
||||
}
|
||||
@ -464,6 +464,11 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
// Mark apogee as reached
|
||||
status.setApogeeReached(true);
|
||||
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;
|
||||
|
||||
case RECOVERY_DEVICE_DEPLOYMENT:
|
||||
@ -501,6 +506,14 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
status.setLiftoff(true);
|
||||
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.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,6 +36,14 @@ public class FlightDataBranch implements Monitorable {
|
||||
private final Map<FlightDataType, Double> maxValues = 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>();
|
||||
|
||||
@ -73,7 +81,7 @@ public class FlightDataBranch implements Monitorable {
|
||||
*/
|
||||
public FlightDataBranch() {
|
||||
branchName = "Empty branch";
|
||||
for (FlightDataType type : FlightDataType.ALL_TYPES){
|
||||
for (FlightDataType type : FlightDataType.ALL_TYPES) {
|
||||
this.setValue(type, Double.NaN);
|
||||
}
|
||||
this.immute();
|
||||
@ -118,7 +126,7 @@ public class FlightDataBranch implements Monitorable {
|
||||
maxValues.put(type, value);
|
||||
}
|
||||
|
||||
if (list.size() > 0){
|
||||
if (list.size() > 0) {
|
||||
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.
|
||||
*
|
||||
@ -241,6 +293,34 @@ public class FlightDataBranch implements Monitorable {
|
||||
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
|
||||
|
@ -268,7 +268,7 @@ public class SimulationConditions implements Monitorable, Cloneable {
|
||||
this.simulation = sim;
|
||||
}
|
||||
|
||||
public Simulation getSimulation(){
|
||||
public Simulation getSimulation() {
|
||||
return this.simulation;
|
||||
}
|
||||
|
||||
@ -291,7 +291,12 @@ public class SimulationConditions implements Monitorable, Cloneable {
|
||||
public SimulationConditions clone() {
|
||||
try {
|
||||
// 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) {
|
||||
throw new BugException(e);
|
||||
}
|
||||
|
@ -27,10 +27,6 @@ import net.sf.openrocket.util.WorldCoordinate;
|
||||
*/
|
||||
public class SimulationStatus implements Monitorable {
|
||||
|
||||
/*
|
||||
* NOTE! All fields must be added to copyFrom() method!!
|
||||
*/
|
||||
|
||||
private SimulationConditions simulationConditions;
|
||||
private Configuration configuration;
|
||||
private MotorInstanceConfiguration motorConfiguration;
|
||||
@ -83,13 +79,15 @@ public class SimulationStatus implements Monitorable {
|
||||
/** Available for special purposes by the listeners. */
|
||||
private final Map<String, Object> extraData = new HashMap<String, Object>();
|
||||
|
||||
double maxAlt = Double.NEGATIVE_INFINITY;
|
||||
double maxAltTime = 0;
|
||||
|
||||
private int modID = 0;
|
||||
private int modIDadd = 0;
|
||||
|
||||
public SimulationStatus( Configuration configuration,
|
||||
public SimulationStatus(Configuration configuration,
|
||||
MotorInstanceConfiguration motorConfiguration,
|
||||
SimulationConditions simulationConditions ) {
|
||||
SimulationConditions simulationConditions) {
|
||||
|
||||
this.simulationConditions = simulationConditions;
|
||||
this.configuration = configuration;
|
||||
@ -163,7 +161,7 @@ public class SimulationStatus implements Monitorable {
|
||||
*
|
||||
* @param orig the object from which to copy
|
||||
*/
|
||||
public SimulationStatus( SimulationStatus orig ) {
|
||||
public SimulationStatus(SimulationStatus orig) {
|
||||
this.simulationConditions = orig.simulationConditions.clone();
|
||||
this.configuration = orig.configuration.clone();
|
||||
this.motorConfiguration = orig.motorConfiguration.clone();
|
||||
@ -292,7 +290,7 @@ public class SimulationStatus implements Monitorable {
|
||||
}
|
||||
|
||||
|
||||
public boolean addBurntOutMotor( MotorId motor ) {
|
||||
public boolean addBurntOutMotor(MotorId motor) {
|
||||
return motorBurntOut.add(motor);
|
||||
}
|
||||
|
||||
@ -384,7 +382,7 @@ public class SimulationStatus implements Monitorable {
|
||||
}
|
||||
|
||||
|
||||
public void setTumbling( boolean tumbling ) {
|
||||
public void setTumbling(boolean tumbling) {
|
||||
this.tumbling = tumbling;
|
||||
this.modID++;
|
||||
}
|
||||
@ -393,6 +391,24 @@ public class SimulationStatus implements Monitorable {
|
||||
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() {
|
||||
return deployedRecoveryDevices;
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ public class AbstractSimulationListener implements SimulationListener, Simulatio
|
||||
* Return an array of any flight data types this listener creates.
|
||||
*/
|
||||
@Override
|
||||
public FlightDataType[] getFlightDataTypes(){
|
||||
public FlightDataType[] getFlightDataTypes() {
|
||||
return new FlightDataType[] {};
|
||||
}
|
||||
|
||||
@ -183,4 +183,9 @@ public class AbstractSimulationListener implements SimulationListener, Simulatio
|
||||
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.exception.SimulationException;
|
||||
|
||||
|
||||
|
||||
public interface SimulationListener {
|
||||
/**
|
||||
* Listen to simulation events and possibly take action.
|
||||
*
|
||||
* 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
|
||||
@ -83,5 +87,5 @@ public interface SimulationListener {
|
||||
*/
|
||||
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 {
|
||||
private final String name;
|
||||
private final String toolTip;
|
||||
|
||||
/**
|
||||
* Create a new column with specified name. Additionally, the {@link #getValueAt(int)}
|
||||
@ -15,6 +16,17 @@ public abstract class Column {
|
||||
*/
|
||||
public Column(String 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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,4 +100,8 @@ public abstract class Column {
|
||||
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;
|
||||
}
|
||||
|
||||
public ValueColumn( String name, String toolTip, UnitGroup unit ) {
|
||||
super( name, toolTip );
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int 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.WarningSet;
|
||||
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.DoubleModel;
|
||||
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.setSelectionBackground(Color.LIGHT_GRAY);
|
||||
table.setSelectionForeground(Color.BLACK);
|
||||
|
@ -40,6 +40,7 @@ import javax.swing.table.TableRowSorter;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
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.components.SelectableLabel;
|
||||
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.setSelectionBackground(Color.LIGHT_GRAY);
|
||||
table.setSelectionForeground(Color.BLACK);
|
||||
|
@ -23,6 +23,7 @@ import net.miginfocom.swing.MigLayout;
|
||||
import net.sf.openrocket.database.Database;
|
||||
import net.sf.openrocket.database.Databases;
|
||||
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.components.StyledLabel;
|
||||
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());
|
||||
table.setAutoCreateRowSorter(true);
|
||||
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.formatting.RocketDescriptor;
|
||||
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.ColumnTableRowSorter;
|
||||
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.Configuration;
|
||||
import net.sf.openrocket.simulation.FlightData;
|
||||
import net.sf.openrocket.simulation.FlightEvent;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.startup.Preferences;
|
||||
import net.sf.openrocket.unit.UnitGroup;
|
||||
@ -184,12 +186,12 @@ public class SimulationPanel extends JPanel {
|
||||
|
||||
int ret = JOptionPane.showConfirmDialog(SimulationPanel.this,
|
||||
new Object[] {
|
||||
//// Delete the selected simulations?
|
||||
trans.get("simpanel.dlg.lbl.DeleteSim1"),
|
||||
//// <html><i>This operation cannot be undone.</i>
|
||||
trans.get("simpanel.dlg.lbl.DeleteSim2"),
|
||||
"",
|
||||
panel },
|
||||
//// Delete the selected simulations?
|
||||
trans.get("simpanel.dlg.lbl.DeleteSim1"),
|
||||
//// <html><i>This operation cannot be undone.</i>
|
||||
trans.get("simpanel.dlg.lbl.DeleteSim2"),
|
||||
"",
|
||||
panel },
|
||||
//// Delete simulations
|
||||
trans.get("simpanel.dlg.lbl.DeleteSim3"),
|
||||
JOptionPane.OK_CANCEL_OPTION,
|
||||
@ -389,6 +391,27 @@ public class SimulationPanel extends JPanel {
|
||||
}
|
||||
},
|
||||
|
||||
//// 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
|
||||
new ValueColumn(trans.get("simpanel.col.Maxvelocity"), UnitGroup.UNITS_VELOCITY) {
|
||||
@Override
|
||||
@ -465,15 +488,15 @@ public class SimulationPanel extends JPanel {
|
||||
}
|
||||
|
||||
) {
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return document.getSimulationCount();
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return document.getSimulationCount();
|
||||
}
|
||||
};
|
||||
|
||||
// Override processKeyBinding so that the JTable does not catch
|
||||
// key bindings used in menu accelerators
|
||||
simulationTable = new JTable(simulationTableModel) {
|
||||
simulationTable = new ColumnTable(simulationTableModel) {
|
||||
@Override
|
||||
protected boolean processKeyBinding(KeyStroke ks,
|
||||
KeyEvent e,
|
||||
|
@ -125,6 +125,7 @@ public class DesignReport {
|
||||
private static final String SIZE = "Size";
|
||||
private static final String ALTITUDE = "Altitude";
|
||||
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 VELOCITY_OFF_PAD = "Velocity off Pad";
|
||||
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(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(velocityUnit.toStringUnit(flight.getLaunchRodVelocity()), 2, 2));
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user