package net.sf.openrocket.simulation;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.Stage;
import net.sf.openrocket.simulation.exception.MotorIgnitionException;
import net.sf.openrocket.simulation.exception.SimulationException;
import net.sf.openrocket.simulation.exception.SimulationLaunchException;
status = initialStatus(configuration, motorConfiguration, simulationConditions, flightData);
status = currentStepper.initialize(status);
-
+
SimulationListenerHelper.fireStartSimulation(status);
// Get originating position (in case listener has modified launch position)
Coordinate origin = status.getRocketPosition();
}
SimulationListenerHelper.firePostStep(status);
-
+ // Calculate values for custom expressions
+ FlightDataBranch data = status.getFlightData();
+ ArrayList<CustomExpression> allExpressions = status.getSimulationConditions().getSimulation().getCustomExpressions();
+ for (CustomExpression expression : allExpressions ) {
+ data.setValue(expression.getType(), expression.evaluate(status));
+ }
+
// Check for NaN values in the simulation status
checkNaN();
maxAlt = status.getRocketPosition().z;
}
-
+
// Position relative to start location
Coordinate relativePosition = status.getRocketPosition().sub(origin);
addEvent(new FlightEvent(FlightEvent.Type.LAUNCHROD, status.getSimulationTime(), null));
}
-
+
// Check for apogee
if (!status.isApogeeReached() && status.getRocketPosition().z < maxAlt - 0.01) {
addEvent(new FlightEvent(FlightEvent.Type.APOGEE, status.getSimulationTime(),
status.getConfiguration().getRocket()));
}
-
+
// Check for burnt out motors
for (MotorId motorId : status.getMotorConfiguration().getMotorIDs()) {
MotorInstance motor = status.getMotorConfiguration().getMotorInstance(motorId);
}
-
+
private SimulationStatus initialStatus(Configuration configuration,
MotorInstanceConfiguration motorConfiguration,
SimulationConditions simulationConditions, FlightData flightData) {
init.setRocketOrientationQuaternion(o);
init.setRocketRotationVelocity(Coordinate.NUL);
-
+
/*
* Calculate the effective launch rod length taking into account launch lugs.
* If no lugs are found, assume a tower launcher of full length.
}
init.setEffectiveLaunchRodLength(length);
-
-
+
+
init.setSimulationStartWallTime(System.nanoTime());
init.setMotorIgnited(false);
}
-
+
/**
* Create a rocket configuration from the launch conditions.
*
}
-
+
/**
* Create a new motor instance configuration for the rocket configuration.
*
for (event = nextEvent(); event != null; event = nextEvent()) {
+ // Ignore events for components that are no longer attached to the rocket
+ if (event.getSource() != null && event.getSource().getParent() != null &&
+ !status.getConfiguration().isStageActive(event.getSource().getStageNumber())) {
+ continue;
+ }
+
// Call simulation listeners, allow aborting event handling
if (!SimulationListenerHelper.fireHandleFlightEvent(status, event)) {
continue;
}
}
-
-
+
+
// Check for motor ignition events, add ignition events to queue
for (MotorId id : status.getMotorConfiguration().getMotorIDs()) {
MotorMount mount = status.getMotorConfiguration().getMotorMount(id);
}
}
-
+
+ // Check for stage separation event
+ for (int stageNo : status.getConfiguration().getActiveStages()) {
+ if (stageNo == 0)
+ continue;
+
+ Stage stage = (Stage) status.getConfiguration().getRocket().getChild(stageNo);
+ if (stage.getSeparationEvent().isSeparationEvent(event, stage)) {
+ addEvent(new FlightEvent(FlightEvent.Type.STAGE_SEPARATION,
+ event.getTime() + stage.getSeparationDelay(), stage));
+ }
+ }
+
+
// Check for recovery device deployment, add events to queue
Iterator<RocketComponent> rci = status.getConfiguration().iterator();
while (rci.hasNext()) {
}
}
-
+
// Handle event
switch (event.getType()) {
status.getFlightData().addEvent(event);
break;
}
-
+
case IGNITION: {
// Ignite the motor
MotorMount mount = (MotorMount) event.getSource();
status.setMotorIgnited(true);
status.getFlightData().addEvent(event);
- // Add stage separation event if appropriate
- int n = component.getStageNumber();
- if (n < component.getRocket().getStageCount() - 1) {
- if (status.getConfiguration().isStageActive(n + 1)) {
- addEvent(new FlightEvent(FlightEvent.Type.STAGE_SEPARATION, event.getTime(),
- component.getStage()));
- }
- }
break;
}
-
+
case LIFTOFF: {
// Mark lift-off as occurred
status.setLiftoff(true);
status.getFlightData().addEvent(event);
break;
}
-
+
case LAUNCHROD: {
// Mark launch rod as cleared
status.setLaunchRodCleared(true);
status.getFlightData().addEvent(event);
break;
}
-
+
case BURNOUT: {
// If motor burnout occurs without lift-off, abort
if (!status.isLiftoff()) {
status.getFlightData().addEvent(event);
break;
}
-
+
case EJECTION_CHARGE: {
status.getFlightData().addEvent(event);
break;
}
-
+
case STAGE_SEPARATION: {
// TODO: HIGH: Store lower stages to be simulated later
RocketComponent stage = event.getSource();
int n = stage.getStageNumber();
- status.getConfiguration().setToStage(n);
+ status.getConfiguration().setToStage(n - 1);
status.getFlightData().addEvent(event);
break;
}
-
+
case APOGEE:
// Mark apogee as reached
status.setApogeeReached(true);
}
-
+
// If no motor has ignited, abort
if (!status.isMotorIgnited()) {
throw new MotorIgnitionException("No motors ignited.");
return ret;
}
-
/**
* Add a flight event to the event queue unless a listener aborts adding it.
*
}
-
+
/**
* Return the next flight event to handle, or null if no more events should be handled.
* This method jumps the simulation time forward in case no motors have been ignited.
}
-
+
private void checkNaN() throws SimulationException {
double d = 0;
boolean b = false;
}
}
-
+
}