Add simulation aborts to .ork file load/save

This commit is contained in:
JoePfeiffer 2024-01-03 07:09:24 -07:00
parent c5f1f011ef
commit f9a8f59247
8 changed files with 71 additions and 43 deletions

View File

@ -634,7 +634,7 @@ simpanel.ttip.notSimulated = <i>Not simulated yet</i><br>Click <i><b>Run simulat
simpanel.ttip.noData = No simulation data available. simpanel.ttip.noData = No simulation data available.
simpanel.ttip.noWarnings = <font color=\"gray\">No warnings.</font> simpanel.ttip.noWarnings = <font color=\"gray\">No warnings.</font>
simpanel.ttip.warnings = <font color=\"red\">Warnings:</font> simpanel.ttip.warnings = <font color=\"red\">Warnings:</font>
simpanel.ttip.simAbort = <font color=\"red\"><i><b>Simulation Abort</b></i></font><br /> simpanel.ttip.simAbort = Simulation Abort
simpanel.msg.invalidCopySelection = Invalid copy selection simpanel.msg.invalidCopySelection = Invalid copy selection
! SimulationRunDialog ! SimulationRunDialog

View File

@ -9,6 +9,7 @@ import java.util.*;
import net.sf.openrocket.file.openrocket.savers.PhotoStudioSaver; import net.sf.openrocket.file.openrocket.savers.PhotoStudioSaver;
import net.sf.openrocket.logging.ErrorSet; import net.sf.openrocket.logging.ErrorSet;
import net.sf.openrocket.logging.SimulationAbort;
import net.sf.openrocket.logging.WarningSet; import net.sf.openrocket.logging.WarningSet;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -539,6 +540,11 @@ public class OpenRocketSaver extends RocketSaver {
if (event.getSource() != null) { if (event.getSource() != null) {
eventStr += "\" source=\"" + TextUtil.escapeXML(event.getSource().getID()); eventStr += "\" source=\"" + TextUtil.escapeXML(event.getSource().getID());
} }
if (event.getType() == FlightEvent.Type.SIM_ABORT) {
eventStr += "\" cause=\"" + enumToXMLName(((SimulationAbort)(event.getData())).getCause());
}
eventStr += "\"/>"; eventStr += "\"/>";
writeln(eventStr); writeln(eventStr);
} }

View File

@ -2,6 +2,8 @@ package net.sf.openrocket.file.openrocket.importt;
import java.util.HashMap; import java.util.HashMap;
import net.sf.openrocket.logging.SimulationAbort;
import net.sf.openrocket.logging.SimulationAbort.Cause;
import net.sf.openrocket.logging.WarningSet; import net.sf.openrocket.logging.WarningSet;
import net.sf.openrocket.file.DocumentLoadingContext; import net.sf.openrocket.file.DocumentLoadingContext;
import net.sf.openrocket.file.simplesax.AbstractElementHandler; import net.sf.openrocket.file.simplesax.AbstractElementHandler;
@ -128,8 +130,10 @@ class FlightDataBranchHandler extends AbstractElementHandler {
if (element.equals("event")) { if (element.equals("event")) {
double time; double time;
FlightEvent.Type type; FlightEvent.Type type;
String sourceID; SimulationAbort abort = null;
SimulationAbort.Cause cause = null;
RocketComponent source = null; RocketComponent source = null;
String sourceID;
try { try {
time = DocumentConfig.stringToDouble(attributes.get("time")); time = DocumentConfig.stringToDouble(attributes.get("time"));
@ -150,8 +154,14 @@ class FlightDataBranchHandler extends AbstractElementHandler {
if (sourceID != null) { if (sourceID != null) {
source = rocket.findComponent(sourceID); source = rocket.findComponent(sourceID);
} }
// For aborts, get the cause
cause = (Cause) DocumentConfig.findEnum(attributes.get("cause"), SimulationAbort.Cause.class);
if (cause != null) {
abort = new SimulationAbort(cause);
}
branch.addEvent(new FlightEvent(type, time, source)); branch.addEvent(new FlightEvent(type, time, source, abort));
return; return;
} }
@ -187,4 +197,4 @@ class FlightDataBranchHandler extends AbstractElementHandler {
branch.setValue(types[i], values[i]); branch.setValue(types[i], values[i]);
} }
} }
} }

View File

@ -10,15 +10,9 @@ public class SimulationAbort extends Message {
private static final Translator trans = Application.getTranslator(); private static final Translator trans = Application.getTranslator();
private final String description;
SimulationAbort(String _description) {
description = _description;
}
@Override @Override
public String getMessageDescription() { public String getMessageDescription() {
return description; return cause.toString();
} }
@Override @Override
@ -29,29 +23,48 @@ public class SimulationAbort extends Message {
/** /**
* Possible causes of sim aborts * Possible causes of sim aborts
*/ */
public enum Cause {
// No motors are defined in the sim configuration
NOMOTORSDEFINED(trans.get("SimulationAbort.noMotorsDefined")),
// No motors are defined in the sim configuration // Motors are defined, but none are configured to fire at liftoff
public static final SimulationAbort NOMOTORSDEFINED = new SimulationAbort(trans.get("SimulationAbort.noMotorsDefined")); NOCONFIGUREDIGNITION(trans.get("SimulationAbort.noConfiguredIgnition")),
// Motors are defined, but none are configured to fire at liftoff
public static final SimulationAbort NOCONFIGUREDIGNITION = new SimulationAbort(trans.get("SimulationAbort.noConfiguredIgnition"));
// No motors fired (can this really happen without getting a NoMotorsDefined?) // No motors fired (can this really happen without getting a NoMotorsDefined?)
public static final SimulationAbort NOMOTORSFIRED = new SimulationAbort(trans.get("SimulationAbort.noIgnition")); NOMOTORSFIRED(trans.get("SimulationAbort.noIgnition")),
// Motors ignited, but rocket did not lift off // Motors ignited, but rocket did not lift off
public static final SimulationAbort NOLIFTOFF = new SimulationAbort(trans.get("SimulationAbort.noLiftOff")); NOLIFTOFF(trans.get("SimulationAbort.noLiftOff")),
// It is impossible to calculate the active components' center of pressure // It is impossible to calculate the active components' center of pressure
public static final SimulationAbort NOCP = new SimulationAbort(trans.get("SimulationAbort.noCP")); NOCP(trans.get("SimulationAbort.noCP")),
// The currently active components have a total length of 0 // The currently active components have a total length of 0
public static final SimulationAbort ACTIVELENGTHZERO = new SimulationAbort(trans.get("SimulationAbort.activeLengthZero")); ACTIVELENGTHZERO(trans.get("SimulationAbort.activeLengthZero")),
// The currently active components have a total mass of 0 // The currently active components have a total mass of 0
public static final SimulationAbort ACTIVEMASSZERO = new SimulationAbort(trans.get("SimulationAbort.activeMassZero")); ACTIVEMASSZERO(trans.get("SimulationAbort.activeMassZero"));
private final String name;
private Cause(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
private final Cause cause;
public SimulationAbort(Cause cause) {
this.cause = cause;
}
public Cause getCause() {
return cause;
}
} }

View File

@ -91,7 +91,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
// No motors in configuration // No motors in configuration
if (!simulationConfig.hasMotors() ) { if (!simulationConfig.hasMotors() ) {
currentStatus.abortSimulation(SimulationAbort.NOMOTORSDEFINED); currentStatus.abortSimulation(SimulationAbort.Cause.NOMOTORSDEFINED);
} }
// Problems that let us simulate, but result is likely bad // Problems that let us simulate, but result is likely bad
@ -442,7 +442,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
case BURNOUT: { case BURNOUT: {
// If motor burnout occurs without lift-off, abort // If motor burnout occurs without lift-off, abort
if (!currentStatus.isLiftoff()) { if (!currentStatus.isLiftoff()) {
currentStatus.abortSimulation(SimulationAbort.NOLIFTOFF); currentStatus.abortSimulation(SimulationAbort.Cause.NOLIFTOFF);
} }
// Add ejection charge event // Add ejection charge event
@ -636,7 +636,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
// If no motor has ignited, abort // If no motor has ignited, abort
if (!currentStatus.isMotorIgnited()) { if (!currentStatus.isMotorIgnited()) {
// TODO MEDIUM: display this as a warning to the user (e.g. highlight the cell in the simulation panel in red and a hover: 'make sure the motor ignition is correct' or something) // TODO MEDIUM: display this as a warning to the user (e.g. highlight the cell in the simulation panel in red and a hover: 'make sure the motor ignition is correct' or something)
currentStatus.abortSimulation(SimulationAbort.NOMOTORSFIRED); currentStatus.abortSimulation(SimulationAbort.Cause.NOMOTORSFIRED);
} }
return ret; return ret;
@ -676,7 +676,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
// Active stages have total length of 0. // Active stages have total length of 0.
if (currentStatus.getConfiguration().getLengthAerodynamic() < MathUtil.EPSILON) { if (currentStatus.getConfiguration().getLengthAerodynamic() < MathUtil.EPSILON) {
currentStatus.abortSimulation(SimulationAbort.ACTIVELENGTHZERO); currentStatus.abortSimulation(SimulationAbort.Cause.ACTIVELENGTHZERO);
} }
// Can't calculate stability // Can't calculate stability
@ -684,7 +684,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
.getCP(currentStatus.getConfiguration(), .getCP(currentStatus.getConfiguration(),
new FlightConditions(currentStatus.getConfiguration()), new FlightConditions(currentStatus.getConfiguration()),
new WarningSet()).weight < MathUtil.EPSILON) { new WarningSet()).weight < MathUtil.EPSILON) {
currentStatus.abortSimulation(SimulationAbort.NOCP); currentStatus.abortSimulation(SimulationAbort.Cause.NOCP);
} }
} }

View File

@ -147,10 +147,6 @@ public class FlightEvent implements Comparable<FlightEvent> {
return data; return data;
} }
/** /**
* Compares this event to another event depending on the event time. Secondary * Compares this event to another event depending on the event time. Secondary
* sorting is performed on stages; lower (numerically higher) stage first. Tertiary * sorting is performed on stages; lower (numerically higher) stage first. Tertiary

View File

@ -567,8 +567,8 @@ public class SimulationStatus implements Monitorable {
/** /**
* Abort the current simulation branch * Abort the current simulation branch
*/ */
public void abortSimulation(SimulationAbort cause) throws SimulationException { public void abortSimulation(SimulationAbort.Cause cause) throws SimulationException {
FlightEvent abortEvent = new FlightEvent(FlightEvent.Type.SIM_ABORT, getSimulationTime(), null, cause); FlightEvent abortEvent = new FlightEvent(FlightEvent.Type.SIM_ABORT, getSimulationTime(), null, new SimulationAbort(cause));
addEvent(abortEvent); addEvent(abortEvent);
} }

View File

@ -52,6 +52,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import net.miginfocom.swing.MigLayout; import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.logging.SimulationAbort;
import net.sf.openrocket.logging.Warning; import net.sf.openrocket.logging.Warning;
import net.sf.openrocket.logging.WarningSet; import net.sf.openrocket.logging.WarningSet;
import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.document.OpenRocketDocument;
@ -782,8 +783,10 @@ public class SimulationPanel extends JPanel {
} }
for (int b = 0; b < data.getBranchCount(); b++) { for (int b = 0; b < data.getBranchCount(); b++) {
if (data.getBranch(b).getFirstEvent(FlightEvent.Type.SIM_ABORT) != null) { FlightEvent abortEvent = data.getBranch(b).getFirstEvent(FlightEvent.Type.SIM_ABORT);
tip += trans.get("simpanel.ttip.simAbort"); if ( abortEvent != null) {
tip += "<font color=\"red\"><i><b>" + trans.get("simpanel.ttip.simAbort") + ":</b></i> " +
((SimulationAbort)(abortEvent.getData())).toString() + "</font><br />";
} }
} }