package net.sf.openrocket.simulation.listeners;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sf.openrocket.aerodynamics.AerodynamicForces;
import net.sf.openrocket.aerodynamics.FlightConditions;
import net.sf.openrocket.aerodynamics.Warning;
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
import net.sf.openrocket.motor.MotorId;
import net.sf.openrocket.motor.MotorInstance;
import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
import net.sf.openrocket.simulation.AccelerationData;
import net.sf.openrocket.simulation.FlightEvent;
import net.sf.openrocket.simulation.MassData;
import net.sf.openrocket.simulation.SimulationStatus;
import net.sf.openrocket.simulation.exception.SimulationException;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.MathUtil;
/**
* Helper methods for firing events to simulation listeners.
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public class SimulationListenerHelper {
private static final Logger log = LoggerFactory.getLogger(SimulationListenerHelper.class);
//////// SimulationListener methods ////////
/**
* Fire startSimulation event.
*/
public static void fireStartSimulation(SimulationStatus status)
throws SimulationException {
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
l.startSimulation(status);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
}
}
/**
* Fire endSimulation event.
*/
public static void fireEndSimulation(SimulationStatus status, SimulationException exception) {
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
l.endSimulation(status, exception);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
}
}
/**
* Fire preStep event.
*
* @return <code>true</code> to handle step normally, <code>false</code> to skip the step.
*/
public static boolean firePreStep(SimulationStatus status)
throws SimulationException {
boolean b;
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
b = l.preStep(status);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (b == false) {
warn(status, l);
return false;
}
}
return true;
}
/**
* Fire postStep event.
*/
public static void firePostStep(SimulationStatus status)
throws SimulationException {
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
l.postStep(status);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
}
}
//////// SimulationEventListener methods ////////
/**
* Fire an add flight event event.
*
* @return <code>true</code> to add the event normally, <code>false</code> to skip adding the event.
*/
public static boolean fireAddFlightEvent(SimulationStatus status, FlightEvent event) throws SimulationException {
boolean b;
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationEventListener) {
b = ((SimulationEventListener) l).addFlightEvent(status, event);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (b == false) {
warn(status, l);
return false;
}
}
}
return true;
}
/**
* Fire a handle flight event event.
*
* @return <code>true</code> to handle the event normally, <code>false</code> to skip event.
*/
public static boolean fireHandleFlightEvent(SimulationStatus status, FlightEvent event) throws SimulationException {
boolean b;
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationEventListener) {
b = ((SimulationEventListener) l).handleFlightEvent(status, event);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (b == false) {
warn(status, l);
return false;
}
}
}
return true;
}
/**
* Fire motor ignition event.
*
* @return <code>true</code> to handle the event normally, <code>false</code> to skip event.
*/
public static boolean fireMotorIgnition(SimulationStatus status, MotorId motorId, MotorMount mount,
MotorInstance instance) throws SimulationException {
boolean b;
int modID = status.getModID(); // Contains also motor instance
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationEventListener) {
b = ((SimulationEventListener) l).motorIgnition(status, motorId, mount, instance);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (b == false) {
warn(status, l);
return false;
}
}
}
return true;
}
/**
* Fire recovery device deployment event.
*
* @return <code>true</code> to handle the event normally, <code>false</code> to skip event.
*/
public static boolean fireRecoveryDeviceDeployment(SimulationStatus status, RecoveryDevice device)
throws SimulationException {
boolean b;
int modID = status.getModID(); // Contains also motor instance
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationEventListener) {
b = ((SimulationEventListener) l).recoveryDeviceDeployment(status, device);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (b == false) {
warn(status, l);
return false;
}
}
}
return true;
}
//////// SimulationComputationalListener methods ////////
/**
* Fire preAtmosphericModel event.
*
* @return <code>null</code> normally, or overriding atmospheric conditions.
*/
public static AtmosphericConditions firePreAtmosphericModel(SimulationStatus status)
throws SimulationException {
AtmosphericConditions conditions;
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationComputationListener) {
conditions = ((SimulationComputationListener) l).preAtmosphericModel(status);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (conditions != null) {
warn(status, l);
return conditions;
}
}
}
return null;
}
/**
* Fire postAtmosphericModel event.
*
* @return the atmospheric conditions to use.
*/
public static AtmosphericConditions firePostAtmosphericModel(SimulationStatus status, AtmosphericConditions conditions)
throws SimulationException {
AtmosphericConditions c;
AtmosphericConditions clone = conditions.clone();
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationComputationListener) {
c = ((SimulationComputationListener) l).postAtmosphericModel(status, clone);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (c != null && !c.equals(conditions)) {
warn(status, l);
conditions = c;
clone = conditions.clone();
}
}
}
return conditions;
}
/**
* Fire preWindModel event.
*
* @return <code>null</code> normally, or overriding wind.
*/
public static Coordinate firePreWindModel(SimulationStatus status)
throws SimulationException {
Coordinate wind;
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationComputationListener) {
wind = ((SimulationComputationListener) l).preWindModel(status);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (wind != null) {
warn(status, l);
return wind;
}
}
}
return null;
}
/**
* Fire postWindModel event.
*
* @return the wind to use.
*/
public static Coordinate firePostWindModel(SimulationStatus status, Coordinate wind) throws SimulationException {
Coordinate w;
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationComputationListener) {
w = ((SimulationComputationListener) l).postWindModel(status, wind);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (w != null && !w.equals(wind)) {
warn(status, l);
wind = w;
}
}
}
return wind;
}
/**
* Fire preGravityModel event.
*
* @return <code>NaN</code> normally, or overriding gravity.
*/
public static double firePreGravityModel(SimulationStatus status)
throws SimulationException {
double gravity;
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationComputationListener) {
gravity = ((SimulationComputationListener) l).preGravityModel(status);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (!Double.isNaN(gravity)) {
warn(status, l);
return gravity;
}
}
}
return Double.NaN;
}
/**
* Fire postGravityModel event.
*
* @return the gravity to use.
*/
public static double firePostGravityModel(SimulationStatus status, double gravity) throws SimulationException {
double g;
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationComputationListener) {
g = ((SimulationComputationListener) l).postGravityModel(status, gravity);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (!Double.isNaN(g) && !MathUtil.equals(g, gravity)) {
warn(status, l);
gravity = g;
}
}
}
return gravity;
}
/**
* Fire preFlightConditions event.
*
* @return <code>null</code> normally, or overriding flight conditions.
*/
public static FlightConditions firePreFlightConditions(SimulationStatus status)
throws SimulationException {
FlightConditions conditions;
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationComputationListener) {
conditions = ((SimulationComputationListener) l).preFlightConditions(status);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (conditions != null) {
warn(status, l);
return conditions;
}
}
}
return null;
}
/**
* Fire postFlightConditions event.
*
* @return the flight conditions to use: either <code>conditions</code> or a new object
* containing the modified conditions.
*/
public static FlightConditions firePostFlightConditions(SimulationStatus status, FlightConditions conditions)
throws SimulationException {
FlightConditions c;
FlightConditions clone = conditions.clone();
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationComputationListener) {
c = ((SimulationComputationListener) l).postFlightConditions(status, clone);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (c != null && !c.equals(conditions)) {
warn(status, l);
conditions = c;
clone = conditions.clone();
}
}
}
return conditions;
}
/**
* Fire preAerodynamicCalculation event.
*
* @return <code>null</code> normally, or overriding aerodynamic forces.
*/
public static AerodynamicForces firePreAerodynamicCalculation(SimulationStatus status)
throws SimulationException {
AerodynamicForces forces;
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationComputationListener) {
forces = ((SimulationComputationListener) l).preAerodynamicCalculation(status);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (forces != null) {
warn(status, l);
return forces;
}
}
}
return null;
}
/**
* Fire postAerodynamicCalculation event.
*
* @return the aerodynamic forces to use.
*/
public static AerodynamicForces firePostAerodynamicCalculation(SimulationStatus status, AerodynamicForces forces)
throws SimulationException {
AerodynamicForces f;
AerodynamicForces clone = forces.clone();
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationComputationListener) {
f = ((SimulationComputationListener) l).postAerodynamicCalculation(status, clone);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (f != null && !f.equals(forces)) {
warn(status, l);
forces = f;
clone = forces.clone();
}
}
}
return forces;
}
/**
* Fire preMassCalculation event.
*
* @return <code>null</code> normally, or overriding mass data.
*/
public static MassData firePreMassCalculation(SimulationStatus status)
throws SimulationException {
MassData mass;
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationComputationListener) {
mass = ((SimulationComputationListener) l).preMassCalculation(status);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (mass != null) {
warn(status, l);
return mass;
}
}
}
return null;
}
/**
* Fire postMassCalculation event.
*
* @return the aerodynamic forces to use.
*/
public static MassData firePostMassCalculation(SimulationStatus status, MassData mass) throws SimulationException {
MassData m;
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationComputationListener) {
m = ((SimulationComputationListener) l).postMassCalculation(status, mass);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (m != null && !m.equals(mass)) {
warn(status, l);
mass = m;
}
}
}
return mass;
}
/**
* Fire preThrustComputation event.
*
* @return <code>NaN</code> normally, or overriding thrust.
*/
public static double firePreThrustCalculation(SimulationStatus status)
throws SimulationException {
double thrust;
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationComputationListener) {
thrust = ((SimulationComputationListener) l).preSimpleThrustCalculation(status);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (!Double.isNaN(thrust)) {
warn(status, l);
return thrust;
}
}
}
return Double.NaN;
}
/**
* Fire postThrustComputation event.
*
* @return the thrust value to use.
*/
public static double firePostThrustCalculation(SimulationStatus status, double thrust) throws SimulationException {
double t;
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationComputationListener) {
t = ((SimulationComputationListener) l).postSimpleThrustCalculation(status, thrust);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (!Double.isNaN(t) && !MathUtil.equals(t, thrust)) {
warn(status, l);
thrust = t;
}
}
}
return thrust;
}
/**
* Fire preMassCalculation event.
*
* @return <code>null</code> normally, or overriding mass data.
*/
public static AccelerationData firePreAccelerationCalculation(SimulationStatus status) throws SimulationException {
AccelerationData acceleration;
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationComputationListener) {
acceleration = ((SimulationComputationListener) l).preAccelerationCalculation(status);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (acceleration != null) {
warn(status, l);
return acceleration;
}
}
}
return null;
}
/**
* Fire postMassCalculation event.
*
* @return the aerodynamic forces to use.
*/
public static AccelerationData firePostAccelerationCalculation(SimulationStatus status,
AccelerationData acceleration) throws SimulationException {
AccelerationData a;
int modID = status.getModID();
for (SimulationListener l : status.getSimulationConditions().getSimulationListenerList()) {
if (l instanceof SimulationComputationListener) {
a = ((SimulationComputationListener) l).postAccelerationCalculation(status, acceleration);
if (modID != status.getModID()) {
warn(status, l);
modID = status.getModID();
}
if (a != null && !a.equals(acceleration)) {
warn(status, l);
acceleration = a;
}
}
}
return acceleration;
}
private static void warn(SimulationStatus status, SimulationListener listener) {
if (!listener.isSystemListener()) {
log.info("Non-system listener " + listener + " affected the simulation");
status.getWarnings().add(Warning.LISTENERS_AFFECTED);
}
}
}