Cleanup configuration as component change listener.
This commit is contained in:
parent
9ce96bdc05
commit
d48a2cb400
@ -34,12 +34,12 @@ import net.sf.openrocket.util.StateChangeListener;
|
|||||||
* <p>
|
* <p>
|
||||||
* This class is not thread-safe and enforces single-threaded access with a
|
* This class is not thread-safe and enforces single-threaded access with a
|
||||||
* SafetyMutex.
|
* SafetyMutex.
|
||||||
*
|
*
|
||||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||||
*/
|
*/
|
||||||
public class Simulation implements ChangeSource, Cloneable {
|
public class Simulation implements ChangeSource, Cloneable {
|
||||||
private static final LogHelper log = Application.getLogger();
|
private static final LogHelper log = Application.getLogger();
|
||||||
|
|
||||||
public static enum Status {
|
public static enum Status {
|
||||||
/** Up-to-date */
|
/** Up-to-date */
|
||||||
UPTODATE,
|
UPTODATE,
|
||||||
@ -56,21 +56,21 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
/** Not yet simulated */
|
/** Not yet simulated */
|
||||||
NOT_SIMULATED
|
NOT_SIMULATED
|
||||||
}
|
}
|
||||||
|
|
||||||
private SafetyMutex mutex = SafetyMutex.newInstance();
|
private SafetyMutex mutex = SafetyMutex.newInstance();
|
||||||
|
|
||||||
private final Rocket rocket;
|
private final Rocket rocket;
|
||||||
|
|
||||||
private String name = "";
|
private String name = "";
|
||||||
|
|
||||||
private Status status = Status.NOT_SIMULATED;
|
private Status status = Status.NOT_SIMULATED;
|
||||||
|
|
||||||
/** The conditions to use */
|
/** The conditions to use */
|
||||||
// TODO: HIGH: Change to use actual conditions class??
|
// TODO: HIGH: Change to use actual conditions class??
|
||||||
private SimulationOptions options;
|
private SimulationOptions options;
|
||||||
|
|
||||||
private ArrayList<String> simulationListeners = new ArrayList<String>();
|
private ArrayList<String> simulationListeners = new ArrayList<String>();
|
||||||
|
|
||||||
private final Class<? extends SimulationEngine> simulationEngineClass = BasicEventSimulationEngine.class;
|
private final Class<? extends SimulationEngine> simulationEngineClass = BasicEventSimulationEngine.class;
|
||||||
private Class<? extends SimulationStepper> simulationStepperClass = RK4SimulationStepper.class;
|
private Class<? extends SimulationStepper> simulationStepperClass = RK4SimulationStepper.class;
|
||||||
private Class<? extends AerodynamicCalculator> aerodynamicCalculatorClass = BarrowmanCalculator.class;
|
private Class<? extends AerodynamicCalculator> aerodynamicCalculatorClass = BarrowmanCalculator.class;
|
||||||
@ -78,35 +78,35 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
|
|
||||||
/** Listeners for this object */
|
/** Listeners for this object */
|
||||||
private List<EventListener> listeners = new ArrayList<EventListener>();
|
private List<EventListener> listeners = new ArrayList<EventListener>();
|
||||||
|
|
||||||
|
|
||||||
/** The conditions actually used in the previous simulation, or null */
|
/** The conditions actually used in the previous simulation, or null */
|
||||||
private SimulationOptions simulatedConditions = null;
|
private SimulationOptions simulatedConditions = null;
|
||||||
private String simulatedMotors = null;
|
private String simulatedMotors = null;
|
||||||
private FlightData simulatedData = null;
|
private FlightData simulatedData = null;
|
||||||
private int simulatedRocketID = -1;
|
private int simulatedRocketID = -1;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new simulation for the rocket. Parent document should also be provided.
|
* Create a new simulation for the rocket. Parent document should also be provided.
|
||||||
* The initial motor configuration is taken from the default rocket configuration.
|
* The initial motor configuration is taken from the default rocket configuration.
|
||||||
*
|
*
|
||||||
* @param rocket the rocket associated with the simulation.
|
* @param rocket the rocket associated with the simulation.
|
||||||
*/
|
*/
|
||||||
public Simulation(Rocket rocket) {
|
public Simulation(Rocket rocket) {
|
||||||
this.rocket = rocket;
|
this.rocket = rocket;
|
||||||
this.status = Status.NOT_SIMULATED;
|
this.status = Status.NOT_SIMULATED;
|
||||||
|
|
||||||
options = new SimulationOptions(rocket);
|
options = new SimulationOptions(rocket);
|
||||||
options.setMotorConfigurationID(
|
options.setMotorConfigurationID(
|
||||||
rocket.getDefaultConfiguration().getMotorConfigurationID());
|
rocket.getDefaultConfiguration().getMotorConfigurationID());
|
||||||
options.addChangeListener(new ConditionListener());
|
options.addChangeListener(new ConditionListener());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Simulation(Rocket rocket, Status status, String name, SimulationOptions options,
|
public Simulation(Rocket rocket, Status status, String name, SimulationOptions options,
|
||||||
List<String> listeners, FlightData data) {
|
List<String> listeners, FlightData data) {
|
||||||
|
|
||||||
if (rocket == null)
|
if (rocket == null)
|
||||||
throw new IllegalArgumentException("rocket cannot be null");
|
throw new IllegalArgumentException("rocket cannot be null");
|
||||||
if (status == null)
|
if (status == null)
|
||||||
@ -115,9 +115,9 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
throw new IllegalArgumentException("name cannot be null");
|
throw new IllegalArgumentException("name cannot be null");
|
||||||
if (options == null)
|
if (options == null)
|
||||||
throw new IllegalArgumentException("options cannot be null");
|
throw new IllegalArgumentException("options cannot be null");
|
||||||
|
|
||||||
this.rocket = rocket;
|
this.rocket = rocket;
|
||||||
|
|
||||||
if (status == Status.UPTODATE) {
|
if (status == Status.UPTODATE) {
|
||||||
this.status = Status.LOADED;
|
this.status = Status.LOADED;
|
||||||
} else if (data == null) {
|
} else if (data == null) {
|
||||||
@ -125,16 +125,16 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
} else {
|
} else {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
options.addChangeListener(new ConditionListener());
|
options.addChangeListener(new ConditionListener());
|
||||||
|
|
||||||
if (listeners != null) {
|
if (listeners != null) {
|
||||||
this.simulationListeners.addAll(listeners);
|
this.simulationListeners.addAll(listeners);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (data != null && this.status != Status.NOT_SIMULATED) {
|
if (data != null && this.status != Status.NOT_SIMULATED) {
|
||||||
simulatedData = data;
|
simulatedData = data;
|
||||||
@ -143,24 +143,24 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
simulatedRocketID = rocket.getModID();
|
simulatedRocketID = rocket.getModID();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the rocket associated with this simulation.
|
* Return the rocket associated with this simulation.
|
||||||
*
|
*
|
||||||
* @return the rocket.
|
* @return the rocket.
|
||||||
*/
|
*/
|
||||||
public Rocket getRocket() {
|
public Rocket getRocket() {
|
||||||
mutex.verify();
|
mutex.verify();
|
||||||
return rocket;
|
return rocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a newly created Configuration for this simulation. The configuration
|
* Return a newly created Configuration for this simulation. The configuration
|
||||||
* has the motor ID set and all stages active.
|
* has the motor ID set and all stages active.
|
||||||
*
|
*
|
||||||
* @return a newly created Configuration of the launch conditions.
|
* @return a newly created Configuration of the launch conditions.
|
||||||
*/
|
*/
|
||||||
public Configuration getConfiguration() {
|
public Configuration getConfiguration() {
|
||||||
@ -170,46 +170,46 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
c.setAllStages();
|
c.setAllStages();
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the simulation options attached to this simulation. The options
|
* Returns the simulation options attached to this simulation. The options
|
||||||
* may be modified freely, and the status of the simulation will change to reflect
|
* may be modified freely, and the status of the simulation will change to reflect
|
||||||
* the changes.
|
* the changes.
|
||||||
*
|
*
|
||||||
* @return the simulation conditions.
|
* @return the simulation conditions.
|
||||||
*/
|
*/
|
||||||
public SimulationOptions getOptions() {
|
public SimulationOptions getOptions() {
|
||||||
mutex.verify();
|
mutex.verify();
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of simulation listeners. The returned list is the one used by
|
* Get the list of simulation listeners. The returned list is the one used by
|
||||||
* this object; changes to it will reflect changes in the simulation.
|
* this object; changes to it will reflect changes in the simulation.
|
||||||
*
|
*
|
||||||
* @return the actual list of simulation listeners.
|
* @return the actual list of simulation listeners.
|
||||||
*/
|
*/
|
||||||
public List<String> getSimulationListeners() {
|
public List<String> getSimulationListeners() {
|
||||||
mutex.verify();
|
mutex.verify();
|
||||||
return simulationListeners;
|
return simulationListeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the user-defined name of the simulation.
|
* Return the user-defined name of the simulation.
|
||||||
*
|
*
|
||||||
* @return the name for the simulation.
|
* @return the name for the simulation.
|
||||||
*/
|
*/
|
||||||
public String getName() {
|
public String getName() {
|
||||||
mutex.verify();
|
mutex.verify();
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the user-defined name of the simulation. Setting the name to
|
* Set the user-defined name of the simulation. Setting the name to
|
||||||
* null yields an empty name.
|
* null yields an empty name.
|
||||||
*
|
*
|
||||||
* @param name the name of the simulation.
|
* @param name the name of the simulation.
|
||||||
*/
|
*/
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
@ -217,43 +217,43 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
try {
|
try {
|
||||||
if (this.name.equals(name))
|
if (this.name.equals(name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (name == null)
|
if (name == null)
|
||||||
this.name = "";
|
this.name = "";
|
||||||
else
|
else
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|
||||||
fireChangeEvent();
|
fireChangeEvent();
|
||||||
} finally {
|
} finally {
|
||||||
mutex.unlock("setName");
|
mutex.unlock("setName");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the status of this simulation. This method examines whether the
|
* Returns the status of this simulation. This method examines whether the
|
||||||
* simulation has been outdated and returns {@link Status#OUTDATED} accordingly.
|
* simulation has been outdated and returns {@link Status#OUTDATED} accordingly.
|
||||||
*
|
*
|
||||||
* @return the status
|
* @return the status
|
||||||
* @see Status
|
* @see Status
|
||||||
*/
|
*/
|
||||||
public Status getStatus() {
|
public Status getStatus() {
|
||||||
mutex.verify();
|
mutex.verify();
|
||||||
|
|
||||||
if (status == Status.UPTODATE || status == Status.LOADED) {
|
if (status == Status.UPTODATE || status == Status.LOADED) {
|
||||||
if (rocket.getFunctionalModID() != simulatedRocketID ||
|
if (rocket.getFunctionalModID() != simulatedRocketID ||
|
||||||
!options.equals(simulatedConditions))
|
!options.equals(simulatedConditions))
|
||||||
return Status.OUTDATED;
|
return Status.OUTDATED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simulate the flight.
|
* Simulate the flight.
|
||||||
*
|
*
|
||||||
* @param additionalListeners additional simulation listeners (those defined by the simulation are used in any case)
|
* @param additionalListeners additional simulation listeners (those defined by the simulation are used in any case)
|
||||||
* @throws SimulationException if a problem occurs during simulation
|
* @throws SimulationException if a problem occurs during simulation
|
||||||
*/
|
*/
|
||||||
@ -261,13 +261,13 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
throws SimulationException {
|
throws SimulationException {
|
||||||
mutex.lock("simulate");
|
mutex.lock("simulate");
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if (this.status == Status.EXTERNAL) {
|
if (this.status == Status.EXTERNAL) {
|
||||||
throw new SimulationException("Cannot simulate imported simulation.");
|
throw new SimulationException("Cannot simulate imported simulation.");
|
||||||
}
|
}
|
||||||
|
|
||||||
SimulationEngine simulator;
|
SimulationEngine simulator;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
simulator = simulationEngineClass.newInstance();
|
simulator = simulationEngineClass.newInstance();
|
||||||
} catch (InstantiationException e) {
|
} catch (InstantiationException e) {
|
||||||
@ -275,13 +275,13 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
throw new IllegalStateException("Cannot access simulator instance?! BUG!", e);
|
throw new IllegalStateException("Cannot access simulator instance?! BUG!", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
SimulationConditions simulationConditions = options.toSimulationConditions();
|
SimulationConditions simulationConditions = options.toSimulationConditions();
|
||||||
simulationConditions.setSimulation(this);
|
simulationConditions.setSimulation(this);
|
||||||
for (SimulationListener l : additionalListeners) {
|
for (SimulationListener l : additionalListeners) {
|
||||||
simulationConditions.getSimulationListenerList().add(l);
|
simulationConditions.getSimulationListenerList().add(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String className : simulationListeners) {
|
for (String className : simulationListeners) {
|
||||||
SimulationListener l = null;
|
SimulationListener l = null;
|
||||||
try {
|
try {
|
||||||
@ -293,43 +293,45 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
}
|
}
|
||||||
simulationConditions.getSimulationListenerList().add(l);
|
simulationConditions.getSimulationListenerList().add(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
long t1, t2;
|
long t1, t2;
|
||||||
log.debug("Simulation: calling simulator");
|
log.debug("Simulation: calling simulator");
|
||||||
t1 = System.currentTimeMillis();
|
t1 = System.currentTimeMillis();
|
||||||
simulatedData = simulator.simulate(simulationConditions);
|
simulatedData = simulator.simulate(simulationConditions);
|
||||||
t2 = System.currentTimeMillis();
|
t2 = System.currentTimeMillis();
|
||||||
log.debug("Simulation: returning from simulator, simulation took " + (t2 - t1) + "ms");
|
log.debug("Simulation: returning from simulator, simulation took " + (t2 - t1) + "ms");
|
||||||
|
|
||||||
// Set simulated info after simulation, will not be set in case of exception
|
// Set simulated info after simulation, will not be set in case of exception
|
||||||
simulatedConditions = options.clone();
|
simulatedConditions = options.clone();
|
||||||
simulatedMotors = getConfiguration().getMotorConfigurationDescription();
|
final Configuration configuration = getConfiguration();
|
||||||
|
simulatedMotors = configuration.getMotorConfigurationDescription();
|
||||||
simulatedRocketID = rocket.getFunctionalModID();
|
simulatedRocketID = rocket.getFunctionalModID();
|
||||||
|
|
||||||
status = Status.UPTODATE;
|
status = Status.UPTODATE;
|
||||||
fireChangeEvent();
|
fireChangeEvent();
|
||||||
|
configuration.release();
|
||||||
} finally {
|
} finally {
|
||||||
mutex.unlock("simulate");
|
mutex.unlock("simulate");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the conditions used in the previous simulation, or <code>null</code>
|
* Return the conditions used in the previous simulation, or <code>null</code>
|
||||||
* if this simulation has not been run.
|
* if this simulation has not been run.
|
||||||
*
|
*
|
||||||
* @return the conditions used in the previous simulation, or <code>null</code>.
|
* @return the conditions used in the previous simulation, or <code>null</code>.
|
||||||
*/
|
*/
|
||||||
public SimulationOptions getSimulatedConditions() {
|
public SimulationOptions getSimulatedConditions() {
|
||||||
mutex.verify();
|
mutex.verify();
|
||||||
return simulatedConditions;
|
return simulatedConditions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the warnings generated in the previous simulation, or
|
* Return the warnings generated in the previous simulation, or
|
||||||
* <code>null</code> if this simulation has not been run. This is the same
|
* <code>null</code> if this simulation has not been run. This is the same
|
||||||
* warning set as contained in the <code>FlightData</code> object.
|
* warning set as contained in the <code>FlightData</code> object.
|
||||||
*
|
*
|
||||||
* @return the warnings during the previous simulation, or <code>null</code>.
|
* @return the warnings during the previous simulation, or <code>null</code>.
|
||||||
* @see FlightData#getWarningSet()
|
* @see FlightData#getWarningSet()
|
||||||
*/
|
*/
|
||||||
@ -339,12 +341,12 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
return null;
|
return null;
|
||||||
return simulatedData.getWarningSet();
|
return simulatedData.getWarningSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a string describing the motor configuration of the previous simulation,
|
* Return a string describing the motor configuration of the previous simulation,
|
||||||
* or <code>null</code> if this simulation has not been run.
|
* or <code>null</code> if this simulation has not been run.
|
||||||
*
|
*
|
||||||
* @return a description of the motor configuration of the previous simulation, or
|
* @return a description of the motor configuration of the previous simulation, or
|
||||||
* <code>null</code>.
|
* <code>null</code>.
|
||||||
* @see Rocket#getMotorConfigurationNameOrDescription(String)
|
* @see Rocket#getMotorConfigurationNameOrDescription(String)
|
||||||
@ -353,33 +355,33 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
mutex.verify();
|
mutex.verify();
|
||||||
return simulatedMotors;
|
return simulatedMotors;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the flight data of the previous simulation, or <code>null</code> if
|
* Return the flight data of the previous simulation, or <code>null</code> if
|
||||||
* this simulation has not been run.
|
* this simulation has not been run.
|
||||||
*
|
*
|
||||||
* @return the flight data of the previous simulation, or <code>null</code>.
|
* @return the flight data of the previous simulation, or <code>null</code>.
|
||||||
*/
|
*/
|
||||||
public FlightData getSimulatedData() {
|
public FlightData getSimulatedData() {
|
||||||
mutex.verify();
|
mutex.verify();
|
||||||
return simulatedData;
|
return simulatedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a copy of this simulation suitable for cut/copy/paste operations.
|
* Returns a copy of this simulation suitable for cut/copy/paste operations.
|
||||||
* The rocket refers to the same instance as the original simulation.
|
* The rocket refers to the same instance as the original simulation.
|
||||||
* This excludes any simulated data.
|
* This excludes any simulated data.
|
||||||
*
|
*
|
||||||
* @return a copy of this simulation and its conditions.
|
* @return a copy of this simulation and its conditions.
|
||||||
*/
|
*/
|
||||||
public Simulation copy() {
|
public Simulation copy() {
|
||||||
mutex.lock("copy");
|
mutex.lock("copy");
|
||||||
try {
|
try {
|
||||||
|
|
||||||
Simulation copy = (Simulation) super.clone();
|
Simulation copy = (Simulation) super.clone();
|
||||||
|
|
||||||
copy.mutex = SafetyMutex.newInstance();
|
copy.mutex = SafetyMutex.newInstance();
|
||||||
copy.status = Status.NOT_SIMULATED;
|
copy.status = Status.NOT_SIMULATED;
|
||||||
copy.options = this.options.clone();
|
copy.options = this.options.clone();
|
||||||
@ -389,21 +391,21 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
copy.simulatedMotors = null;
|
copy.simulatedMotors = null;
|
||||||
copy.simulatedData = null;
|
copy.simulatedData = null;
|
||||||
copy.simulatedRocketID = -1;
|
copy.simulatedRocketID = -1;
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
|
|
||||||
} catch (CloneNotSupportedException e) {
|
} catch (CloneNotSupportedException e) {
|
||||||
throw new BugException("Clone not supported, BUG", e);
|
throw new BugException("Clone not supported, BUG", e);
|
||||||
} finally {
|
} finally {
|
||||||
mutex.unlock("copy");
|
mutex.unlock("copy");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a duplicate of this simulation with the specified rocket. The new
|
* Create a duplicate of this simulation with the specified rocket. The new
|
||||||
* simulation is in non-simulated state.
|
* simulation is in non-simulated state.
|
||||||
*
|
*
|
||||||
* @param newRocket the rocket for the new simulation.
|
* @param newRocket the rocket for the new simulation.
|
||||||
* @return a new simulation with the same conditions and properties.
|
* @return a new simulation with the same conditions and properties.
|
||||||
*/
|
*/
|
||||||
@ -411,33 +413,33 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
mutex.lock("duplicateSimulation");
|
mutex.lock("duplicateSimulation");
|
||||||
try {
|
try {
|
||||||
Simulation copy = new Simulation(newRocket);
|
Simulation copy = new Simulation(newRocket);
|
||||||
|
|
||||||
copy.name = this.name;
|
copy.name = this.name;
|
||||||
copy.options.copyFrom(this.options);
|
copy.options.copyFrom(this.options);
|
||||||
copy.simulationListeners = this.simulationListeners.clone();
|
copy.simulationListeners = this.simulationListeners.clone();
|
||||||
copy.simulationStepperClass = this.simulationStepperClass;
|
copy.simulationStepperClass = this.simulationStepperClass;
|
||||||
copy.aerodynamicCalculatorClass = this.aerodynamicCalculatorClass;
|
copy.aerodynamicCalculatorClass = this.aerodynamicCalculatorClass;
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
} finally {
|
} finally {
|
||||||
mutex.unlock("duplicateSimulation");
|
mutex.unlock("duplicateSimulation");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addChangeListener(EventListener listener) {
|
public void addChangeListener(EventListener listener) {
|
||||||
mutex.verify();
|
mutex.verify();
|
||||||
listeners.add(listener);
|
listeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeChangeListener(EventListener listener) {
|
public void removeChangeListener(EventListener listener) {
|
||||||
mutex.verify();
|
mutex.verify();
|
||||||
listeners.remove(listener);
|
listeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void fireChangeEvent() {
|
protected void fireChangeEvent() {
|
||||||
EventObject e = new EventObject(this);
|
EventObject e = new EventObject(this);
|
||||||
// Copy the list before iterating to prevent concurrent modification exceptions.
|
// Copy the list before iterating to prevent concurrent modification exceptions.
|
||||||
@ -448,14 +450,14 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private class ConditionListener implements StateChangeListener {
|
private class ConditionListener implements StateChangeListener {
|
||||||
|
|
||||||
private Status oldStatus = null;
|
private Status oldStatus = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stateChanged(EventObject e) {
|
public void stateChanged(EventObject e) {
|
||||||
if (getStatus() != oldStatus) {
|
if (getStatus() != oldStatus) {
|
||||||
|
@ -94,8 +94,10 @@ public class RocksimSaver extends RocketSaver {
|
|||||||
|
|
||||||
MassCalculator massCalc = new BasicMassCalculator();
|
MassCalculator massCalc = new BasicMassCalculator();
|
||||||
|
|
||||||
final double cg = massCalc.getCG(new Configuration(rocket), MassCalculator.MassCalcType.NO_MOTORS).x *
|
final Configuration configuration = new Configuration(rocket);
|
||||||
|
final double cg = massCalc.getCG(configuration, MassCalculator.MassCalcType.NO_MOTORS).x *
|
||||||
RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH;
|
RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH;
|
||||||
|
configuration.release();
|
||||||
int stageCount = rocket.getStageCount();
|
int stageCount = rocket.getStageCount();
|
||||||
if (stageCount == 3) {
|
if (stageCount == 3) {
|
||||||
result.setStage321CG(cg);
|
result.setStage321CG(cg);
|
||||||
|
@ -74,33 +74,33 @@ import com.itextpdf.text.pdf.PdfWriter;
|
|||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public class DesignReport {
|
public class DesignReport {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final LogHelper log = Application.getLogger();
|
private static final LogHelper log = Application.getLogger();
|
||||||
public static final double SCALE_FUDGE_FACTOR = 0.4d;
|
public static final double SCALE_FUDGE_FACTOR = 0.4d;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The OR Document.
|
* The OR Document.
|
||||||
*/
|
*/
|
||||||
private OpenRocketDocument rocketDocument;
|
private OpenRocketDocument rocketDocument;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A panel used for rendering of the design diagram.
|
* A panel used for rendering of the design diagram.
|
||||||
*/
|
*/
|
||||||
final RocketPanel panel;
|
final RocketPanel panel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The iText document.
|
* The iText document.
|
||||||
*/
|
*/
|
||||||
protected Document document;
|
protected Document document;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The figure rotation.
|
* The figure rotation.
|
||||||
*/
|
*/
|
||||||
private double rotation = 0d;
|
private double rotation = 0d;
|
||||||
|
|
||||||
/** The displayed strings. */
|
/** The displayed strings. */
|
||||||
private static final String STAGES = "Stages: ";
|
private static final String STAGES = "Stages: ";
|
||||||
private static final String MASS_WITH_MOTORS = "Mass (with motors): ";
|
private static final String MASS_WITH_MOTORS = "Mass (with motors): ";
|
||||||
@ -126,7 +126,7 @@ public class DesignReport {
|
|||||||
private static final String LANDING_VELOCITY = "Landing Velocity";
|
private static final String LANDING_VELOCITY = "Landing Velocity";
|
||||||
private static final String ROCKET_DESIGN = "Rocket Design";
|
private static final String ROCKET_DESIGN = "Rocket Design";
|
||||||
private static final double GRAVITY_CONSTANT = 9.80665d;
|
private static final double GRAVITY_CONSTANT = 9.80665d;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
@ -140,7 +140,7 @@ public class DesignReport {
|
|||||||
panel = new RocketPanel(rocketDocument);
|
panel = new RocketPanel(rocketDocument);
|
||||||
rotation = figureRotation;
|
rotation = figureRotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main entry point. Prints the rocket drawing and design data.
|
* Main entry point. Prints the rocket drawing and design data.
|
||||||
*
|
*
|
||||||
@ -153,23 +153,23 @@ public class DesignReport {
|
|||||||
com.itextpdf.text.Rectangle pageSize = document.getPageSize();
|
com.itextpdf.text.Rectangle pageSize = document.getPageSize();
|
||||||
int pageImageableWidth = (int) pageSize.getWidth() - (int) pageSize.getBorderWidth() * 2;
|
int pageImageableWidth = (int) pageSize.getWidth() - (int) pageSize.getBorderWidth() * 2;
|
||||||
int pageImageableHeight = (int) pageSize.getHeight() / 2 - (int) pageSize.getBorderWidthTop();
|
int pageImageableHeight = (int) pageSize.getHeight() / 2 - (int) pageSize.getBorderWidthTop();
|
||||||
|
|
||||||
PrintUtilities.addText(document, PrintUtilities.BIG_BOLD, ROCKET_DESIGN);
|
PrintUtilities.addText(document, PrintUtilities.BIG_BOLD, ROCKET_DESIGN);
|
||||||
|
|
||||||
Rocket rocket = rocketDocument.getRocket();
|
Rocket rocket = rocketDocument.getRocket();
|
||||||
final Configuration configuration = rocket.getDefaultConfiguration().clone();
|
final Configuration configuration = rocket.getDefaultConfiguration().clone();
|
||||||
configuration.setAllStages();
|
configuration.setAllStages();
|
||||||
PdfContentByte canvas = writer.getDirectContent();
|
PdfContentByte canvas = writer.getDirectContent();
|
||||||
|
|
||||||
final PrintFigure figure = new PrintFigure(configuration);
|
final PrintFigure figure = new PrintFigure(configuration);
|
||||||
figure.setRotation(rotation);
|
figure.setRotation(rotation);
|
||||||
|
|
||||||
FigureElement cp = panel.getExtraCP();
|
FigureElement cp = panel.getExtraCP();
|
||||||
FigureElement cg = panel.getExtraCG();
|
FigureElement cg = panel.getExtraCG();
|
||||||
RocketInfo text = panel.getExtraText();
|
RocketInfo text = panel.getExtraText();
|
||||||
|
|
||||||
double scale = paintRocketDiagram(pageImageableWidth, pageImageableHeight, canvas, figure, cp, cg);
|
double scale = paintRocketDiagram(pageImageableWidth, pageImageableHeight, canvas, figure, cp, cg);
|
||||||
|
|
||||||
canvas.beginText();
|
canvas.beginText();
|
||||||
canvas.setFontAndSize(ITextHelper.getBaseFont(), PrintUtilities.NORMAL_FONT_SIZE);
|
canvas.setFontAndSize(ITextHelper.getBaseFont(), PrintUtilities.NORMAL_FONT_SIZE);
|
||||||
int figHeightPts = (int) (PrintUnit.METERS.toPoints(figure.getFigureHeight()) * 0.4 * (scale / PrintUnit.METERS
|
int figHeightPts = (int) (PrintUnit.METERS.toPoints(figure.getFigureHeight()) * 0.4 * (scale / PrintUnit.METERS
|
||||||
@ -177,15 +177,15 @@ public class DesignReport {
|
|||||||
final int diagramHeight = pageImageableHeight * 2 - 70 - (figHeightPts);
|
final int diagramHeight = pageImageableHeight * 2 - 70 - (figHeightPts);
|
||||||
canvas.moveText(document.leftMargin() + pageSize.getBorderWidthLeft(), diagramHeight);
|
canvas.moveText(document.leftMargin() + pageSize.getBorderWidthLeft(), diagramHeight);
|
||||||
canvas.moveTextWithLeading(0, -16);
|
canvas.moveTextWithLeading(0, -16);
|
||||||
|
|
||||||
float initialY = canvas.getYTLM();
|
float initialY = canvas.getYTLM();
|
||||||
|
|
||||||
canvas.showText(rocketDocument.getRocket().getName());
|
canvas.showText(rocketDocument.getRocket().getName());
|
||||||
|
|
||||||
canvas.newlineShowText(STAGES);
|
canvas.newlineShowText(STAGES);
|
||||||
canvas.showText("" + rocket.getStageCount());
|
canvas.showText("" + rocket.getStageCount());
|
||||||
|
|
||||||
|
|
||||||
if (configuration.hasMotors()) {
|
if (configuration.hasMotors()) {
|
||||||
if (configuration.getStageCount() > 1) {
|
if (configuration.getStageCount() > 1) {
|
||||||
canvas.newlineShowText(MASS_WITH_MOTORS);
|
canvas.newlineShowText(MASS_WITH_MOTORS);
|
||||||
@ -196,29 +196,29 @@ public class DesignReport {
|
|||||||
canvas.newlineShowText(MASS_EMPTY);
|
canvas.newlineShowText(MASS_EMPTY);
|
||||||
}
|
}
|
||||||
canvas.showText(text.getMass(UnitGroup.UNITS_MASS.getDefaultUnit()));
|
canvas.showText(text.getMass(UnitGroup.UNITS_MASS.getDefaultUnit()));
|
||||||
|
|
||||||
canvas.newlineShowText(STABILITY);
|
canvas.newlineShowText(STABILITY);
|
||||||
canvas.showText(text.getStability());
|
canvas.showText(text.getStability());
|
||||||
|
|
||||||
canvas.newlineShowText(CG);
|
canvas.newlineShowText(CG);
|
||||||
canvas.showText(text.getCg());
|
canvas.showText(text.getCg());
|
||||||
|
|
||||||
canvas.newlineShowText(CP);
|
canvas.newlineShowText(CP);
|
||||||
canvas.showText(text.getCp());
|
canvas.showText(text.getCp());
|
||||||
canvas.endText();
|
canvas.endText();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//Move the internal pointer of the document below that of what was just written using the direct byte buffer.
|
//Move the internal pointer of the document below that of what was just written using the direct byte buffer.
|
||||||
Paragraph paragraph = new Paragraph();
|
Paragraph paragraph = new Paragraph();
|
||||||
float finalY = canvas.getYTLM();
|
float finalY = canvas.getYTLM();
|
||||||
int heightOfDiagramAndText = (int) (pageSize.getHeight() - (finalY - initialY + diagramHeight));
|
int heightOfDiagramAndText = (int) (pageSize.getHeight() - (finalY - initialY + diagramHeight));
|
||||||
|
|
||||||
paragraph.setSpacingAfter(heightOfDiagramAndText);
|
paragraph.setSpacingAfter(heightOfDiagramAndText);
|
||||||
document.add(paragraph);
|
document.add(paragraph);
|
||||||
|
|
||||||
String[] motorIds = rocket.getMotorConfigurationIDs();
|
String[] motorIds = rocket.getMotorConfigurationIDs();
|
||||||
List<Simulation> simulations = rocketDocument.getSimulations();
|
List<Simulation> simulations = rocketDocument.getSimulations();
|
||||||
|
|
||||||
for (int j = 0; j < motorIds.length; j++) {
|
for (int j = 0; j < motorIds.length; j++) {
|
||||||
String motorId = motorIds[j];
|
String motorId = motorIds[j];
|
||||||
if (motorId != null) {
|
if (motorId != null) {
|
||||||
@ -242,8 +242,8 @@ public class DesignReport {
|
|||||||
log.error("Could not modify document.", e);
|
log.error("Could not modify document.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Paint a diagram of the rocket into the PDF document.
|
* Paint a diagram of the rocket into the PDF document.
|
||||||
*
|
*
|
||||||
@ -264,7 +264,7 @@ public class DesignReport {
|
|||||||
theFigure.addRelativeExtra(theCp);
|
theFigure.addRelativeExtra(theCp);
|
||||||
theFigure.addRelativeExtra(theCg);
|
theFigure.addRelativeExtra(theCg);
|
||||||
theFigure.updateFigure();
|
theFigure.updateFigure();
|
||||||
|
|
||||||
double scale =
|
double scale =
|
||||||
(thePageImageableWidth * 2.2) / theFigure.getFigureWidth();
|
(thePageImageableWidth * 2.2) / theFigure.getFigureWidth();
|
||||||
theFigure.setScale(scale);
|
theFigure.setScale(scale);
|
||||||
@ -273,7 +273,7 @@ public class DesignReport {
|
|||||||
*/
|
*/
|
||||||
theFigure.setSize(thePageImageableWidth, thePageImageableHeight);
|
theFigure.setSize(thePageImageableWidth, thePageImageableHeight);
|
||||||
theFigure.updateFigure();
|
theFigure.updateFigure();
|
||||||
|
|
||||||
final DefaultFontMapper mapper = new DefaultFontMapper();
|
final DefaultFontMapper mapper = new DefaultFontMapper();
|
||||||
Graphics2D g2d = theCanvas.createGraphics(thePageImageableWidth, thePageImageableHeight * 2, mapper);
|
Graphics2D g2d = theCanvas.createGraphics(thePageImageableWidth, thePageImageableHeight * 2, mapper);
|
||||||
final double halfFigureHeight = SCALE_FUDGE_FACTOR * theFigure.getFigureHeightPx() / 2;
|
final double halfFigureHeight = SCALE_FUDGE_FACTOR * theFigure.getFigureHeightPx() / 2;
|
||||||
@ -284,13 +284,13 @@ public class DesignReport {
|
|||||||
y += (int) halfFigureHeight;
|
y += (int) halfFigureHeight;
|
||||||
}
|
}
|
||||||
g2d.translate(20, y);
|
g2d.translate(20, y);
|
||||||
|
|
||||||
g2d.scale(SCALE_FUDGE_FACTOR, SCALE_FUDGE_FACTOR);
|
g2d.scale(SCALE_FUDGE_FACTOR, SCALE_FUDGE_FACTOR);
|
||||||
theFigure.paint(g2d);
|
theFigure.paint(g2d);
|
||||||
g2d.dispose();
|
g2d.dispose();
|
||||||
return scale;
|
return scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the motor data for a motor configuration to the table.
|
* Add the motor data for a motor configuration to the table.
|
||||||
*
|
*
|
||||||
@ -299,11 +299,11 @@ public class DesignReport {
|
|||||||
* @param parent the parent to which the motor data will be added
|
* @param parent the parent to which the motor data will be added
|
||||||
*/
|
*/
|
||||||
private void addMotorData(Rocket rocket, String motorId, final PdfPTable parent) {
|
private void addMotorData(Rocket rocket, String motorId, final PdfPTable parent) {
|
||||||
|
|
||||||
PdfPTable motorTable = new PdfPTable(8);
|
PdfPTable motorTable = new PdfPTable(8);
|
||||||
motorTable.setWidthPercentage(68);
|
motorTable.setWidthPercentage(68);
|
||||||
motorTable.setHorizontalAlignment(Element.ALIGN_LEFT);
|
motorTable.setHorizontalAlignment(Element.ALIGN_LEFT);
|
||||||
|
|
||||||
final PdfPCell motorCell = ITextHelper.createCell(MOTOR, PdfPCell.BOTTOM, PrintUtilities.SMALL);
|
final PdfPCell motorCell = ITextHelper.createCell(MOTOR, PdfPCell.BOTTOM, PrintUtilities.SMALL);
|
||||||
final int mPad = 10;
|
final int mPad = 10;
|
||||||
motorCell.setPaddingLeft(mPad);
|
motorCell.setPaddingLeft(mPad);
|
||||||
@ -315,25 +315,25 @@ public class DesignReport {
|
|||||||
motorTable.addCell(ITextHelper.createCell(THRUST_TO_WT, PdfPCell.BOTTOM, PrintUtilities.SMALL));
|
motorTable.addCell(ITextHelper.createCell(THRUST_TO_WT, PdfPCell.BOTTOM, PrintUtilities.SMALL));
|
||||||
motorTable.addCell(ITextHelper.createCell(PROPELLANT_WT, PdfPCell.BOTTOM, PrintUtilities.SMALL));
|
motorTable.addCell(ITextHelper.createCell(PROPELLANT_WT, PdfPCell.BOTTOM, PrintUtilities.SMALL));
|
||||||
motorTable.addCell(ITextHelper.createCell(SIZE, PdfPCell.BOTTOM, PrintUtilities.SMALL));
|
motorTable.addCell(ITextHelper.createCell(SIZE, PdfPCell.BOTTOM, PrintUtilities.SMALL));
|
||||||
|
|
||||||
DecimalFormat ttwFormat = new DecimalFormat("0.00");
|
DecimalFormat ttwFormat = new DecimalFormat("0.00");
|
||||||
|
|
||||||
MassCalculator massCalc = new BasicMassCalculator();
|
MassCalculator massCalc = new BasicMassCalculator();
|
||||||
|
|
||||||
Configuration config = new Configuration(rocket);
|
Configuration config = new Configuration(rocket);
|
||||||
config.setMotorConfigurationID(motorId);
|
config.setMotorConfigurationID(motorId);
|
||||||
|
|
||||||
int totalMotorCount = 0;
|
int totalMotorCount = 0;
|
||||||
double totalPropMass = 0;
|
double totalPropMass = 0;
|
||||||
double totalImpulse = 0;
|
double totalImpulse = 0;
|
||||||
double totalTTW = 0;
|
double totalTTW = 0;
|
||||||
|
|
||||||
int stage = 0;
|
int stage = 0;
|
||||||
double stageMass = 0;
|
double stageMass = 0;
|
||||||
|
|
||||||
boolean topBorder = false;
|
boolean topBorder = false;
|
||||||
for (RocketComponent c : rocket) {
|
for (RocketComponent c : rocket) {
|
||||||
|
|
||||||
if (c instanceof Stage) {
|
if (c instanceof Stage) {
|
||||||
config.setToStage(stage);
|
config.setToStage(stage);
|
||||||
stage++;
|
stage++;
|
||||||
@ -342,26 +342,26 @@ public class DesignReport {
|
|||||||
totalTTW = 0;
|
totalTTW = 0;
|
||||||
topBorder = true;
|
topBorder = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c instanceof MotorMount && ((MotorMount) c).isMotorMount()) {
|
if (c instanceof MotorMount && ((MotorMount) c).isMotorMount()) {
|
||||||
MotorMount mount = (MotorMount) c;
|
MotorMount mount = (MotorMount) c;
|
||||||
|
|
||||||
if (mount.isMotorMount() && mount.getMotor(motorId) != null) {
|
if (mount.isMotorMount() && mount.getMotor(motorId) != null) {
|
||||||
Motor motor = mount.getMotor(motorId);
|
Motor motor = mount.getMotor(motorId);
|
||||||
int motorCount = c.toAbsolute(Coordinate.NUL).length;
|
int motorCount = c.toAbsolute(Coordinate.NUL).length;
|
||||||
|
|
||||||
|
|
||||||
int border = Rectangle.NO_BORDER;
|
int border = Rectangle.NO_BORDER;
|
||||||
if (topBorder) {
|
if (topBorder) {
|
||||||
border = Rectangle.TOP;
|
border = Rectangle.TOP;
|
||||||
topBorder = false;
|
topBorder = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String name = motor.getDesignation();
|
String name = motor.getDesignation();
|
||||||
if (motorCount > 1) {
|
if (motorCount > 1) {
|
||||||
name += " (" + Chars.TIMES + motorCount + ")";
|
name += " (" + Chars.TIMES + motorCount + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
final PdfPCell motorVCell = ITextHelper.createCell(name, border);
|
final PdfPCell motorVCell = ITextHelper.createCell(name, border);
|
||||||
motorVCell.setPaddingLeft(mPad);
|
motorVCell.setPaddingLeft(mPad);
|
||||||
motorTable.addCell(motorVCell);
|
motorTable.addCell(motorVCell);
|
||||||
@ -373,21 +373,21 @@ public class DesignReport {
|
|||||||
UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit(motor.getMaxThrustEstimate()), border));
|
UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit(motor.getMaxThrustEstimate()), border));
|
||||||
motorTable.addCell(ITextHelper.createCell(
|
motorTable.addCell(ITextHelper.createCell(
|
||||||
UnitGroup.UNITS_IMPULSE.getDefaultUnit().toStringUnit(motor.getTotalImpulseEstimate()), border));
|
UnitGroup.UNITS_IMPULSE.getDefaultUnit().toStringUnit(motor.getTotalImpulseEstimate()), border));
|
||||||
|
|
||||||
double ttw = motor.getAverageThrustEstimate() / (stageMass * GRAVITY_CONSTANT);
|
double ttw = motor.getAverageThrustEstimate() / (stageMass * GRAVITY_CONSTANT);
|
||||||
motorTable.addCell(ITextHelper.createCell(
|
motorTable.addCell(ITextHelper.createCell(
|
||||||
ttwFormat.format(ttw) + ":1", border));
|
ttwFormat.format(ttw) + ":1", border));
|
||||||
|
|
||||||
double propMass = (motor.getLaunchCG().weight - motor.getEmptyCG().weight);
|
double propMass = (motor.getLaunchCG().weight - motor.getEmptyCG().weight);
|
||||||
motorTable.addCell(ITextHelper.createCell(
|
motorTable.addCell(ITextHelper.createCell(
|
||||||
UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(propMass), border));
|
UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(propMass), border));
|
||||||
|
|
||||||
final Unit motorUnit = UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit();
|
final Unit motorUnit = UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit();
|
||||||
motorTable.addCell(ITextHelper.createCell(motorUnit.toString(motor.getDiameter()) +
|
motorTable.addCell(ITextHelper.createCell(motorUnit.toString(motor.getDiameter()) +
|
||||||
"/" +
|
"/" +
|
||||||
motorUnit.toString(motor.getLength()) + " " +
|
motorUnit.toString(motor.getLength()) + " " +
|
||||||
motorUnit.toString(), border));
|
motorUnit.toString(), border));
|
||||||
|
|
||||||
// Sum up total count
|
// Sum up total count
|
||||||
totalMotorCount += motorCount;
|
totalMotorCount += motorCount;
|
||||||
totalPropMass += propMass * motorCount;
|
totalPropMass += propMass * motorCount;
|
||||||
@ -396,7 +396,7 @@ public class DesignReport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalMotorCount > 1) {
|
if (totalMotorCount > 1) {
|
||||||
int border = Rectangle.TOP;
|
int border = Rectangle.TOP;
|
||||||
final PdfPCell motorVCell = ITextHelper.createCell("Total:", border);
|
final PdfPCell motorVCell = ITextHelper.createCell("Total:", border);
|
||||||
@ -412,16 +412,17 @@ public class DesignReport {
|
|||||||
motorTable.addCell(ITextHelper.createCell(
|
motorTable.addCell(ITextHelper.createCell(
|
||||||
UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(totalPropMass), border));
|
UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(totalPropMass), border));
|
||||||
motorTable.addCell(ITextHelper.createCell("", border));
|
motorTable.addCell(ITextHelper.createCell("", border));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PdfPCell c = new PdfPCell(motorTable);
|
PdfPCell c = new PdfPCell(motorTable);
|
||||||
c.setBorder(PdfPCell.LEFT);
|
c.setBorder(PdfPCell.LEFT);
|
||||||
c.setBorderWidthTop(0f);
|
c.setBorderWidthTop(0f);
|
||||||
parent.addCell(c);
|
parent.addCell(c);
|
||||||
|
config.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the flight data for a simulation configuration to the table.
|
* Add the flight data for a simulation configuration to the table.
|
||||||
*
|
*
|
||||||
@ -432,47 +433,47 @@ public class DesignReport {
|
|||||||
* @param leading the number of points for the leading
|
* @param leading the number of points for the leading
|
||||||
*/
|
*/
|
||||||
private void addFlightData(final FlightData flight, final Rocket theRocket, final String motorId, final PdfPTable parent, int leading) {
|
private void addFlightData(final FlightData flight, final Rocket theRocket, final String motorId, final PdfPTable parent, int leading) {
|
||||||
|
|
||||||
// Output the flight data
|
// Output the flight data
|
||||||
if (flight != null) {
|
if (flight != null) {
|
||||||
try {
|
try {
|
||||||
final Unit distanceUnit = UnitGroup.UNITS_DISTANCE.getDefaultUnit();
|
final Unit distanceUnit = UnitGroup.UNITS_DISTANCE.getDefaultUnit();
|
||||||
final Unit velocityUnit = UnitGroup.UNITS_VELOCITY.getDefaultUnit();
|
final Unit velocityUnit = UnitGroup.UNITS_VELOCITY.getDefaultUnit();
|
||||||
final Unit flightTimeUnit = UnitGroup.UNITS_FLIGHT_TIME.getDefaultUnit();
|
final Unit flightTimeUnit = UnitGroup.UNITS_FLIGHT_TIME.getDefaultUnit();
|
||||||
|
|
||||||
PdfPTable labelTable = new PdfPTable(2);
|
PdfPTable labelTable = new PdfPTable(2);
|
||||||
labelTable.setWidths(new int[] { 3, 2 });
|
labelTable.setWidths(new int[] { 3, 2 });
|
||||||
final Paragraph chunk = ITextHelper.createParagraph(stripBrackets(
|
final Paragraph chunk = ITextHelper.createParagraph(stripBrackets(
|
||||||
theRocket.getMotorConfigurationNameOrDescription(motorId)), PrintUtilities.BOLD);
|
theRocket.getMotorConfigurationNameOrDescription(motorId)), PrintUtilities.BOLD);
|
||||||
chunk.setLeading(leading);
|
chunk.setLeading(leading);
|
||||||
chunk.setSpacingAfter(3f);
|
chunk.setSpacingAfter(3f);
|
||||||
|
|
||||||
document.add(chunk);
|
document.add(chunk);
|
||||||
|
|
||||||
final PdfPCell cell = ITextHelper.createCell(ALTITUDE, 2, 2);
|
final PdfPCell cell = ITextHelper.createCell(ALTITUDE, 2, 2);
|
||||||
cell.setUseBorderPadding(false);
|
cell.setUseBorderPadding(false);
|
||||||
cell.setBorderWidthTop(0f);
|
cell.setBorderWidthTop(0f);
|
||||||
labelTable.addCell(cell);
|
labelTable.addCell(cell);
|
||||||
labelTable.addCell(ITextHelper.createCell(distanceUnit.toStringUnit(flight.getMaxAltitude()), 2, 2));
|
labelTable.addCell(ITextHelper.createCell(distanceUnit.toStringUnit(flight.getMaxAltitude()), 2, 2));
|
||||||
|
|
||||||
labelTable.addCell(ITextHelper.createCell(FLIGHT_TIME, 2, 2));
|
labelTable.addCell(ITextHelper.createCell(FLIGHT_TIME, 2, 2));
|
||||||
labelTable.addCell(ITextHelper.createCell(flightTimeUnit.toStringUnit(flight.getFlightTime()), 2, 2));
|
labelTable.addCell(ITextHelper.createCell(flightTimeUnit.toStringUnit(flight.getFlightTime()), 2, 2));
|
||||||
|
|
||||||
labelTable.addCell(ITextHelper.createCell(TIME_TO_APOGEE, 2, 2));
|
labelTable.addCell(ITextHelper.createCell(TIME_TO_APOGEE, 2, 2));
|
||||||
labelTable.addCell(ITextHelper.createCell(flightTimeUnit.toStringUnit(flight.getTimeToApogee()), 2, 2));
|
labelTable.addCell(ITextHelper.createCell(flightTimeUnit.toStringUnit(flight.getTimeToApogee()), 2, 2));
|
||||||
|
|
||||||
labelTable.addCell(ITextHelper.createCell(VELOCITY_OFF_PAD, 2, 2));
|
labelTable.addCell(ITextHelper.createCell(VELOCITY_OFF_PAD, 2, 2));
|
||||||
labelTable.addCell(ITextHelper.createCell(velocityUnit.toStringUnit(flight.getLaunchRodVelocity()), 2, 2));
|
labelTable.addCell(ITextHelper.createCell(velocityUnit.toStringUnit(flight.getLaunchRodVelocity()), 2, 2));
|
||||||
|
|
||||||
labelTable.addCell(ITextHelper.createCell(MAX_VELOCITY, 2, 2));
|
labelTable.addCell(ITextHelper.createCell(MAX_VELOCITY, 2, 2));
|
||||||
labelTable.addCell(ITextHelper.createCell(velocityUnit.toStringUnit(flight.getMaxVelocity()), 2, 2));
|
labelTable.addCell(ITextHelper.createCell(velocityUnit.toStringUnit(flight.getMaxVelocity()), 2, 2));
|
||||||
|
|
||||||
labelTable.addCell(ITextHelper.createCell(DEPLOYMENT_VELOCITY, 2, 2));
|
labelTable.addCell(ITextHelper.createCell(DEPLOYMENT_VELOCITY, 2, 2));
|
||||||
labelTable.addCell(ITextHelper.createCell(velocityUnit.toStringUnit(flight.getDeploymentVelocity()), 2, 2));
|
labelTable.addCell(ITextHelper.createCell(velocityUnit.toStringUnit(flight.getDeploymentVelocity()), 2, 2));
|
||||||
|
|
||||||
labelTable.addCell(ITextHelper.createCell(LANDING_VELOCITY, 2, 2));
|
labelTable.addCell(ITextHelper.createCell(LANDING_VELOCITY, 2, 2));
|
||||||
labelTable.addCell(ITextHelper.createCell(velocityUnit.toStringUnit(flight.getGroundHitVelocity()), 2, 2));
|
labelTable.addCell(ITextHelper.createCell(velocityUnit.toStringUnit(flight.getGroundHitVelocity()), 2, 2));
|
||||||
|
|
||||||
//Add the table to the parent; have to wrap it in a cell
|
//Add the table to the parent; have to wrap it in a cell
|
||||||
PdfPCell c = new PdfPCell(labelTable);
|
PdfPCell c = new PdfPCell(labelTable);
|
||||||
c.setBorder(PdfPCell.RIGHT);
|
c.setBorder(PdfPCell.RIGHT);
|
||||||
@ -484,7 +485,7 @@ public class DesignReport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locate the simulation based on the motor id. Copy the simulation and execute it, then return the resulting
|
* Locate the simulation based on the motor id. Copy the simulation and execute it, then return the resulting
|
||||||
* flight data.
|
* flight data.
|
||||||
@ -512,7 +513,7 @@ public class DesignReport {
|
|||||||
}
|
}
|
||||||
return flight;
|
return flight;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strip [] brackets from a string.
|
* Strip [] brackets from a string.
|
||||||
*
|
*
|
||||||
@ -523,7 +524,7 @@ public class DesignReport {
|
|||||||
private String stripBrackets(String target) {
|
private String stripBrackets(String target) {
|
||||||
return stripLeftBracket(stripRightBracket(target));
|
return stripLeftBracket(stripRightBracket(target));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strip [ from a string.
|
* Strip [ from a string.
|
||||||
*
|
*
|
||||||
@ -534,7 +535,7 @@ public class DesignReport {
|
|||||||
private String stripLeftBracket(String target) {
|
private String stripLeftBracket(String target) {
|
||||||
return target.replace("[", "");
|
return target.replace("[", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strip ] from a string.
|
* Strip ] from a string.
|
||||||
*
|
*
|
||||||
@ -545,5 +546,5 @@ public class DesignReport {
|
|||||||
private String stripRightBracket(String target) {
|
private String stripRightBracket(String target) {
|
||||||
return target.replace("]", "");
|
return target.replace("]", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,53 +31,53 @@ import net.sf.openrocket.util.Quaternion;
|
|||||||
|
|
||||||
|
|
||||||
public class BasicEventSimulationEngine implements SimulationEngine {
|
public class BasicEventSimulationEngine implements SimulationEngine {
|
||||||
|
|
||||||
private static final Translator trans = Application.getTranslator();
|
private static final Translator trans = Application.getTranslator();
|
||||||
private static final LogHelper log = Application.getLogger();
|
private static final LogHelper log = Application.getLogger();
|
||||||
|
|
||||||
// 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 currentStepper;
|
private SimulationStepper currentStepper;
|
||||||
|
|
||||||
private SimulationStatus status;
|
private SimulationStatus status;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FlightData simulate(SimulationConditions simulationConditions) throws SimulationException {
|
public FlightData simulate(SimulationConditions simulationConditions) throws SimulationException {
|
||||||
Set<MotorId> motorBurntOut = new HashSet<MotorId>();
|
Set<MotorId> motorBurntOut = new HashSet<MotorId>();
|
||||||
|
|
||||||
// Set up flight data
|
// Set up flight data
|
||||||
FlightData flightData = new FlightData();
|
FlightData flightData = new FlightData();
|
||||||
|
|
||||||
// Set up rocket configuration
|
// Set up rocket configuration
|
||||||
Configuration configuration = setupConfiguration(simulationConditions);
|
Configuration configuration = setupConfiguration(simulationConditions);
|
||||||
MotorInstanceConfiguration motorConfiguration = setupMotorConfiguration(configuration);
|
MotorInstanceConfiguration motorConfiguration = setupMotorConfiguration(configuration);
|
||||||
if (motorConfiguration.getMotorIDs().isEmpty()) {
|
if (motorConfiguration.getMotorIDs().isEmpty()) {
|
||||||
throw new MotorIgnitionException("No motors defined in the simulation.");
|
throw new MotorIgnitionException("No motors defined in the simulation.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the simulation
|
// Initialize the simulation
|
||||||
currentStepper = flightStepper;
|
currentStepper = flightStepper;
|
||||||
status = initialStatus(configuration, motorConfiguration, simulationConditions, flightData);
|
status = initialStatus(configuration, motorConfiguration, simulationConditions, flightData);
|
||||||
status = currentStepper.initialize(status);
|
status = currentStepper.initialize(status);
|
||||||
|
|
||||||
|
|
||||||
SimulationListenerHelper.fireStartSimulation(status);
|
SimulationListenerHelper.fireStartSimulation(status);
|
||||||
// Get originating position (in case listener has modified launch position)
|
// Get originating position (in case listener has modified launch position)
|
||||||
Coordinate origin = status.getRocketPosition();
|
Coordinate origin = status.getRocketPosition();
|
||||||
Coordinate originVelocity = status.getRocketVelocity();
|
Coordinate originVelocity = status.getRocketVelocity();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
double maxAlt = Double.NEGATIVE_INFINITY;
|
double maxAlt = Double.NEGATIVE_INFINITY;
|
||||||
|
|
||||||
// Start the simulation
|
// Start the simulation
|
||||||
while (handleEvents()) {
|
while (handleEvents()) {
|
||||||
|
|
||||||
// Take the step
|
// Take the step
|
||||||
double oldAlt = status.getRocketPosition().z;
|
double oldAlt = status.getRocketPosition().z;
|
||||||
|
|
||||||
if (SimulationListenerHelper.firePreStep(status)) {
|
if (SimulationListenerHelper.firePreStep(status)) {
|
||||||
// Step at most to the next event
|
// Step at most to the next event
|
||||||
double maxStepTime = Double.MAX_VALUE;
|
double maxStepTime = Double.MAX_VALUE;
|
||||||
@ -89,27 +89,27 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
currentStepper.step(status, maxStepTime);
|
currentStepper.step(status, maxStepTime);
|
||||||
}
|
}
|
||||||
SimulationListenerHelper.firePostStep(status);
|
SimulationListenerHelper.firePostStep(status);
|
||||||
|
|
||||||
|
|
||||||
// Check for NaN values in the simulation status
|
// Check for NaN values in the simulation status
|
||||||
checkNaN();
|
checkNaN();
|
||||||
|
|
||||||
// Add altitude event
|
// Add altitude event
|
||||||
addEvent(new FlightEvent(FlightEvent.Type.ALTITUDE, status.getSimulationTime(),
|
addEvent(new FlightEvent(FlightEvent.Type.ALTITUDE, status.getSimulationTime(),
|
||||||
status.getConfiguration().getRocket(),
|
status.getConfiguration().getRocket(),
|
||||||
new Pair<Double, Double>(oldAlt, status.getRocketPosition().z)));
|
new Pair<Double, Double>(oldAlt, status.getRocketPosition().z)));
|
||||||
|
|
||||||
if (status.getRocketPosition().z > maxAlt) {
|
if (status.getRocketPosition().z > maxAlt) {
|
||||||
maxAlt = status.getRocketPosition().z;
|
maxAlt = status.getRocketPosition().z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Position relative to start location
|
// Position relative to start location
|
||||||
Coordinate relativePosition = status.getRocketPosition().sub(origin);
|
Coordinate relativePosition = status.getRocketPosition().sub(origin);
|
||||||
|
|
||||||
// Add appropriate events
|
// Add appropriate events
|
||||||
if (!status.isLiftoff()) {
|
if (!status.isLiftoff()) {
|
||||||
|
|
||||||
// Avoid sinking into ground before liftoff
|
// Avoid sinking into ground before liftoff
|
||||||
if (relativePosition.z < 0) {
|
if (relativePosition.z < 0) {
|
||||||
status.setRocketPosition(origin);
|
status.setRocketPosition(origin);
|
||||||
@ -119,32 +119,32 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
if (relativePosition.z > 0.02) {
|
if (relativePosition.z > 0.02) {
|
||||||
addEvent(new FlightEvent(FlightEvent.Type.LIFTOFF, status.getSimulationTime()));
|
addEvent(new FlightEvent(FlightEvent.Type.LIFTOFF, status.getSimulationTime()));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Check ground hit after liftoff
|
// Check ground hit after liftoff
|
||||||
if (status.getRocketPosition().z < 0) {
|
if (status.getRocketPosition().z < 0) {
|
||||||
status.setRocketPosition(status.getRocketPosition().setZ(0));
|
status.setRocketPosition(status.getRocketPosition().setZ(0));
|
||||||
addEvent(new FlightEvent(FlightEvent.Type.GROUND_HIT, status.getSimulationTime()));
|
addEvent(new FlightEvent(FlightEvent.Type.GROUND_HIT, status.getSimulationTime()));
|
||||||
addEvent(new FlightEvent(FlightEvent.Type.SIMULATION_END, status.getSimulationTime()));
|
addEvent(new FlightEvent(FlightEvent.Type.SIMULATION_END, status.getSimulationTime()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for launch guide clearance
|
// Check for launch guide clearance
|
||||||
if (!status.isLaunchRodCleared() &&
|
if (!status.isLaunchRodCleared() &&
|
||||||
relativePosition.length() > status.getSimulationConditions().getLaunchRodLength()) {
|
relativePosition.length() > status.getSimulationConditions().getLaunchRodLength()) {
|
||||||
addEvent(new FlightEvent(FlightEvent.Type.LAUNCHROD, status.getSimulationTime(), null));
|
addEvent(new FlightEvent(FlightEvent.Type.LAUNCHROD, status.getSimulationTime(), null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Check for apogee
|
// Check for apogee
|
||||||
if (!status.isApogeeReached() && status.getRocketPosition().z < maxAlt - 0.01) {
|
if (!status.isApogeeReached() && status.getRocketPosition().z < maxAlt - 0.01) {
|
||||||
addEvent(new FlightEvent(FlightEvent.Type.APOGEE, status.getSimulationTime(),
|
addEvent(new FlightEvent(FlightEvent.Type.APOGEE, status.getSimulationTime(),
|
||||||
status.getConfiguration().getRocket()));
|
status.getConfiguration().getRocket()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Check for burnt out motors
|
// Check for burnt out motors
|
||||||
for (MotorId motorId : status.getMotorConfiguration().getMotorIDs()) {
|
for (MotorId motorId : status.getMotorConfiguration().getMotorIDs()) {
|
||||||
MotorInstance motor = status.getMotorConfiguration().getMotorInstance(motorId);
|
MotorInstance motor = status.getMotorConfiguration().getMotorInstance(motorId);
|
||||||
@ -153,58 +153,59 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
(RocketComponent) status.getMotorConfiguration().getMotorMount(motorId), motorId));
|
(RocketComponent) status.getMotorConfiguration().getMotorMount(motorId), motorId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (SimulationException e) {
|
} catch (SimulationException e) {
|
||||||
SimulationListenerHelper.fireEndSimulation(status, e);
|
SimulationListenerHelper.fireEndSimulation(status, e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
SimulationListenerHelper.fireEndSimulation(status, null);
|
SimulationListenerHelper.fireEndSimulation(status, null);
|
||||||
|
|
||||||
flightData.addBranch(status.getFlightData());
|
flightData.addBranch(status.getFlightData());
|
||||||
|
|
||||||
if (!flightData.getWarningSet().isEmpty()) {
|
if (!flightData.getWarningSet().isEmpty()) {
|
||||||
log.info("Warnings at the end of simulation: " + flightData.getWarningSet());
|
log.info("Warnings at the end of simulation: " + flightData.getWarningSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configuration.release();
|
||||||
// TODO: HIGH: Simulate branches
|
// TODO: HIGH: Simulate branches
|
||||||
return flightData;
|
return flightData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private SimulationStatus initialStatus(Configuration configuration,
|
private SimulationStatus initialStatus(Configuration configuration,
|
||||||
MotorInstanceConfiguration motorConfiguration,
|
MotorInstanceConfiguration motorConfiguration,
|
||||||
SimulationConditions simulationConditions, FlightData flightData) {
|
SimulationConditions simulationConditions, FlightData flightData) {
|
||||||
|
|
||||||
SimulationStatus init = new SimulationStatus();
|
SimulationStatus init = new SimulationStatus();
|
||||||
init.setSimulationConditions(simulationConditions);
|
init.setSimulationConditions(simulationConditions);
|
||||||
init.setConfiguration(configuration);
|
init.setConfiguration(configuration);
|
||||||
init.setMotorConfiguration(motorConfiguration);
|
init.setMotorConfiguration(motorConfiguration);
|
||||||
|
|
||||||
init.setSimulationTime(0);
|
init.setSimulationTime(0);
|
||||||
init.setPreviousTimeStep(simulationConditions.getTimeStep());
|
init.setPreviousTimeStep(simulationConditions.getTimeStep());
|
||||||
init.setRocketPosition(Coordinate.NUL);
|
init.setRocketPosition(Coordinate.NUL);
|
||||||
init.setRocketVelocity(Coordinate.NUL);
|
init.setRocketVelocity(Coordinate.NUL);
|
||||||
init.setRocketWorldPosition(simulationConditions.getLaunchSite());
|
init.setRocketWorldPosition(simulationConditions.getLaunchSite());
|
||||||
|
|
||||||
// Initialize to roll angle with least stability w.r.t. the wind
|
// Initialize to roll angle with least stability w.r.t. the wind
|
||||||
Quaternion o;
|
Quaternion o;
|
||||||
FlightConditions cond = new FlightConditions(configuration);
|
FlightConditions cond = new FlightConditions(configuration);
|
||||||
simulationConditions.getAerodynamicCalculator().getWorstCP(configuration, cond, null);
|
simulationConditions.getAerodynamicCalculator().getWorstCP(configuration, cond, null);
|
||||||
double angle = -cond.getTheta() - simulationConditions.getLaunchRodDirection();
|
double angle = -cond.getTheta() - simulationConditions.getLaunchRodDirection();
|
||||||
o = Quaternion.rotation(new Coordinate(0, 0, angle));
|
o = Quaternion.rotation(new Coordinate(0, 0, angle));
|
||||||
|
|
||||||
// Launch rod angle and direction
|
// Launch rod angle and direction
|
||||||
o = o.multiplyLeft(Quaternion.rotation(new Coordinate(0, simulationConditions.getLaunchRodAngle(), 0)));
|
o = o.multiplyLeft(Quaternion.rotation(new Coordinate(0, simulationConditions.getLaunchRodAngle(), 0)));
|
||||||
o = o.multiplyLeft(Quaternion.rotation(new Coordinate(0, 0, simulationConditions.getLaunchRodDirection())));
|
o = o.multiplyLeft(Quaternion.rotation(new Coordinate(0, 0, simulationConditions.getLaunchRodDirection())));
|
||||||
|
|
||||||
init.setRocketOrientationQuaternion(o);
|
init.setRocketOrientationQuaternion(o);
|
||||||
init.setRocketRotationVelocity(Coordinate.NUL);
|
init.setRocketRotationVelocity(Coordinate.NUL);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate the effective launch rod length taking into account launch lugs.
|
* Calculate the effective launch rod length taking into account launch lugs.
|
||||||
* If no lugs are found, assume a tower launcher of full length.
|
* If no lugs are found, assume a tower launcher of full length.
|
||||||
@ -230,29 +231,29 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
init.setEffectiveLaunchRodLength(length);
|
init.setEffectiveLaunchRodLength(length);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
init.setSimulationStartWallTime(System.nanoTime());
|
init.setSimulationStartWallTime(System.nanoTime());
|
||||||
|
|
||||||
init.setMotorIgnited(false);
|
init.setMotorIgnited(false);
|
||||||
init.setLiftoff(false);
|
init.setLiftoff(false);
|
||||||
init.setLaunchRodCleared(false);
|
init.setLaunchRodCleared(false);
|
||||||
init.setApogeeReached(false);
|
init.setApogeeReached(false);
|
||||||
|
|
||||||
init.getEventQueue().add(new FlightEvent(FlightEvent.Type.LAUNCH, 0, simulationConditions.getRocket()));
|
init.getEventQueue().add(new FlightEvent(FlightEvent.Type.LAUNCH, 0, simulationConditions.getRocket()));
|
||||||
|
|
||||||
init.setFlightData(new FlightDataBranch("MAIN", FlightDataType.TYPE_TIME));
|
init.setFlightData(new FlightDataBranch("MAIN", FlightDataType.TYPE_TIME));
|
||||||
init.setWarnings(flightData.getWarningSet());
|
init.setWarnings(flightData.getWarningSet());
|
||||||
|
|
||||||
return init;
|
return init;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a rocket configuration from the launch conditions.
|
* Create a rocket configuration from the launch conditions.
|
||||||
*
|
*
|
||||||
* @param simulation the launch conditions.
|
* @param simulation the launch conditions.
|
||||||
* @return a rocket configuration with all stages attached.
|
* @return a rocket configuration with all stages attached.
|
||||||
*/
|
*/
|
||||||
@ -260,28 +261,28 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
Configuration configuration = new Configuration(simulation.getRocket());
|
Configuration configuration = new Configuration(simulation.getRocket());
|
||||||
configuration.setAllStages();
|
configuration.setAllStages();
|
||||||
configuration.setMotorConfigurationID(simulation.getMotorConfigurationID());
|
configuration.setMotorConfigurationID(simulation.getMotorConfigurationID());
|
||||||
|
|
||||||
return configuration;
|
return configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new motor instance configuration for the rocket configuration.
|
* Create a new motor instance configuration for the rocket configuration.
|
||||||
*
|
*
|
||||||
* @param configuration the rocket configuration.
|
* @param configuration the rocket configuration.
|
||||||
* @return a new motor instance configuration with all motors in place.
|
* @return a new motor instance configuration with all motors in place.
|
||||||
*/
|
*/
|
||||||
private MotorInstanceConfiguration setupMotorConfiguration(Configuration configuration) {
|
private MotorInstanceConfiguration setupMotorConfiguration(Configuration configuration) {
|
||||||
MotorInstanceConfiguration motors = new MotorInstanceConfiguration();
|
MotorInstanceConfiguration motors = new MotorInstanceConfiguration();
|
||||||
final String motorId = configuration.getMotorConfigurationID();
|
final String motorId = configuration.getMotorConfigurationID();
|
||||||
|
|
||||||
Iterator<MotorMount> iterator = configuration.motorIterator();
|
Iterator<MotorMount> iterator = configuration.motorIterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
MotorMount mount = iterator.next();
|
MotorMount mount = iterator.next();
|
||||||
RocketComponent component = (RocketComponent) mount;
|
RocketComponent component = (RocketComponent) mount;
|
||||||
Motor motor = mount.getMotor(motorId);
|
Motor motor = mount.getMotor(motorId);
|
||||||
|
|
||||||
if (motor != null) {
|
if (motor != null) {
|
||||||
Coordinate[] positions = component.toAbsolute(mount.getMotorPosition(motorId));
|
Coordinate[] positions = component.toAbsolute(mount.getMotorPosition(motorId));
|
||||||
for (int i = 0; i < positions.length; i++) {
|
for (int i = 0; i < positions.length; i++) {
|
||||||
@ -293,7 +294,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
}
|
}
|
||||||
return motors;
|
return motors;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles events occurring during the flight from the event queue.
|
* Handles events occurring during the flight from the event queue.
|
||||||
* Each event that has occurred before or at the current simulation time is
|
* Each event that has occurred before or at the current simulation time is
|
||||||
@ -302,24 +303,24 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
private boolean handleEvents() throws SimulationException {
|
private boolean handleEvents() throws SimulationException {
|
||||||
boolean ret = true;
|
boolean ret = true;
|
||||||
FlightEvent event;
|
FlightEvent event;
|
||||||
|
|
||||||
for (event = nextEvent(); event != null; event = nextEvent()) {
|
for (event = nextEvent(); event != null; event = nextEvent()) {
|
||||||
|
|
||||||
// Ignore events for components that are no longer attached to the rocket
|
// Ignore events for components that are no longer attached to the rocket
|
||||||
if (event.getSource() != null && event.getSource().getParent() != null &&
|
if (event.getSource() != null && event.getSource().getParent() != null &&
|
||||||
!status.getConfiguration().isStageActive(event.getSource().getStageNumber())) {
|
!status.getConfiguration().isStageActive(event.getSource().getStageNumber())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call simulation listeners, allow aborting event handling
|
// Call simulation listeners, allow aborting event handling
|
||||||
if (!SimulationListenerHelper.fireHandleFlightEvent(status, event)) {
|
if (!SimulationListenerHelper.fireHandleFlightEvent(status, event)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.getType() != FlightEvent.Type.ALTITUDE) {
|
if (event.getType() != FlightEvent.Type.ALTITUDE) {
|
||||||
log.verbose("BasicEventSimulationEngine: Handling event " + event);
|
log.verbose("BasicEventSimulationEngine: Handling event " + event);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.getType() == FlightEvent.Type.IGNITION) {
|
if (event.getType() == FlightEvent.Type.IGNITION) {
|
||||||
MotorMount mount = (MotorMount) event.getSource();
|
MotorMount mount = (MotorMount) event.getSource();
|
||||||
MotorId motorId = (MotorId) event.getData();
|
MotorId motorId = (MotorId) event.getData();
|
||||||
@ -328,42 +329,42 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.getType() == FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT) {
|
if (event.getType() == FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT) {
|
||||||
RecoveryDevice device = (RecoveryDevice) event.getSource();
|
RecoveryDevice device = (RecoveryDevice) event.getSource();
|
||||||
if (!SimulationListenerHelper.fireRecoveryDeviceDeployment(status, device)) {
|
if (!SimulationListenerHelper.fireRecoveryDeviceDeployment(status, device)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Check for motor ignition events, add ignition events to queue
|
// Check for motor ignition events, add ignition events to queue
|
||||||
for (MotorId id : status.getMotorConfiguration().getMotorIDs()) {
|
for (MotorId id : status.getMotorConfiguration().getMotorIDs()) {
|
||||||
MotorMount mount = status.getMotorConfiguration().getMotorMount(id);
|
MotorMount mount = status.getMotorConfiguration().getMotorMount(id);
|
||||||
RocketComponent component = (RocketComponent) mount;
|
RocketComponent component = (RocketComponent) mount;
|
||||||
|
|
||||||
if (mount.getIgnitionEvent().isActivationEvent(event, component)) {
|
if (mount.getIgnitionEvent().isActivationEvent(event, component)) {
|
||||||
addEvent(new FlightEvent(FlightEvent.Type.IGNITION,
|
addEvent(new FlightEvent(FlightEvent.Type.IGNITION,
|
||||||
status.getSimulationTime() + mount.getIgnitionDelay(),
|
status.getSimulationTime() + mount.getIgnitionDelay(),
|
||||||
component, id));
|
component, id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Check for stage separation event
|
// Check for stage separation event
|
||||||
for (int stageNo : status.getConfiguration().getActiveStages()) {
|
for (int stageNo : status.getConfiguration().getActiveStages()) {
|
||||||
if (stageNo == 0)
|
if (stageNo == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Stage stage = (Stage) status.getConfiguration().getRocket().getChild(stageNo);
|
Stage stage = (Stage) status.getConfiguration().getRocket().getChild(stageNo);
|
||||||
if (stage.getSeparationEvent().isSeparationEvent(event, stage)) {
|
if (stage.getSeparationEvent().isSeparationEvent(event, stage)) {
|
||||||
addEvent(new FlightEvent(FlightEvent.Type.STAGE_SEPARATION,
|
addEvent(new FlightEvent(FlightEvent.Type.STAGE_SEPARATION,
|
||||||
event.getTime() + stage.getSeparationDelay(), stage));
|
event.getTime() + stage.getSeparationDelay(), stage));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Check for recovery device deployment, add events to queue
|
// Check for recovery device deployment, add events to queue
|
||||||
Iterator<RocketComponent> rci = status.getConfiguration().iterator();
|
Iterator<RocketComponent> rci = status.getConfiguration().iterator();
|
||||||
while (rci.hasNext()) {
|
while (rci.hasNext()) {
|
||||||
@ -376,16 +377,16 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
event.getTime() + Math.max(0.001, ((RecoveryDevice) c).getDeployDelay()), c));
|
event.getTime() + Math.max(0.001, ((RecoveryDevice) c).getDeployDelay()), c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Handle event
|
// Handle event
|
||||||
switch (event.getType()) {
|
switch (event.getType()) {
|
||||||
|
|
||||||
case LAUNCH: {
|
case LAUNCH: {
|
||||||
status.getFlightData().addEvent(event);
|
status.getFlightData().addEvent(event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case IGNITION: {
|
case IGNITION: {
|
||||||
// Ignite the motor
|
// Ignite the motor
|
||||||
MotorMount mount = (MotorMount) event.getSource();
|
MotorMount mount = (MotorMount) event.getSource();
|
||||||
@ -395,24 +396,24 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
config.setMotorIgnitionTime(motorId, event.getTime());
|
config.setMotorIgnitionTime(motorId, event.getTime());
|
||||||
status.setMotorIgnited(true);
|
status.setMotorIgnited(true);
|
||||||
status.getFlightData().addEvent(event);
|
status.getFlightData().addEvent(event);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case LIFTOFF: {
|
case LIFTOFF: {
|
||||||
// Mark lift-off as occurred
|
// Mark lift-off as occurred
|
||||||
status.setLiftoff(true);
|
status.setLiftoff(true);
|
||||||
status.getFlightData().addEvent(event);
|
status.getFlightData().addEvent(event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case LAUNCHROD: {
|
case LAUNCHROD: {
|
||||||
// Mark launch rod as cleared
|
// Mark launch rod as cleared
|
||||||
status.setLaunchRodCleared(true);
|
status.setLaunchRodCleared(true);
|
||||||
status.getFlightData().addEvent(event);
|
status.getFlightData().addEvent(event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BURNOUT: {
|
case BURNOUT: {
|
||||||
// If motor burnout occurs without lift-off, abort
|
// If motor burnout occurs without lift-off, abort
|
||||||
if (!status.isLiftoff()) {
|
if (!status.isLiftoff()) {
|
||||||
@ -429,12 +430,12 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
status.getFlightData().addEvent(event);
|
status.getFlightData().addEvent(event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EJECTION_CHARGE: {
|
case EJECTION_CHARGE: {
|
||||||
status.getFlightData().addEvent(event);
|
status.getFlightData().addEvent(event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case STAGE_SEPARATION: {
|
case STAGE_SEPARATION: {
|
||||||
// TODO: HIGH: Store lower stages to be simulated later
|
// TODO: HIGH: Store lower stages to be simulated later
|
||||||
RocketComponent stage = event.getSource();
|
RocketComponent stage = event.getSource();
|
||||||
@ -443,20 +444,20 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
status.getFlightData().addEvent(event);
|
status.getFlightData().addEvent(event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case APOGEE:
|
case APOGEE:
|
||||||
// Mark apogee as reached
|
// Mark apogee as reached
|
||||||
status.setApogeeReached(true);
|
status.setApogeeReached(true);
|
||||||
status.getFlightData().addEvent(event);
|
status.getFlightData().addEvent(event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RECOVERY_DEVICE_DEPLOYMENT:
|
case RECOVERY_DEVICE_DEPLOYMENT:
|
||||||
RocketComponent c = event.getSource();
|
RocketComponent c = event.getSource();
|
||||||
int n = c.getStageNumber();
|
int n = c.getStageNumber();
|
||||||
// Ignore event if stage not active
|
// Ignore event if stage not active
|
||||||
if (status.getConfiguration().isStageActive(n)) {
|
if (status.getConfiguration().isStageActive(n)) {
|
||||||
// TODO: HIGH: Check stage activeness for other events as well?
|
// TODO: HIGH: Check stage activeness for other events as well?
|
||||||
|
|
||||||
// Check whether any motor in the active stages is active anymore
|
// Check whether any motor in the active stages is active anymore
|
||||||
for (MotorId motorId : status.getMotorConfiguration().getMotorIDs()) {
|
for (MotorId motorId : status.getMotorConfiguration().getMotorIDs()) {
|
||||||
int stage = ((RocketComponent) status.getMotorConfiguration().
|
int stage = ((RocketComponent) status.getMotorConfiguration().
|
||||||
@ -467,12 +468,12 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
continue;
|
continue;
|
||||||
status.getWarnings().add(Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING);
|
status.getWarnings().add(Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for launch rod
|
// Check for launch rod
|
||||||
if (!status.isLaunchRodCleared()) {
|
if (!status.isLaunchRodCleared()) {
|
||||||
status.getWarnings().add(Warning.RECOVERY_LAUNCH_ROD);
|
status.getWarnings().add(Warning.RECOVERY_LAUNCH_ROD);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check current velocity
|
// Check current velocity
|
||||||
if (status.getRocketVelocity().length() > 20) {
|
if (status.getRocketVelocity().length() > 20) {
|
||||||
// TODO: LOW: Custom warning.
|
// TODO: LOW: Custom warning.
|
||||||
@ -481,44 +482,44 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
+ UnitGroup.UNITS_VELOCITY.toStringUnit(status.getRocketVelocity().length())
|
+ UnitGroup.UNITS_VELOCITY.toStringUnit(status.getRocketVelocity().length())
|
||||||
+ ")."));
|
+ ")."));
|
||||||
}
|
}
|
||||||
|
|
||||||
status.setLiftoff(true);
|
status.setLiftoff(true);
|
||||||
status.getDeployedRecoveryDevices().add((RecoveryDevice) c);
|
status.getDeployedRecoveryDevices().add((RecoveryDevice) c);
|
||||||
|
|
||||||
this.currentStepper = this.landingStepper;
|
this.currentStepper = this.landingStepper;
|
||||||
this.status = currentStepper.initialize(status);
|
this.status = currentStepper.initialize(status);
|
||||||
|
|
||||||
status.getFlightData().addEvent(event);
|
status.getFlightData().addEvent(event);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GROUND_HIT:
|
case GROUND_HIT:
|
||||||
status.getFlightData().addEvent(event);
|
status.getFlightData().addEvent(event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SIMULATION_END:
|
case SIMULATION_END:
|
||||||
ret = false;
|
ret = false;
|
||||||
status.getFlightData().addEvent(event);
|
status.getFlightData().addEvent(event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ALTITUDE:
|
case ALTITUDE:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// If no motor has ignited, abort
|
// If no motor has ignited, abort
|
||||||
if (!status.isMotorIgnited()) {
|
if (!status.isMotorIgnited()) {
|
||||||
throw new MotorIgnitionException("No motors ignited.");
|
throw new MotorIgnitionException("No motors ignited.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a flight event to the event queue unless a listener aborts adding it.
|
* Add a flight event to the event queue unless a listener aborts adding it.
|
||||||
*
|
*
|
||||||
* @param event the event to add to the queue.
|
* @param event the event to add to the queue.
|
||||||
*/
|
*/
|
||||||
private void addEvent(FlightEvent event) throws SimulationException {
|
private void addEvent(FlightEvent event) throws SimulationException {
|
||||||
@ -526,15 +527,14 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
status.getEventQueue().add(event);
|
status.getEventQueue().add(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the next flight event to handle, or null if no more events should be handled.
|
* 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.
|
* This method jumps the simulation time forward in case no motors have been ignited.
|
||||||
* The flight event is removed from the event queue.
|
* The flight event is removed from the event queue.
|
||||||
*
|
*
|
||||||
* @param status the simulation status
|
|
||||||
* @return the flight event to handle, or null
|
* @return the flight event to handle, or null
|
||||||
*/
|
*/
|
||||||
private FlightEvent nextEvent() {
|
private FlightEvent nextEvent() {
|
||||||
@ -542,7 +542,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
FlightEvent event = queue.peek();
|
FlightEvent event = queue.peek();
|
||||||
if (event == null)
|
if (event == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Jump to event if no motors have been ignited
|
// Jump to event if no motors have been ignited
|
||||||
if (!status.isMotorIgnited() && event.getTime() > status.getSimulationTime()) {
|
if (!status.isMotorIgnited() && event.getTime() > status.getSimulationTime()) {
|
||||||
status.setSimulationTime(event.getTime());
|
status.setSimulationTime(event.getTime());
|
||||||
@ -553,9 +553,9 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void checkNaN() throws SimulationException {
|
private void checkNaN() throws SimulationException {
|
||||||
double d = 0;
|
double d = 0;
|
||||||
boolean b = false;
|
boolean b = false;
|
||||||
@ -566,7 +566,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
b |= status.getRocketOrientationQuaternion().isNaN();
|
b |= status.getRocketOrientationQuaternion().isNaN();
|
||||||
b |= status.getRocketRotationVelocity().isNaN();
|
b |= status.getRocketRotationVelocity().isNaN();
|
||||||
d += status.getEffectiveLaunchRodLength();
|
d += status.getEffectiveLaunchRodLength();
|
||||||
|
|
||||||
if (Double.isNaN(d) || b) {
|
if (Double.isNaN(d) || b) {
|
||||||
log.error("Simulation resulted in NaN value:" +
|
log.error("Simulation resulted in NaN value:" +
|
||||||
" simulationTime=" + status.getSimulationTime() +
|
" simulationTime=" + status.getSimulationTime() +
|
||||||
@ -579,6 +579,6 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
throw new SimulationException("Simulation resulted in not-a-number (NaN) value, please report a bug.");
|
throw new SimulationException("Simulation resulted in not-a-number (NaN) value, please report a bug.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user