Merge branch 'tumble-recovery' into kruland-integration
Conflicts: core/resources/datafiles/examples/Three-stage rocket.ork core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java Ignored changes to Three-stage rocket.ork since that will need to be reproduced after the cool 3d view enhancements to the example. The BasicEventSimulationEngine conflicts were trivial and manually resolved.
This commit is contained in:
commit
3eb96ee04d
@ -1371,6 +1371,7 @@ FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT = Recovery device deployment
|
|||||||
FlightEvent.Type.GROUND_HIT = Ground hit
|
FlightEvent.Type.GROUND_HIT = Ground hit
|
||||||
FlightEvent.Type.SIMULATION_END = Simulation end
|
FlightEvent.Type.SIMULATION_END = Simulation end
|
||||||
FlightEvent.Type.ALTITUDE = Altitude change
|
FlightEvent.Type.ALTITUDE = Altitude change
|
||||||
|
FlightEvent.Type.TUMBLE = Tumbling
|
||||||
|
|
||||||
! ThrustCurveMotorColumns
|
! ThrustCurveMotorColumns
|
||||||
TCurveMotorCol.MANUFACTURER = Manufacturer
|
TCurveMotorCol.MANUFACTURER = Manufacturer
|
||||||
|
@ -36,6 +36,7 @@ public class PlotConfiguration implements Cloneable {
|
|||||||
config.setEvent(FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT, true);
|
config.setEvent(FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT, true);
|
||||||
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
||||||
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
||||||
|
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
||||||
configs.add(config);
|
configs.add(config);
|
||||||
|
|
||||||
//// Total motion vs. time
|
//// Total motion vs. time
|
||||||
@ -49,6 +50,7 @@ public class PlotConfiguration implements Cloneable {
|
|||||||
config.setEvent(FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT, true);
|
config.setEvent(FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT, true);
|
||||||
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
||||||
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
||||||
|
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
||||||
configs.add(config);
|
configs.add(config);
|
||||||
|
|
||||||
//// Flight side profile
|
//// Flight side profile
|
||||||
@ -60,6 +62,7 @@ public class PlotConfiguration implements Cloneable {
|
|||||||
config.setEvent(FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT, true);
|
config.setEvent(FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT, true);
|
||||||
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
||||||
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
||||||
|
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
||||||
configs.add(config);
|
configs.add(config);
|
||||||
|
|
||||||
//// Stability vs. time
|
//// Stability vs. time
|
||||||
@ -73,6 +76,7 @@ public class PlotConfiguration implements Cloneable {
|
|||||||
config.setEvent(FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT, true);
|
config.setEvent(FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT, true);
|
||||||
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
||||||
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
||||||
|
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
||||||
configs.add(config);
|
configs.add(config);
|
||||||
|
|
||||||
//// Drag coefficients vs. Mach number
|
//// Drag coefficients vs. Mach number
|
||||||
@ -97,6 +101,7 @@ public class PlotConfiguration implements Cloneable {
|
|||||||
config.setEvent(FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT, true);
|
config.setEvent(FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT, true);
|
||||||
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
||||||
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
||||||
|
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
||||||
configs.add(config);
|
configs.add(config);
|
||||||
|
|
||||||
//// Angle of attack and orientation vs. time
|
//// Angle of attack and orientation vs. time
|
||||||
@ -110,6 +115,7 @@ public class PlotConfiguration implements Cloneable {
|
|||||||
config.setEvent(FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT, true);
|
config.setEvent(FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT, true);
|
||||||
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
||||||
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
||||||
|
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
||||||
configs.add(config);
|
configs.add(config);
|
||||||
|
|
||||||
//// Simulation time step and computation time
|
//// Simulation time step and computation time
|
||||||
@ -122,6 +128,7 @@ public class PlotConfiguration implements Cloneable {
|
|||||||
config.setEvent(FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT, true);
|
config.setEvent(FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT, true);
|
||||||
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true);
|
||||||
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
config.setEvent(FlightEvent.Type.GROUND_HIT, true);
|
||||||
|
config.setEvent(FlightEvent.Type.TUMBLE, true);
|
||||||
configs.add(config);
|
configs.add(config);
|
||||||
|
|
||||||
DEFAULT_CONFIGURATIONS = configs.toArray(new PlotConfiguration[0]);
|
DEFAULT_CONFIGURATIONS = configs.toArray(new PlotConfiguration[0]);
|
||||||
|
@ -37,6 +37,11 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
// TODO: MEDIUM: Allow selecting steppers
|
// TODO: MEDIUM: Allow selecting steppers
|
||||||
private SimulationStepper flightStepper = new RK4SimulationStepper();
|
private SimulationStepper flightStepper = new RK4SimulationStepper();
|
||||||
private SimulationStepper landingStepper = new BasicLandingStepper();
|
private SimulationStepper landingStepper = new BasicLandingStepper();
|
||||||
|
private SimulationStepper tumbleStepper = new BasicTumbleStepper();
|
||||||
|
|
||||||
|
// Constant holding 30 degress in radians. This is the AOA condition
|
||||||
|
// necessary to transistion to tumbling.
|
||||||
|
private final static double AOA_TUMBLE_CONDITION = Math.PI / 3.0;
|
||||||
|
|
||||||
private SimulationStepper currentStepper;
|
private SimulationStepper currentStepper;
|
||||||
|
|
||||||
@ -192,6 +197,24 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for Tumbling
|
||||||
|
// Conditions for transision are:
|
||||||
|
// apogee reached
|
||||||
|
// and is not already tumbling
|
||||||
|
// and not stable (cg > cp)
|
||||||
|
// and aoa > 30
|
||||||
|
|
||||||
|
if (status.isApogeeReached() && !status.isTumbling()) {
|
||||||
|
double cp = status.getFlightData().getLast(FlightDataType.TYPE_CP_LOCATION);
|
||||||
|
double cg = status.getFlightData().getLast(FlightDataType.TYPE_CG_LOCATION);
|
||||||
|
double aoa = status.getFlightData().getLast(FlightDataType.TYPE_AOA);
|
||||||
|
if (cg > cp && aoa > AOA_TUMBLE_CONDITION) {
|
||||||
|
addEvent(new FlightEvent(FlightEvent.Type.TUMBLE, status.getSimulationTime()));
|
||||||
|
status.setTumbling(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (SimulationException e) {
|
} catch (SimulationException e) {
|
||||||
@ -479,6 +502,12 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
|
|
||||||
case ALTITUDE:
|
case ALTITUDE:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TUMBLE:
|
||||||
|
this.currentStepper = this.tumbleStepper;
|
||||||
|
this.status = currentStepper.initialize(status);
|
||||||
|
status.getFlightData().addEvent(event);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
77
core/src/net/sf/openrocket/simulation/BasicTumbleStatus.java
Normal file
77
core/src/net/sf/openrocket/simulation/BasicTumbleStatus.java
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package net.sf.openrocket.simulation;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import net.sf.openrocket.aerodynamics.AerodynamicForces;
|
||||||
|
import net.sf.openrocket.aerodynamics.FlightConditions;
|
||||||
|
import net.sf.openrocket.aerodynamics.WarningSet;
|
||||||
|
import net.sf.openrocket.motor.MotorInstanceConfiguration;
|
||||||
|
import net.sf.openrocket.rocketcomponent.Configuration;
|
||||||
|
import net.sf.openrocket.rocketcomponent.FinSet;
|
||||||
|
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||||
|
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||||
|
import net.sf.openrocket.rocketcomponent.SymmetricComponent;
|
||||||
|
|
||||||
|
public class BasicTumbleStatus extends SimulationStatus {
|
||||||
|
|
||||||
|
// Magic constants from techdoc.pdf
|
||||||
|
private final static double cDFin = 1.42;
|
||||||
|
private final static double cDBt = 0.56;
|
||||||
|
// Fin efficiency. Index is number of fins. The 0th entry is arbitrary and used to
|
||||||
|
// offset the indexes so finEff[1] is the coefficient for one fin from the table in techdoc.pdf
|
||||||
|
private final static double[] finEff = { 0.0, 0.5, 1.0, 1.41, 1.81, 1.73, 1.90, 1.85 };
|
||||||
|
|
||||||
|
private double drag;
|
||||||
|
|
||||||
|
public BasicTumbleStatus(Configuration configuration,
|
||||||
|
MotorInstanceConfiguration motorConfiguration,
|
||||||
|
SimulationConditions simulationConditions) {
|
||||||
|
super(configuration, motorConfiguration, simulationConditions);
|
||||||
|
computeTumbleDrag();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasicTumbleStatus(SimulationStatus orig) {
|
||||||
|
super(orig);
|
||||||
|
if ( orig instanceof BasicTumbleStatus ) {
|
||||||
|
this.drag = ((BasicTumbleStatus) orig).drag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getTumbleDrag( ) {
|
||||||
|
return drag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void computeTumbleDrag() {
|
||||||
|
|
||||||
|
// Computed based on Sampo's experimentation as documented in the pdf.
|
||||||
|
|
||||||
|
// compute the fin and body tube projected areas
|
||||||
|
double aFins = 0.0;
|
||||||
|
double aBt = 0.0;
|
||||||
|
Rocket r = this.getConfiguration().getRocket();
|
||||||
|
Iterator<RocketComponent> componentIterator = r.iterator();
|
||||||
|
while ( componentIterator.hasNext() ) {
|
||||||
|
RocketComponent component = componentIterator.next();
|
||||||
|
if ( ! component.isAerodynamic() ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( component instanceof FinSet ) {
|
||||||
|
|
||||||
|
double finComponent = ((FinSet)component).getFinArea();
|
||||||
|
int finCount = ((FinSet)component).getFinCount();
|
||||||
|
// check bounds on finCount.
|
||||||
|
if ( finCount >= finEff.length ) {
|
||||||
|
finCount = finEff.length-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
aFins += finComponent * finEff[finCount];
|
||||||
|
|
||||||
|
} else if (component instanceof SymmetricComponent ){
|
||||||
|
aBt += ((SymmetricComponent) component) .getComponentPlanformArea();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drag = ( cDFin * aFins + cDBt * aBt );
|
||||||
|
}
|
||||||
|
}
|
137
core/src/net/sf/openrocket/simulation/BasicTumbleStepper.java
Normal file
137
core/src/net/sf/openrocket/simulation/BasicTumbleStepper.java
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
package net.sf.openrocket.simulation;
|
||||||
|
|
||||||
|
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
|
||||||
|
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||||
|
import net.sf.openrocket.util.Coordinate;
|
||||||
|
import net.sf.openrocket.util.GeodeticComputationStrategy;
|
||||||
|
import net.sf.openrocket.util.MathUtil;
|
||||||
|
import net.sf.openrocket.util.WorldCoordinate;
|
||||||
|
|
||||||
|
public class BasicTumbleStepper extends AbstractSimulationStepper {
|
||||||
|
|
||||||
|
private static final double RECOVERY_TIME_STEP = 0.5;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimulationStatus initialize(SimulationStatus status) throws SimulationException {
|
||||||
|
return new BasicTumbleStatus(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void step(SimulationStatus status, double maxTimeStep) throws SimulationException {
|
||||||
|
|
||||||
|
// Get the atmospheric conditions
|
||||||
|
AtmosphericConditions atmosphere = modelAtmosphericConditions(status);
|
||||||
|
|
||||||
|
//// Local wind speed and direction
|
||||||
|
Coordinate windSpeed = modelWindVelocity(status);
|
||||||
|
Coordinate airSpeed = status.getRocketVelocity().add(windSpeed);
|
||||||
|
|
||||||
|
// Get total CD
|
||||||
|
double mach = airSpeed.length() / atmosphere.getMachSpeed();
|
||||||
|
|
||||||
|
double tumbleDrag = ((BasicTumbleStatus)status).getTumbleDrag();
|
||||||
|
|
||||||
|
// Compute drag force
|
||||||
|
double dynP = (0.5 * atmosphere.getDensity() * airSpeed.length2());
|
||||||
|
double dragForce = tumbleDrag * dynP;
|
||||||
|
MassData massData = calculateMassData(status);
|
||||||
|
double mass = massData.getCG().weight;
|
||||||
|
|
||||||
|
|
||||||
|
// Compute drag acceleration
|
||||||
|
Coordinate linearAcceleration;
|
||||||
|
if (airSpeed.length() > 0.001) {
|
||||||
|
linearAcceleration = airSpeed.normalize().multiply(-dragForce / mass);
|
||||||
|
} else {
|
||||||
|
linearAcceleration = Coordinate.NUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add effect of gravity
|
||||||
|
double gravity = modelGravity(status);
|
||||||
|
linearAcceleration = linearAcceleration.sub(0, 0, gravity);
|
||||||
|
|
||||||
|
|
||||||
|
// Add coriolis acceleration
|
||||||
|
Coordinate coriolisAcceleration = status.getSimulationConditions().getGeodeticComputation().getCoriolisAcceleration(
|
||||||
|
status.getRocketWorldPosition(), status.getRocketVelocity());
|
||||||
|
linearAcceleration = linearAcceleration.add(coriolisAcceleration);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Select time step
|
||||||
|
double timeStep = MathUtil.min(0.5 / linearAcceleration.length(), RECOVERY_TIME_STEP);
|
||||||
|
|
||||||
|
// Perform Euler integration
|
||||||
|
status.setRocketPosition(status.getRocketPosition().add(status.getRocketVelocity().multiply(timeStep)).
|
||||||
|
add(linearAcceleration.multiply(MathUtil.pow2(timeStep) / 2)));
|
||||||
|
status.setRocketVelocity(status.getRocketVelocity().add(linearAcceleration.multiply(timeStep)));
|
||||||
|
status.setSimulationTime(status.getSimulationTime() + timeStep);
|
||||||
|
|
||||||
|
|
||||||
|
// Update the world coordinate
|
||||||
|
WorldCoordinate w = status.getSimulationConditions().getLaunchSite();
|
||||||
|
w = status.getSimulationConditions().getGeodeticComputation().addCoordinate(w, status.getRocketPosition());
|
||||||
|
status.setRocketWorldPosition(w);
|
||||||
|
|
||||||
|
|
||||||
|
// Store data
|
||||||
|
FlightDataBranch data = status.getFlightData();
|
||||||
|
boolean extra = status.getSimulationConditions().isCalculateExtras();
|
||||||
|
data.addPoint();
|
||||||
|
|
||||||
|
data.setValue(FlightDataType.TYPE_TIME, status.getSimulationTime());
|
||||||
|
data.setValue(FlightDataType.TYPE_ALTITUDE, status.getRocketPosition().z);
|
||||||
|
data.setValue(FlightDataType.TYPE_POSITION_X, status.getRocketPosition().x);
|
||||||
|
data.setValue(FlightDataType.TYPE_POSITION_Y, status.getRocketPosition().y);
|
||||||
|
if (extra) {
|
||||||
|
data.setValue(FlightDataType.TYPE_POSITION_XY,
|
||||||
|
MathUtil.hypot(status.getRocketPosition().x, status.getRocketPosition().y));
|
||||||
|
data.setValue(FlightDataType.TYPE_POSITION_DIRECTION,
|
||||||
|
Math.atan2(status.getRocketPosition().y, status.getRocketPosition().x));
|
||||||
|
|
||||||
|
data.setValue(FlightDataType.TYPE_VELOCITY_XY,
|
||||||
|
MathUtil.hypot(status.getRocketVelocity().x, status.getRocketVelocity().y));
|
||||||
|
data.setValue(FlightDataType.TYPE_ACCELERATION_XY,
|
||||||
|
MathUtil.hypot(linearAcceleration.x, linearAcceleration.y));
|
||||||
|
|
||||||
|
data.setValue(FlightDataType.TYPE_ACCELERATION_TOTAL, linearAcceleration.length());
|
||||||
|
|
||||||
|
double Re = airSpeed.length() *
|
||||||
|
status.getConfiguration().getLength() /
|
||||||
|
atmosphere.getKinematicViscosity();
|
||||||
|
data.setValue(FlightDataType.TYPE_REYNOLDS_NUMBER, Re);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
data.setValue(FlightDataType.TYPE_LATITUDE, status.getRocketWorldPosition().getLatitudeRad());
|
||||||
|
data.setValue(FlightDataType.TYPE_LONGITUDE, status.getRocketWorldPosition().getLongitudeRad());
|
||||||
|
data.setValue(FlightDataType.TYPE_GRAVITY, gravity);
|
||||||
|
|
||||||
|
if (status.getSimulationConditions().getGeodeticComputation() != GeodeticComputationStrategy.FLAT) {
|
||||||
|
data.setValue(FlightDataType.TYPE_CORIOLIS_ACCELERATION, coriolisAcceleration.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
data.setValue(FlightDataType.TYPE_VELOCITY_Z, status.getRocketVelocity().z);
|
||||||
|
data.setValue(FlightDataType.TYPE_ACCELERATION_Z, linearAcceleration.z);
|
||||||
|
|
||||||
|
data.setValue(FlightDataType.TYPE_VELOCITY_TOTAL, airSpeed.length());
|
||||||
|
data.setValue(FlightDataType.TYPE_MACH_NUMBER, mach);
|
||||||
|
|
||||||
|
data.setValue(FlightDataType.TYPE_MASS, mass);
|
||||||
|
data.setValue(FlightDataType.TYPE_PROPELLANT_MASS, 0.0); // Is this a reasonable assumption? Probably.
|
||||||
|
|
||||||
|
data.setValue(FlightDataType.TYPE_THRUST_FORCE, 0);
|
||||||
|
data.setValue(FlightDataType.TYPE_DRAG_FORCE, dragForce);
|
||||||
|
|
||||||
|
data.setValue(FlightDataType.TYPE_WIND_VELOCITY, windSpeed.length());
|
||||||
|
data.setValue(FlightDataType.TYPE_AIR_TEMPERATURE, atmosphere.getTemperature());
|
||||||
|
data.setValue(FlightDataType.TYPE_AIR_PRESSURE, atmosphere.getPressure());
|
||||||
|
data.setValue(FlightDataType.TYPE_SPEED_OF_SOUND, atmosphere.getMachSpeed());
|
||||||
|
|
||||||
|
data.setValue(FlightDataType.TYPE_TIME_STEP, timeStep);
|
||||||
|
data.setValue(FlightDataType.TYPE_COMPUTATION_TIME,
|
||||||
|
(System.nanoTime() - status.getSimulationStartWallTime()) / 1000000000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -72,7 +72,12 @@ public class FlightEvent implements Comparable<FlightEvent> {
|
|||||||
* A change in altitude has occurred. Data is a <code>Pair<Double,Double></code>
|
* A change in altitude has occurred. Data is a <code>Pair<Double,Double></code>
|
||||||
* which contains the old and new altitudes.
|
* which contains the old and new altitudes.
|
||||||
*/
|
*/
|
||||||
ALTITUDE(trans.get("FlightEvent.Type.ALTITUDE"));
|
ALTITUDE(trans.get("FlightEvent.Type.ALTITUDE")),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The rocket begins to tumble.
|
||||||
|
*/
|
||||||
|
TUMBLE(trans.get("FlightEvent.Type.TUMBLE"));
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
|
@ -69,6 +69,9 @@ public class SimulationStatus implements Monitorable {
|
|||||||
/** Set to true when apogee has been detected. */
|
/** Set to true when apogee has been detected. */
|
||||||
private boolean apogeeReached = false;
|
private boolean apogeeReached = false;
|
||||||
|
|
||||||
|
/** Set to true to indicate the rocket is tumbling. */
|
||||||
|
private boolean tumbling = false;
|
||||||
|
|
||||||
/** Contains a list of deployed recovery devices. */
|
/** Contains a list of deployed recovery devices. */
|
||||||
private MonitorableSet<RecoveryDevice> deployedRecoveryDevices = new MonitorableSet<RecoveryDevice>();
|
private MonitorableSet<RecoveryDevice> deployedRecoveryDevices = new MonitorableSet<RecoveryDevice>();
|
||||||
|
|
||||||
@ -179,6 +182,7 @@ public class SimulationStatus implements Monitorable {
|
|||||||
this.liftoff = orig.liftoff;
|
this.liftoff = orig.liftoff;
|
||||||
this.launchRodCleared = orig.launchRodCleared;
|
this.launchRodCleared = orig.launchRodCleared;
|
||||||
this.apogeeReached = orig.apogeeReached;
|
this.apogeeReached = orig.apogeeReached;
|
||||||
|
this.tumbling = orig.tumbling;
|
||||||
this.motorBurntOut = orig.motorBurntOut;
|
this.motorBurntOut = orig.motorBurntOut;
|
||||||
|
|
||||||
this.deployedRecoveryDevices.clear();
|
this.deployedRecoveryDevices.clear();
|
||||||
@ -380,6 +384,15 @@ public class SimulationStatus implements Monitorable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setTumbling( boolean tumbling ) {
|
||||||
|
this.tumbling = tumbling;
|
||||||
|
this.modID++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTumbling() {
|
||||||
|
return tumbling;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<RecoveryDevice> getDeployedRecoveryDevices() {
|
public Set<RecoveryDevice> getDeployedRecoveryDevices() {
|
||||||
return deployedRecoveryDevices;
|
return deployedRecoveryDevices;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user