[Bugfix] Merged FlightConfiguration MotorInstanceConfiguration
fixed ignition configuration load / save
This commit is contained in:
parent
890d390b4b
commit
729effd690
@ -94,9 +94,9 @@ public abstract class AbstractAerodynamicCalculator implements AerodynamicCalcul
|
||||
protected final void checkCache(FlightConfiguration configuration) {
|
||||
if (rocketAeroModID != configuration.getRocket().getAerodynamicModID() ||
|
||||
rocketTreeModID != configuration.getRocket().getTreeModID()) {
|
||||
// vvvv DEVEL vvvv
|
||||
log.error("Voiding the aerodynamic cache because modIDs changed...", new BugException(" unsure why modID has changed..."));
|
||||
// ^^^^ DEVEL ^^^^
|
||||
// // vvvv DEVEL vvvv
|
||||
// log.error("Voiding the aerodynamic cache because modIDs changed...", new BugException(" unsure why modID has changed..."));
|
||||
// // ^^^^ DEVEL ^^^^
|
||||
|
||||
rocketAeroModID = configuration.getRocket().getAerodynamicModID();
|
||||
rocketTreeModID = configuration.getRocket().getTreeModID();
|
||||
|
||||
@ -354,7 +354,7 @@ public class OpenRocketSaver extends RocketSaver {
|
||||
continue;
|
||||
|
||||
MotorMount mount = (MotorMount) c;
|
||||
for( FlightConfiguration config : document.getRocket().getConfigurationSet()) {
|
||||
for( FlightConfiguration config : document.getRocket().getConfigSet()) {
|
||||
FlightConfigurationID fcid = config.getFlightConfigurationID();
|
||||
if (mount.getMotorInstance(fcid) != null) {
|
||||
return FILE_VERSION_DIVISOR + 4;
|
||||
|
||||
@ -30,19 +30,6 @@ class IgnitionConfigurationHandler extends AbstractElementHandler {
|
||||
return PlainTextHandler.INSTANCE;
|
||||
}
|
||||
|
||||
|
||||
// public IgnitionConfiguration getConfiguration(IgnitionConfiguration def) {
|
||||
// IgnitionConfiguration config = def.clone();
|
||||
// if (ignitionEvent != null) {
|
||||
// config.setIgnitionEvent(ignitionEvent);
|
||||
// }
|
||||
// if (ignitionDelay != null) {
|
||||
// config.setIgnitionDelay(ignitionDelay);
|
||||
// }
|
||||
// return config;
|
||||
// }
|
||||
//
|
||||
|
||||
@Override
|
||||
public void closeElement(String element, HashMap<String, String> attributes,
|
||||
String content, WarningSet warnings) throws SAXException {
|
||||
|
||||
@ -64,7 +64,7 @@ class MotorConfigurationHandler extends AbstractElementHandler {
|
||||
|
||||
if ("true".equals(attributes.remove("default"))) {
|
||||
// associate this configuration with both this FCID and the default.
|
||||
ParameterSet<FlightConfiguration> fcs = rocket.getConfigurationSet();
|
||||
ParameterSet<FlightConfiguration> fcs = rocket.getConfigSet();
|
||||
FlightConfiguration fc = fcs.get(fcid);
|
||||
fcs.setDefault(fc);
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ class MotorMountHandler extends AbstractElementHandler {
|
||||
}
|
||||
|
||||
if (element.equals("ignitionconfiguration")) {
|
||||
ignitionConfigHandler = new IgnitionConfigurationHandler(context);
|
||||
ignitionConfigHandler = new IgnitionConfigurationHandler( context);
|
||||
return ignitionConfigHandler;
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ class MotorMountHandler extends AbstractElementHandler {
|
||||
// System.err.println("closing MotorMount element: "+ element);
|
||||
|
||||
if (element.equals("motor")) {
|
||||
// yes, this is confirmed to be the FLIGHT config id, instead of the motor instance id.
|
||||
// yes, this is confirmed to be the FLIGHT config id == motor instance id.
|
||||
FlightConfigurationID fcid = new FlightConfigurationID(attributes.get("configid"));
|
||||
if (!fcid.isValid()) {
|
||||
warnings.add(Warning.fromString("Illegal motor specification, ignoring."));
|
||||
@ -93,11 +93,9 @@ class MotorMountHandler extends AbstractElementHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
MotorInstance inst = mount.getDefaultMotorInstance();
|
||||
// ignitionConfigHandler.getConfiguration(null); // all the parsing / loading into the confighandler should already be done...
|
||||
MotorInstance inst = mount.getMotorInstance(fcid);
|
||||
inst.setIgnitionDelay(ignitionConfigHandler.ignitionDelay);
|
||||
inst.setIgnitionEvent(ignitionConfigHandler.ignitionEvent);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -51,10 +51,10 @@ public class AxialStageSaver extends ComponentAssemblySaver {
|
||||
// Note - getFlightConfigurationIDs returns at least one element. The first element
|
||||
// is null and means "default".
|
||||
|
||||
int configCount = rocket.getConfigurationSet().size();
|
||||
int configCount = rocket.getConfigSet().size();
|
||||
if (1 < configCount ){
|
||||
|
||||
for (FlightConfiguration curConfig : rocket.getConfigurationSet()){
|
||||
for (FlightConfiguration curConfig : rocket.getConfigSet()){
|
||||
FlightConfigurationID fcid = curConfig.getFlightConfigurationID();
|
||||
if (fcid == null) {
|
||||
continue;
|
||||
|
||||
@ -37,7 +37,7 @@ public class RecoveryDeviceSaver extends MassObjectSaver {
|
||||
//dev.getDeploymentConfigurations().printDebug();
|
||||
// DEBUG
|
||||
|
||||
ParameterSet<FlightConfiguration> configList = rocket.getConfigurationSet();
|
||||
ParameterSet<FlightConfiguration> configList = rocket.getConfigSet();
|
||||
for (FlightConfigurationID fcid : configList.getSortedConfigurationIDs()) {
|
||||
//System.err.println("checking FlightConfiguration:"+fcid.getShortKey()+ " save?");
|
||||
|
||||
|
||||
@ -43,7 +43,7 @@ public class RocketSaver extends RocketComponentSaver {
|
||||
|
||||
|
||||
// Motor configurations
|
||||
ParameterSet<FlightConfiguration> allConfigs = rocket.getConfigurationSet();
|
||||
ParameterSet<FlightConfiguration> allConfigs = rocket.getConfigSet();
|
||||
for (FlightConfigurationID fcid : allConfigs.getSortedConfigurationIDs()) {
|
||||
FlightConfiguration flightConfig = allConfigs.get(fcid);
|
||||
if (fcid == null)
|
||||
|
||||
@ -58,7 +58,7 @@ public class BodyTubeDTO extends BasePartDTO implements AttachableParts {
|
||||
@XmlElementRef(name = RocksimCommonConstants.STREAMER, type = StreamerDTO.class),
|
||||
@XmlElementRef(name = RocksimCommonConstants.PARACHUTE, type = ParachuteDTO.class),
|
||||
@XmlElementRef(name = RocksimCommonConstants.MASS_OBJECT, type = MassObjectDTO.class)})
|
||||
List<BasePartDTO> attachedParts = new ArrayList();
|
||||
List<BasePartDTO> attachedParts = new ArrayList<BasePartDTO>();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
|
||||
@ -187,28 +187,13 @@ public class MotorInstance implements FlightConfigurableParameter<MotorInstance>
|
||||
|
||||
@Override
|
||||
public boolean equals( Object other ){
|
||||
if( other == null )
|
||||
if( null == other ){
|
||||
return false;
|
||||
if( other instanceof MotorInstance ){
|
||||
}else if( other instanceof MotorInstance ){
|
||||
MotorInstance omi = (MotorInstance)other;
|
||||
if( this.id.equals( omi.id)){
|
||||
return true;
|
||||
}
|
||||
// }else if( this.mount != omi.mount ){
|
||||
// return false;
|
||||
// }else if( this.ignitionEvent == omi.ignitionEvent ){
|
||||
// return false;
|
||||
// }else if( EPSILON < Math.abs(this.ignitionDelay - omi.ignitionDelay )){
|
||||
// return false;
|
||||
// }else if( EPSILON < Math.abs( this.ejectionDelay - omi.ejectionDelay )){
|
||||
// return false;
|
||||
// }else if( ! this.position.equals( omi.position )){
|
||||
// return false;
|
||||
// }else if( EPSILON < Math.abs( this.ignitionTime - omi.ignitionTime )){
|
||||
// return false;
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1,241 +0,0 @@
|
||||
package net.sf.openrocket.motor;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
|
||||
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.FlightConfigurationID;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.util.ArrayList;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.Monitorable;
|
||||
|
||||
/**
|
||||
* A configuration of motor instances identified by a MotorInstanceId. Each motor instance has
|
||||
* an individual position, ingition time etc.
|
||||
*
|
||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||
*/
|
||||
public class MotorInstanceConfiguration implements Cloneable, Iterable<MotorInstance>, Monitorable {
|
||||
protected final HashMap<MotorInstanceId, MotorInstance> motors = new HashMap<MotorInstanceId, MotorInstance>();
|
||||
protected final FlightConfiguration config;
|
||||
private int modID = 0;
|
||||
|
||||
private MotorInstanceConfiguration() {
|
||||
this.config = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new motor instance configuration for the rocket configuration.
|
||||
*
|
||||
* @param configuration the rocket configuration.
|
||||
*/
|
||||
public MotorInstanceConfiguration( final FlightConfiguration _configuration) {
|
||||
this.config = _configuration;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a motor instance to this configuration. The motor is placed at
|
||||
* the specified position and with an infinite ignition time (never ignited).
|
||||
*
|
||||
* @param id the ID of this motor instance.
|
||||
* @param motor the motor instance.
|
||||
* @param mount the motor mount containing this motor
|
||||
* @param ignitionEvent the ignition event for the motor
|
||||
* @param ignitionDelay the ignition delay for the motor
|
||||
* @param position the position of the motor in absolute coordinates.
|
||||
* @throws IllegalArgumentException if a motor with the specified ID already exists.
|
||||
*/
|
||||
// public void addMotor(MotorId _id, Motor _motor, double _ejectionDelay, MotorMount _mount,
|
||||
// IgnitionEvent _ignitionEvent, double _ignitionDelay, Coordinate _position) {
|
||||
//
|
||||
// MotorInstance instanceToAdd = new MotorInstance(_id, _motor, _mount, _ejectionDelay,
|
||||
// _ignitionEvent, _ignitionDelay, _position);
|
||||
//
|
||||
//
|
||||
// // this.ids.add(id);
|
||||
// // this.motors.add(motor);
|
||||
// // this.ejectionDelays.add(ejectionDelay);
|
||||
// // this.mounts.add(mount);
|
||||
// // this.ignitionEvents.add(ignitionEvent);
|
||||
// // this.ignitionDelays.add(ignitionDelay);
|
||||
// // this.positions.add(position);
|
||||
// // this.ignitionTimes.add(Double.POSITIVE_INFINITY);
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* Add a motor instance to this configuration.
|
||||
*
|
||||
* @param motor the motor instance.
|
||||
* @throws IllegalArgumentException if a motor with the specified ID already exists.
|
||||
*/
|
||||
public void addMotor(MotorInstance motor) {
|
||||
if( motor.isEmpty() ){
|
||||
throw new IllegalArgumentException("MotorInstance is empty.");
|
||||
}
|
||||
MotorInstanceId id = motor.getID();
|
||||
if (this.motors.containsKey(id)) {
|
||||
throw new IllegalArgumentException("MotorInstanceConfiguration already " +
|
||||
"contains a motor with id " + id);
|
||||
}
|
||||
this.motors.put(id, motor);
|
||||
|
||||
modID++;
|
||||
}
|
||||
|
||||
public Collection<MotorInstance> getAllMotors() {
|
||||
return motors.values();
|
||||
}
|
||||
|
||||
public int getMotorCount() {
|
||||
return motors.size();
|
||||
}
|
||||
|
||||
public Set<MotorInstanceId> getMotorIDs() {
|
||||
return this.motors.keySet();
|
||||
}
|
||||
|
||||
public MotorInstance getMotorInstance(MotorInstanceId id) {
|
||||
return motors.get(id);
|
||||
}
|
||||
|
||||
public boolean hasMotors() {
|
||||
return (0 < motors.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Step all of the motor instances to the specified time minus their ignition time.
|
||||
* @param time the "global" time
|
||||
*/
|
||||
public void step(double time, double acceleration, AtmosphericConditions cond) {
|
||||
for (MotorInstance inst : motors.values()) {
|
||||
double t = time - inst.getIgnitionTime();
|
||||
if (t >= 0) {
|
||||
inst.step(t, acceleration, cond);
|
||||
}
|
||||
}
|
||||
modID++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getModID() {
|
||||
int id = modID;
|
||||
for (MotorInstance motor : motors.values()) {
|
||||
id += motor.getModID();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this motor instance configuration with independent motor instances
|
||||
* from this instance.
|
||||
*/
|
||||
@Override
|
||||
public MotorInstanceConfiguration clone() {
|
||||
MotorInstanceConfiguration clone = new MotorInstanceConfiguration();
|
||||
for (MotorInstance motor : this.motors.values()) {
|
||||
clone.motors.put(motor.getID(), motor.clone());
|
||||
}
|
||||
clone.modID = this.modID;
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<MotorInstance> iterator() {
|
||||
return this.motors.values().iterator();
|
||||
}
|
||||
|
||||
public List<MotorInstance> getActiveMotors() {
|
||||
List<MotorInstance> activeList = new ArrayList<MotorInstance>();
|
||||
for( MotorInstance inst : this.motors.values() ){
|
||||
if( inst.isActive() ){
|
||||
activeList.add( inst );
|
||||
}
|
||||
}
|
||||
|
||||
return activeList;
|
||||
}
|
||||
|
||||
public void populate( final MotorInstanceConfiguration source){
|
||||
this.motors.putAll( source.motors );
|
||||
}
|
||||
|
||||
public void update() {
|
||||
this.motors.clear();
|
||||
|
||||
FlightConfigurationID fcid = this.config.getFlightConfigurationID();
|
||||
for ( RocketComponent comp : this.config.getActiveComponents() ){
|
||||
if ( comp instanceof MotorMount ){
|
||||
MotorMount mount = (MotorMount)comp;
|
||||
MotorInstance inst = mount.getMotorInstance( fcid);
|
||||
if( inst.isEmpty()){
|
||||
continue;
|
||||
}
|
||||
|
||||
// this merely accounts for instancing of *this* component:
|
||||
// int instancCount = comp.getInstanceCount();
|
||||
|
||||
// this includes *all* the instancing between here and the rocket root.
|
||||
Coordinate[] instanceLocations= comp.getLocations();
|
||||
|
||||
// System.err.println(String.format(",,,,,,,, : %s (%s)",
|
||||
// inst.getMotor().getDigest(), inst.getMotorID() ));
|
||||
int instanceNumber = 0;
|
||||
for ( Coordinate curMountLocation : instanceLocations ){
|
||||
MotorInstance curInstance = inst.clone();
|
||||
curInstance.setID( new MotorInstanceId( comp.getName(), instanceNumber+1) );
|
||||
|
||||
// motor location w/in mount: parent.refpoint -> motor.refpoint
|
||||
Coordinate curMotorOffset = curInstance.getOffset();
|
||||
curInstance.setPosition( curMountLocation.add(curMotorOffset) );
|
||||
this.motors.put( curInstance.getID(), curInstance);
|
||||
|
||||
// vvvv DEVEL vvvv
|
||||
// System.err.println(String.format(",,,,,,,,[ %2d]: %s. (%s)",
|
||||
// instanceNumber, curInstance.getMotor().getDigest(), curInstance));
|
||||
// ^^^^ DEVEL ^^^^
|
||||
instanceNumber ++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
//System.err.println("returning "+toReturn.size()+" active motor instances for this configuration: "+this.fcid.getShortKey());
|
||||
//System.err.println(this.rocket.getConfigurationSet().toDebug());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
StringBuilder buff = new StringBuilder("[");
|
||||
boolean first = true;
|
||||
for( MotorInstance motor : this.motors.values() ){
|
||||
if( first ){
|
||||
first = false;
|
||||
}else{
|
||||
buff.append(", ");
|
||||
}
|
||||
buff.append(motor.getMotor().getDesignation());
|
||||
}
|
||||
buff.append("]");
|
||||
return buff.toString();
|
||||
}
|
||||
|
||||
public String toDebugString(){
|
||||
StringBuilder buff = new StringBuilder();
|
||||
for( MotorInstance motor : this.motors.values() ){
|
||||
final String idString = motor.getID().toShortKey();
|
||||
final String activeString = motor.isActive()? " on": "off";
|
||||
final String nameString = motor.getMotor().getDesignation();
|
||||
buff.append( String.format(" ..[%8s][%s] %10s", idString, activeString, nameString));
|
||||
}
|
||||
return buff.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@ -5,16 +5,17 @@ import java.util.Collection;
|
||||
import java.util.EventListener;
|
||||
import java.util.EventObject;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
|
||||
import net.sf.openrocket.motor.MotorInstance;
|
||||
import net.sf.openrocket.motor.MotorInstanceConfiguration;
|
||||
import net.sf.openrocket.motor.MotorInstanceId;
|
||||
import net.sf.openrocket.util.ArrayList;
|
||||
import net.sf.openrocket.util.ChangeSource;
|
||||
@ -56,7 +57,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
|
||||
/* Cached data */
|
||||
final protected HashMap<Integer, StageFlags> stages = new HashMap<Integer, StageFlags>();
|
||||
final protected MotorInstanceConfiguration motors;
|
||||
protected final HashMap<MotorInstanceId, MotorInstance> motors = new HashMap<MotorInstanceId, MotorInstance>();
|
||||
|
||||
private int boundsModID = -1;
|
||||
private ArrayList<Coordinate> cachedBounds = new ArrayList<Coordinate>();
|
||||
@ -67,6 +68,8 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
|
||||
private int modID = 0;
|
||||
|
||||
private boolean debug = false;
|
||||
|
||||
/**
|
||||
* Create a new configuration with the specified <code>Rocket</code>.
|
||||
*
|
||||
@ -82,13 +85,16 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
this.rocket = rocket;
|
||||
this.isNamed = false;
|
||||
this.configurationName = "<WARN: attempt to access unset configurationName. WARN!> ";
|
||||
this.motors = new MotorInstanceConfiguration(this);
|
||||
|
||||
updateStageMap();
|
||||
this.motors.update();
|
||||
updateStages();
|
||||
updateMotors();
|
||||
rocket.addComponentChangeListener(this);
|
||||
}
|
||||
|
||||
public void enableDebugging(){
|
||||
this.debug=true;
|
||||
}
|
||||
|
||||
public Rocket getRocket() {
|
||||
return rocket;
|
||||
}
|
||||
@ -114,17 +120,19 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
*
|
||||
* @param stageNumber stage number to inactivate
|
||||
*/
|
||||
public void clearOnlyStage(final int stageNumber) {
|
||||
setStageActive(stageNumber, false);
|
||||
public void clearStage(final int stageNumber) {
|
||||
setStageActive( stageNumber, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method flags a stage active. Other stages are unaffected.
|
||||
* This method flags the specified stage as active, and all other stages as inactive.
|
||||
*
|
||||
* @param stageNumber stage number to activate
|
||||
*/
|
||||
public void setOnlyStage(final int stageNumber) {
|
||||
setAllStages(false);
|
||||
setStageActive(stageNumber, true);
|
||||
fireChangeEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -161,7 +169,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
if (stageNumber >= this.rocket.getStageCount()) {
|
||||
return false;
|
||||
}
|
||||
// DEVEL
|
||||
|
||||
if( ! stages.containsKey(stageNumber)){
|
||||
throw new IllegalArgumentException(" Configuration does not contain stage number: "+stageNumber);
|
||||
}
|
||||
@ -188,18 +196,6 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
public List<MotorInstance> getActiveMotors() {
|
||||
return this.motors.getActiveMotors();
|
||||
}
|
||||
|
||||
public Collection<MotorInstance> getAllMotors() {
|
||||
return this.motors.getAllMotors();
|
||||
}
|
||||
|
||||
public boolean hasMotors() {
|
||||
return this.motors.hasMotors();
|
||||
}
|
||||
|
||||
public List<AxialStage> getActiveStages() {
|
||||
List<AxialStage> activeStages = new ArrayList<AxialStage>();
|
||||
@ -241,10 +237,6 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
return stages.size();
|
||||
}
|
||||
|
||||
public MotorInstance getMotor( final MotorInstanceId mid ){
|
||||
return this.motors.getMotorInstance( mid );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the reference length associated with the current configuration. The
|
||||
* reference length type is retrieved from the <code>Rocket</code>.
|
||||
@ -267,6 +259,10 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
return fcid;
|
||||
}
|
||||
|
||||
public FlightConfigurationID getId() {
|
||||
return getFlightConfigurationID();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the listener connection to the rocket and listeners of this object.
|
||||
* This configuration may not be used after a call to this method!
|
||||
@ -304,11 +300,14 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
}
|
||||
}
|
||||
|
||||
updateStageMap();
|
||||
motors.update();
|
||||
updateStages();
|
||||
updateMotors();
|
||||
}
|
||||
|
||||
private void updateStageMap() {
|
||||
private void updateStages() {
|
||||
if( debug){
|
||||
System.err.println("updating config stages");
|
||||
}
|
||||
if (this.rocket.getStageCount() == this.stages.size()) {
|
||||
// no changes needed
|
||||
return;
|
||||
@ -334,7 +333,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
return configurationName;
|
||||
}else{
|
||||
if( this.hasMotors()){
|
||||
return fcid.toShortKey()+" - "+this.motors.toString();
|
||||
return fcid.toShortKey()+" - "+this.getMotorsOneline();
|
||||
}else{
|
||||
return fcid.getFullKeyText();
|
||||
}
|
||||
@ -365,8 +364,8 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
// DEBUG / DEVEL
|
||||
public String toMotorDetail(){
|
||||
StringBuilder buff = new StringBuilder();
|
||||
buff.append(String.format("\nDumping %2d Motors for configuration %s: \n", this.motors.getMotorCount(), this.fcid.toShortKey()));
|
||||
for( MotorInstance curMotor : this.getAllMotors()){
|
||||
buff.append(String.format("\nDumping %2d Motors for configuration %s: \n", this.motors.size(), this.fcid.toShortKey()));
|
||||
for( MotorInstance curMotor : this.motors.values() ){
|
||||
if( curMotor.isEmpty() ){
|
||||
buff.append( String.format( " ..[%8s] <empty> \n", curMotor.getID().toShortKey()));
|
||||
}else{
|
||||
@ -378,7 +377,36 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
}
|
||||
}
|
||||
return buff.toString();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public String getMotorsOneline(){
|
||||
StringBuilder buff = new StringBuilder("[");
|
||||
boolean first = true;
|
||||
for ( RocketComponent comp : getActiveComponents() ){
|
||||
if (( comp instanceof MotorMount )&&( ((MotorMount)comp).isMotorMount())){
|
||||
MotorMount mount = (MotorMount)comp;
|
||||
MotorInstance inst = mount.getMotorInstance( fcid);
|
||||
|
||||
if( first ){
|
||||
first = false;
|
||||
}else{
|
||||
buff.append(";");
|
||||
}
|
||||
|
||||
if( ! inst.isEmpty()){
|
||||
buff.append( inst.getMotor().getDesignation());
|
||||
}
|
||||
}
|
||||
}
|
||||
buff.append("]");
|
||||
return buff.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@ -388,11 +416,155 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
@Override
|
||||
public void componentChanged(ComponentChangeEvent cce) {
|
||||
// update according to incoming events
|
||||
updateStageMap();
|
||||
this.motors.update();
|
||||
updateStages();
|
||||
updateMotors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a motor instance to this configuration. The motor is placed at
|
||||
* the specified position and with an infinite ignition time (never ignited).
|
||||
*
|
||||
* @param id the ID of this motor instance.
|
||||
* @param motor the motor instance.
|
||||
* @param mount the motor mount containing this motor
|
||||
* @param ignitionEvent the ignition event for the motor
|
||||
* @param ignitionDelay the ignition delay for the motor
|
||||
* @param position the position of the motor in absolute coordinates.
|
||||
* @throws IllegalArgumentException if a motor with the specified ID already exists.
|
||||
*/
|
||||
// public void addMotor(MotorId _id, Motor _motor, double _ejectionDelay, MotorMount _mount,
|
||||
// IgnitionEvent _ignitionEvent, double _ignitionDelay, Coordinate _position) {
|
||||
//
|
||||
// MotorInstance instanceToAdd = new MotorInstance(_id, _motor, _mount, _ejectionDelay,
|
||||
// _ignitionEvent, _ignitionDelay, _position);
|
||||
//
|
||||
//
|
||||
// // this.ids.add(id);
|
||||
// // this.motors.add(motor);
|
||||
// // this.ejectionDelays.add(ejectionDelay);
|
||||
// // this.mounts.add(mount);
|
||||
// // this.ignitionEvents.add(ignitionEvent);
|
||||
// // this.ignitionDelays.add(ignitionDelay);
|
||||
// // this.positions.add(position);
|
||||
// // this.ignitionTimes.add(Double.POSITIVE_INFINITY);
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* Add a motor instance to this configuration.
|
||||
*
|
||||
* @param motor the motor instance.
|
||||
* @throws IllegalArgumentException if a motor with the specified ID already exists.
|
||||
*/
|
||||
public void addMotor(MotorInstance motor) {
|
||||
if( motor.isEmpty() ){
|
||||
throw new IllegalArgumentException("MotorInstance is empty.");
|
||||
}
|
||||
MotorInstanceId id = motor.getID();
|
||||
if (this.motors.containsKey(id)) {
|
||||
throw new IllegalArgumentException("MotorInstanceConfiguration already " +
|
||||
"contains a motor with id " + id);
|
||||
}
|
||||
this.motors.put(id, motor);
|
||||
|
||||
modID++;
|
||||
}
|
||||
|
||||
public Collection<MotorInstance> getAllMotors() {
|
||||
return motors.values();
|
||||
}
|
||||
|
||||
public int getMotorCount() {
|
||||
return motors.size();
|
||||
}
|
||||
|
||||
public Set<MotorInstanceId> getMotorIDs() {
|
||||
return this.motors.keySet();
|
||||
}
|
||||
|
||||
public MotorInstance getMotorInstance(MotorInstanceId id) {
|
||||
return motors.get(id);
|
||||
}
|
||||
|
||||
public boolean hasMotors() {
|
||||
return (0 < motors.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Step all of the motor instances to the specified time minus their ignition time.
|
||||
* @param time the "global" time
|
||||
*/
|
||||
public void step(double time, double acceleration, AtmosphericConditions cond) {
|
||||
for (MotorInstance inst : motors.values()) {
|
||||
double t = time - inst.getIgnitionTime();
|
||||
if (t >= 0) {
|
||||
inst.step(t, acceleration, cond);
|
||||
}
|
||||
}
|
||||
modID++;
|
||||
}
|
||||
|
||||
public List<MotorInstance> getActiveMotors() {
|
||||
List<MotorInstance> activeList = new ArrayList<MotorInstance>();
|
||||
for( MotorInstance inst : this.motors.values() ){
|
||||
if( inst.isActive() ){
|
||||
activeList.add( inst );
|
||||
}
|
||||
}
|
||||
|
||||
return activeList;
|
||||
}
|
||||
|
||||
public void updateMotors() {
|
||||
if( debug){
|
||||
System.err.println("updating config motors");
|
||||
}
|
||||
this.motors.clear();
|
||||
|
||||
for ( RocketComponent comp : getActiveComponents() ){
|
||||
if (( comp instanceof MotorMount )&&( ((MotorMount)comp).isMotorMount())){
|
||||
MotorMount mount = (MotorMount)comp;
|
||||
MotorInstance inst = mount.getMotorInstance( fcid);
|
||||
if( inst.isEmpty()){
|
||||
continue;
|
||||
}
|
||||
|
||||
// this merely accounts for instancing of *this* component:
|
||||
// int instancCount = comp.getInstanceCount();
|
||||
|
||||
// this includes *all* the instancing between here and the rocket root.
|
||||
Coordinate[] instanceLocations= comp.getLocations();
|
||||
|
||||
if( debug){
|
||||
System.err.println(String.format(",,,,,,,, %s (%s)",
|
||||
inst.getMotor().getDigest(), inst.getID() ));
|
||||
}
|
||||
int instanceNumber = 1;
|
||||
final int instanceCount = instanceLocations.length;
|
||||
for ( Coordinate curMountLocation : instanceLocations ){
|
||||
MotorInstance curInstance = inst.clone();
|
||||
curInstance.setID( new MotorInstanceId( comp.getName(), instanceNumber) );
|
||||
|
||||
// motor location w/in mount: parent.refpoint -> motor.refpoint
|
||||
Coordinate curMotorOffset = curInstance.getOffset();
|
||||
curInstance.setPosition( curMountLocation.add(curMotorOffset) );
|
||||
this.motors.put( curInstance.getID(), curInstance);
|
||||
|
||||
// vvvv DEVEL vvvv
|
||||
if(debug){
|
||||
System.err.println(String.format(",,,,,,,, [%2d/%2d]: %s. (%s)",
|
||||
instanceNumber, instanceCount, curInstance.getMotor().getDigest(), curInstance));
|
||||
}
|
||||
// ^^^^ DEVEL ^^^^
|
||||
instanceNumber ++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
//System.err.println("returning "+toReturn.size()+" active motor instances for this configuration: "+this.fcid.getShortKey());
|
||||
//System.err.println(this.rocket.getConfigurationSet().toDebug());
|
||||
}
|
||||
|
||||
/////////////// Helper methods ///////////////
|
||||
|
||||
/**
|
||||
@ -447,30 +619,34 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
return cachedLength;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Perform a deep-clone. The object references are also cloned and no
|
||||
* listeners are listening on the cloned object. The rocket instance remains the same.
|
||||
*/
|
||||
@Override
|
||||
public FlightConfiguration clone() {
|
||||
FlightConfiguration config = new FlightConfiguration( this.getRocket(), this.fcid );
|
||||
config.listenerList = new ArrayList<EventListener>();
|
||||
config.stages.putAll( (Map<Integer, StageFlags>) this.stages);
|
||||
config.motors.populate( this.motors );
|
||||
config.cachedBounds = this.cachedBounds.clone();
|
||||
config.boundsModID = -1;
|
||||
config.refLengthModID = -1;
|
||||
rocket.addComponentChangeListener(config);
|
||||
return config;
|
||||
FlightConfiguration clone = new FlightConfiguration( this.getRocket(), this.fcid );
|
||||
clone.setName(this.fcid.toShortKey()+" - clone");
|
||||
clone.listenerList = new ArrayList<EventListener>();
|
||||
clone.stages.putAll( (Map<Integer, StageFlags>) this.stages);
|
||||
clone.motors.putAll( (Map<MotorInstanceId, MotorInstance>) this.motors);
|
||||
clone.cachedBounds = this.cachedBounds.clone();
|
||||
clone.modID = this.modID;
|
||||
clone.boundsModID = -1;
|
||||
clone.refLengthModID = -1;
|
||||
rocket.addComponentChangeListener(clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getModID() {
|
||||
return modID + rocket.getModID();
|
||||
// TODO: this doesn't seem consistent...
|
||||
int id = modID;
|
||||
// for (MotorInstance motor : motors.values()) {
|
||||
// id += motor.getModID();
|
||||
// }
|
||||
id += rocket.getModID();
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setName( final String newName) {
|
||||
@ -487,8 +663,4 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
this.configurationName = newName;
|
||||
}
|
||||
|
||||
public void step(double time, double acceleration, AtmosphericConditions cond) {
|
||||
this.motors.step( time, acceleration, cond);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -401,14 +401,14 @@ public class Rocket extends RocketComponent {
|
||||
|
||||
// Update modification ID's only for normal (not undo/redo) events
|
||||
{ // vvvv DEVEL vvvv
|
||||
String changeString;
|
||||
if (cce.isUndoChange()) {
|
||||
changeString = "an 'undo' change from: "+cce.getSource().getName()+" as:"+cce.toString();
|
||||
}else{
|
||||
changeString = "a normal change from: "+cce.getSource().getName()+" as:"+cce.toString();
|
||||
}
|
||||
|
||||
log.error("Processing a rocket change: "+changeString, new IllegalArgumentException());
|
||||
// String changeString;
|
||||
// if (cce.isUndoChange()) {
|
||||
// changeString = "an 'undo' change from: "+cce.getSource().getName()+" as:"+cce.toString();
|
||||
// }else{
|
||||
// changeString = "a normal change from: "+cce.getSource().getName()+" as:"+cce.toString();
|
||||
// }
|
||||
//
|
||||
// log.error("Processing a rocket change: "+changeString, new IllegalArgumentException());
|
||||
} // ^^^^ DEVEL ^^^^
|
||||
|
||||
// Check whether frozen
|
||||
@ -541,7 +541,7 @@ public class Rocket extends RocketComponent {
|
||||
return this.configSet.size();
|
||||
}
|
||||
|
||||
public ParameterSet<FlightConfiguration> getConfigurationSet(){
|
||||
public ParameterSet<FlightConfiguration> getConfigSet(){
|
||||
checkState();
|
||||
return this.configSet;
|
||||
}
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
package net.sf.openrocket.rocketcomponent;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
import java.util.Deque;
|
||||
import java.util.EventObject;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@ -1082,17 +1083,6 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
}
|
||||
this.offset = newOffset;
|
||||
this.position = new Coordinate(newAxialPosition, this.position.y, this.position.z);
|
||||
|
||||
// if( this instanceof CenteringRing ){
|
||||
// System.err.println("Moving "+this.getName()+"("+this.getID().substring(0, 8)+") to:"+newOffset+" via:"+positionMethod.name());
|
||||
// System.err.println(" new Position = "+this.position);
|
||||
// if( positionMethod == Position.BOTTOM){
|
||||
// StackTraceElement[] stack = Thread.currentThread().getStackTrace();
|
||||
// for( int i = 0; i < 12 ; i++){
|
||||
// System.err.println( stack[i]);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
protected void update() {
|
||||
@ -2029,7 +2019,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
*/
|
||||
private static class RocketComponentIterator implements Iterator<RocketComponent> {
|
||||
// Stack holds iterators which still have some components left.
|
||||
private final Stack<Iterator<RocketComponent>> iteratorStack = new Stack<Iterator<RocketComponent>>();
|
||||
private final Deque<Iterator<RocketComponent>> iteratorStack = new ArrayDeque<Iterator<RocketComponent>>();
|
||||
|
||||
private final Rocket root;
|
||||
private final int treeModID;
|
||||
|
||||
@ -185,6 +185,7 @@ public abstract class AbstractSimulationStepper implements SimulationStepper {
|
||||
configuration.step(status.getSimulationTime() + timestep, acceleration, atmosphericConditions);
|
||||
thrust = 0;
|
||||
|
||||
//?? needs to instance the motors...
|
||||
List<MotorInstance> activeMotors = configuration.getActiveMotors();
|
||||
for (MotorInstance currentMotorInstance : activeMotors) {
|
||||
thrust += currentMotorInstance.getThrust();
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package net.sf.openrocket.simulation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -52,14 +52,17 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
|
||||
private SimulationStepper currentStepper;
|
||||
|
||||
private SimulationStatus status;
|
||||
private SimulationStatus currentStatus;
|
||||
|
||||
private FlightConfigurationID fcid;
|
||||
|
||||
// was a stack, but parallel staging breaks that
|
||||
protected Stack<SimulationStatus> stages = new Stack<SimulationStatus>();
|
||||
// protected ArrayList<SimulationStatus> burningStages = new ArrayList<SimulationStatus>();
|
||||
// protected ArrayList<SimulationStatus> carriedStages = new ArrayList<SimulationStatus>();
|
||||
// old: protected Stack<SimulationStatus> stages = new Stack<SimulationStatus>();
|
||||
// this variable was class member stack, but parallel staging breaks metaphor:
|
||||
// parallel stages may ignite before OR after their 'inner' stages
|
||||
|
||||
|
||||
// this is just a list of simulation branches to
|
||||
Deque<SimulationStatus> toSimulate = new ArrayDeque<SimulationStatus>();
|
||||
|
||||
|
||||
@Override
|
||||
@ -79,32 +82,33 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
throw new MotorIgnitionException(errorMessage);
|
||||
}
|
||||
|
||||
status = new SimulationStatus(configuration, simulationConditions);
|
||||
status.getEventQueue().add(new FlightEvent(FlightEvent.Type.LAUNCH, 0, simulationConditions.getRocket()));
|
||||
currentStatus = new SimulationStatus(configuration, simulationConditions);
|
||||
currentStatus.getEventQueue().add(new FlightEvent(FlightEvent.Type.LAUNCH, 0, simulationConditions.getRocket()));
|
||||
{
|
||||
// main sustainer stage
|
||||
RocketComponent sustainer = configuration.getRocket().getChild(0);
|
||||
status.setFlightData(new FlightDataBranch(sustainer.getName(), FlightDataType.TYPE_TIME));
|
||||
// main simulation branch
|
||||
final String branchName = configuration.getRocket().getTopmostStage().getName();
|
||||
currentStatus.setFlightData(new FlightDataBranch( branchName, FlightDataType.TYPE_TIME));
|
||||
}
|
||||
stages.add(status);
|
||||
toSimulate.add(currentStatus);
|
||||
|
||||
SimulationListenerHelper.fireStartSimulation(status);
|
||||
|
||||
while (true) {
|
||||
if (stages.size() == 0) {
|
||||
SimulationListenerHelper.fireStartSimulation(currentStatus);
|
||||
do{
|
||||
if( null == toSimulate.peek()){
|
||||
break;
|
||||
}
|
||||
SimulationStatus stageStatus = stages.pop();
|
||||
if (stageStatus == null) {
|
||||
break;
|
||||
}
|
||||
status = stageStatus;
|
||||
currentStatus = toSimulate.pop();
|
||||
log.info(">>Starting simulation of branch: "+currentStatus.getFlightData().getBranchName());
|
||||
|
||||
FlightDataBranch dataBranch = simulateLoop();
|
||||
flightData.addBranch(dataBranch);
|
||||
flightData.getWarningSet().addAll(status.getWarnings());
|
||||
}
|
||||
flightData.getWarningSet().addAll(currentStatus.getWarnings());
|
||||
|
||||
log.info(String.format("<<Finished simulating branch: %s at:%s",
|
||||
currentStatus.getFlightData().getBranchName(),
|
||||
currentStatus.getFlightData().getLast(FlightDataType.TYPE_TIME)));
|
||||
}while( ! toSimulate.isEmpty());
|
||||
|
||||
SimulationListenerHelper.fireEndSimulation(status, null);
|
||||
SimulationListenerHelper.fireEndSimulation(currentStatus, null);
|
||||
|
||||
configuration.release();
|
||||
|
||||
@ -119,92 +123,95 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
|
||||
// Initialize the simulation
|
||||
currentStepper = flightStepper;
|
||||
status = currentStepper.initialize(status);
|
||||
currentStatus = currentStepper.initialize(currentStatus);
|
||||
|
||||
// Get originating position (in case listener has modified launch position)
|
||||
Coordinate origin = status.getRocketPosition();
|
||||
Coordinate originVelocity = status.getRocketVelocity();
|
||||
Coordinate origin = currentStatus.getRocketPosition();
|
||||
Coordinate originVelocity = currentStatus.getRocketVelocity();
|
||||
|
||||
try {
|
||||
log.info(String.format(" >> Starting simulate loop."));
|
||||
|
||||
// Start the simulation
|
||||
while (handleEvents()) {
|
||||
|
||||
log.info(String.format(" >> Events Handled."));
|
||||
|
||||
// Take the step
|
||||
double oldAlt = status.getRocketPosition().z;
|
||||
double oldAlt = currentStatus.getRocketPosition().z;
|
||||
|
||||
if (SimulationListenerHelper.firePreStep(status)) {
|
||||
if (SimulationListenerHelper.firePreStep(currentStatus)) {
|
||||
// Step at most to the next event
|
||||
double maxStepTime = Double.MAX_VALUE;
|
||||
FlightEvent nextEvent = status.getEventQueue().peek();
|
||||
FlightEvent nextEvent = currentStatus.getEventQueue().peek();
|
||||
if (nextEvent != null) {
|
||||
maxStepTime = MathUtil.max(nextEvent.getTime() - status.getSimulationTime(), 0.001);
|
||||
maxStepTime = MathUtil.max(nextEvent.getTime() - currentStatus.getSimulationTime(), 0.001);
|
||||
}
|
||||
log.trace("BasicEventSimulationEngine: Taking simulation step at t=" + status.getSimulationTime());
|
||||
currentStepper.step(status, maxStepTime);
|
||||
log.trace("BasicEventSimulationEngine: Taking simulation step at t=" + currentStatus.getSimulationTime());
|
||||
currentStepper.step(currentStatus, maxStepTime);
|
||||
}
|
||||
SimulationListenerHelper.firePostStep(status);
|
||||
SimulationListenerHelper.firePostStep(currentStatus);
|
||||
|
||||
|
||||
// Check for NaN values in the simulation status
|
||||
checkNaN();
|
||||
|
||||
// Add altitude event
|
||||
addEvent(new FlightEvent(FlightEvent.Type.ALTITUDE, status.getSimulationTime(),
|
||||
status.getConfiguration().getRocket(),
|
||||
new Pair<Double, Double>(oldAlt, status.getRocketPosition().z)));
|
||||
addEvent(new FlightEvent(FlightEvent.Type.ALTITUDE, currentStatus.getSimulationTime(),
|
||||
currentStatus.getConfiguration().getRocket(),
|
||||
new Pair<Double, Double>(oldAlt, currentStatus.getRocketPosition().z)));
|
||||
|
||||
if (status.getRocketPosition().z > status.getMaxAlt()) {
|
||||
status.setMaxAlt(status.getRocketPosition().z);
|
||||
if (currentStatus.getRocketPosition().z > currentStatus.getMaxAlt()) {
|
||||
currentStatus.setMaxAlt(currentStatus.getRocketPosition().z);
|
||||
}
|
||||
|
||||
|
||||
// Position relative to start location
|
||||
Coordinate relativePosition = status.getRocketPosition().sub(origin);
|
||||
Coordinate relativePosition = currentStatus.getRocketPosition().sub(origin);
|
||||
|
||||
// Add appropriate events
|
||||
if (!status.isLiftoff()) {
|
||||
if (!currentStatus.isLiftoff()) {
|
||||
|
||||
// Avoid sinking into ground before liftoff
|
||||
if (relativePosition.z < 0) {
|
||||
status.setRocketPosition(origin);
|
||||
status.setRocketVelocity(originVelocity);
|
||||
currentStatus.setRocketPosition(origin);
|
||||
currentStatus.setRocketVelocity(originVelocity);
|
||||
}
|
||||
// Detect lift-off
|
||||
if (relativePosition.z > 0.02) {
|
||||
addEvent(new FlightEvent(FlightEvent.Type.LIFTOFF, status.getSimulationTime()));
|
||||
addEvent(new FlightEvent(FlightEvent.Type.LIFTOFF, currentStatus.getSimulationTime()));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Check ground hit after liftoff
|
||||
if (status.getRocketPosition().z < 0) {
|
||||
status.setRocketPosition(status.getRocketPosition().setZ(0));
|
||||
addEvent(new FlightEvent(FlightEvent.Type.GROUND_HIT, status.getSimulationTime()));
|
||||
addEvent(new FlightEvent(FlightEvent.Type.SIMULATION_END, status.getSimulationTime()));
|
||||
if (currentStatus.getRocketPosition().z < 0) {
|
||||
currentStatus.setRocketPosition(currentStatus.getRocketPosition().setZ(0));
|
||||
addEvent(new FlightEvent(FlightEvent.Type.GROUND_HIT, currentStatus.getSimulationTime()));
|
||||
addEvent(new FlightEvent(FlightEvent.Type.SIMULATION_END, currentStatus.getSimulationTime()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Check for launch guide clearance
|
||||
if (!status.isLaunchRodCleared() &&
|
||||
relativePosition.length() > status.getSimulationConditions().getLaunchRodLength()) {
|
||||
addEvent(new FlightEvent(FlightEvent.Type.LAUNCHROD, status.getSimulationTime(), null));
|
||||
if (!currentStatus.isLaunchRodCleared() &&
|
||||
relativePosition.length() > currentStatus.getSimulationConditions().getLaunchRodLength()) {
|
||||
addEvent(new FlightEvent(FlightEvent.Type.LAUNCHROD, currentStatus.getSimulationTime(), null));
|
||||
}
|
||||
|
||||
|
||||
// Check for apogee
|
||||
if (!status.isApogeeReached() && status.getRocketPosition().z < status.getMaxAlt() - 0.01) {
|
||||
status.setMaxAltTime(status.getSimulationTime());
|
||||
addEvent(new FlightEvent(FlightEvent.Type.APOGEE, status.getSimulationTime(),
|
||||
status.getConfiguration().getRocket()));
|
||||
if (!currentStatus.isApogeeReached() && currentStatus.getRocketPosition().z < currentStatus.getMaxAlt() - 0.01) {
|
||||
currentStatus.setMaxAltTime(currentStatus.getSimulationTime());
|
||||
addEvent(new FlightEvent(FlightEvent.Type.APOGEE, currentStatus.getSimulationTime(),
|
||||
currentStatus.getConfiguration().getRocket()));
|
||||
}
|
||||
|
||||
|
||||
// Check for burnt out motors
|
||||
for( MotorInstance motor : status.getConfiguration().getAllMotors()){
|
||||
for( MotorInstance motor : currentStatus.getConfiguration().getAllMotors()){
|
||||
MotorInstanceId motorId = motor.getID();
|
||||
if (!motor.isActive() && status.addBurntOutMotor(motorId)) {
|
||||
addEvent(new FlightEvent(FlightEvent.Type.BURNOUT, status.getSimulationTime(),
|
||||
if (!motor.isActive() && currentStatus.addBurntOutMotor(motorId)) {
|
||||
addEvent(new FlightEvent(FlightEvent.Type.BURNOUT, currentStatus.getSimulationTime(),
|
||||
(RocketComponent) motor.getMount(), motorId));
|
||||
}
|
||||
}
|
||||
@ -217,23 +224,23 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
// and aoa > AOA_TUMBLE_CONDITION threshold
|
||||
// and thrust < THRUST_TUMBLE_CONDITION threshold
|
||||
|
||||
if (!status.isTumbling()) {
|
||||
final double t = status.getFlightData().getLast(FlightDataType.TYPE_THRUST_FORCE);
|
||||
final double cp = status.getFlightData().getLast(FlightDataType.TYPE_CP_LOCATION);
|
||||
final double cg = status.getFlightData().getLast(FlightDataType.TYPE_CG_LOCATION);
|
||||
final double aoa = status.getFlightData().getLast(FlightDataType.TYPE_AOA);
|
||||
if (!currentStatus.isTumbling()) {
|
||||
final double t = currentStatus.getFlightData().getLast(FlightDataType.TYPE_THRUST_FORCE);
|
||||
final double cp = currentStatus.getFlightData().getLast(FlightDataType.TYPE_CP_LOCATION);
|
||||
final double cg = currentStatus.getFlightData().getLast(FlightDataType.TYPE_CG_LOCATION);
|
||||
final double aoa = currentStatus.getFlightData().getLast(FlightDataType.TYPE_AOA);
|
||||
|
||||
final boolean wantToTumble = (cg > cp && aoa > AOA_TUMBLE_CONDITION);
|
||||
|
||||
if (wantToTumble) {
|
||||
final boolean tooMuchThrust = t > THRUST_TUMBLE_CONDITION;
|
||||
//final boolean isSustainer = status.getConfiguration().isStageActive(0);
|
||||
final boolean isApogee = status.isApogeeReached();
|
||||
final boolean isApogee = currentStatus.isApogeeReached();
|
||||
if (tooMuchThrust) {
|
||||
status.getWarnings().add(Warning.TUMBLE_UNDER_THRUST);
|
||||
currentStatus.getWarnings().add(Warning.TUMBLE_UNDER_THRUST);
|
||||
} else if (isApogee) {
|
||||
addEvent(new FlightEvent(FlightEvent.Type.TUMBLE, status.getSimulationTime()));
|
||||
status.setTumbling(true);
|
||||
addEvent(new FlightEvent(FlightEvent.Type.TUMBLE, currentStatus.getSimulationTime()));
|
||||
currentStatus.setTumbling(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,13 +249,13 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
}
|
||||
|
||||
} catch (SimulationException e) {
|
||||
SimulationListenerHelper.fireEndSimulation(status, e);
|
||||
SimulationListenerHelper.fireEndSimulation(currentStatus, e);
|
||||
// Add FlightEvent for Abort.
|
||||
status.getFlightData().addEvent(new FlightEvent(FlightEvent.Type.EXCEPTION, status.getSimulationTime(), status.getConfiguration().getRocket(), e.getLocalizedMessage()));
|
||||
status.getWarnings().add(e.getLocalizedMessage());
|
||||
currentStatus.getFlightData().addEvent(new FlightEvent(FlightEvent.Type.EXCEPTION, currentStatus.getSimulationTime(), currentStatus.getConfiguration().getRocket(), e.getLocalizedMessage()));
|
||||
currentStatus.getWarnings().add(e.getLocalizedMessage());
|
||||
}
|
||||
|
||||
return status.getFlightData();
|
||||
return currentStatus.getFlightData();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -260,18 +267,18 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
boolean ret = true;
|
||||
FlightEvent event;
|
||||
|
||||
log.trace("HandleEvents: current branch = " + status.getFlightData().getBranchName());
|
||||
log.trace("EventQueue = " + status.getEventQueue().toString());
|
||||
log.trace("HandleEvents: current branch = " + currentStatus.getFlightData().getBranchName());
|
||||
log.trace("EventQueue = " + currentStatus.getEventQueue().toString());
|
||||
for (event = nextEvent(); event != null; event = nextEvent()) {
|
||||
|
||||
// Ignore events for components that are no longer attached to the rocket
|
||||
if (event.getSource() != null && event.getSource().getParent() != null &&
|
||||
!status.getConfiguration().isComponentActive(event.getSource())) {
|
||||
!currentStatus.getConfiguration().isComponentActive(event.getSource())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Call simulation listeners, allow aborting event handling
|
||||
if (!SimulationListenerHelper.fireHandleFlightEvent(status, event)) {
|
||||
if (!SimulationListenerHelper.fireHandleFlightEvent(currentStatus, event)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -279,25 +286,27 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
log.trace("BasicEventSimulationEngine: Handling event " + event);
|
||||
}
|
||||
|
||||
log.trace(String.format(" >> about to ignite motors events"));
|
||||
if (event.getType() == FlightEvent.Type.IGNITION) {
|
||||
MotorMount mount = (MotorMount) event.getSource();
|
||||
MotorInstanceId motorId = (MotorInstanceId) event.getData();
|
||||
MotorInstance instance = status.getMotor(motorId);
|
||||
if (!SimulationListenerHelper.fireMotorIgnition(status, motorId, mount, instance)) {
|
||||
MotorInstance instance = currentStatus.getMotor(motorId);
|
||||
if (!SimulationListenerHelper.fireMotorIgnition(currentStatus, motorId, mount, instance)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
log.trace(String.format(" >> about to fire motors (?) events"));
|
||||
if (event.getType() == FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT) {
|
||||
RecoveryDevice device = (RecoveryDevice) event.getSource();
|
||||
if (!SimulationListenerHelper.fireRecoveryDeviceDeployment(status, device)) {
|
||||
if (!SimulationListenerHelper.fireRecoveryDeviceDeployment(currentStatus, device)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
log.trace(String.format(" >> about to check for motors ignite events"));
|
||||
|
||||
// Check for motor ignition events, add ignition events to queue
|
||||
for (MotorInstance motor : status.getFlightConfiguration().getActiveMotors() ){
|
||||
for (MotorInstance motor : currentStatus.getFlightConfiguration().getActiveMotors() ){
|
||||
MotorInstanceId mid = motor.getID();
|
||||
IgnitionEvent ignitionEvent = motor.getIgnitionEvent();
|
||||
MotorMount mount = motor.getMount();
|
||||
@ -306,7 +315,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
if (ignitionEvent.isActivationEvent(event, component)) {
|
||||
double ignitionDelay = motor.getIgnitionDelay();
|
||||
addEvent(new FlightEvent(FlightEvent.Type.IGNITION,
|
||||
status.getSimulationTime() + ignitionDelay,
|
||||
currentStatus.getSimulationTime() + ignitionDelay,
|
||||
component, mid));
|
||||
}
|
||||
}
|
||||
@ -314,7 +323,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
|
||||
// Check for stage separation event
|
||||
|
||||
for (AxialStage stage : status.getConfiguration().getActiveStages()) {
|
||||
for (AxialStage stage : currentStatus.getConfiguration().getActiveStages()) {
|
||||
int stageNo = stage.getStageNumber();
|
||||
if (stageNo == 0)
|
||||
continue;
|
||||
@ -328,7 +337,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
|
||||
|
||||
// Check for recovery device deployment, add events to queue
|
||||
for (RocketComponent c : status.getConfiguration().getActiveComponents()) {
|
||||
for (RocketComponent c : currentStatus.getConfiguration().getActiveComponents()) {
|
||||
if (!(c instanceof RecoveryDevice))
|
||||
continue;
|
||||
DeploymentConfiguration deployConfig = ((RecoveryDevice) c).getDeploymentConfigurations().get(this.fcid);
|
||||
@ -339,92 +348,92 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
}
|
||||
}
|
||||
|
||||
log.trace(String.format(" >> about to handle events"));
|
||||
|
||||
// Handle event
|
||||
switch (event.getType()) {
|
||||
|
||||
case LAUNCH: {
|
||||
status.getFlightData().addEvent(event);
|
||||
currentStatus.getFlightData().addEvent(event);
|
||||
break;
|
||||
}
|
||||
|
||||
case IGNITION: {
|
||||
// Ignite the motor
|
||||
MotorInstanceId motorId = (MotorInstanceId) event.getData();
|
||||
MotorInstance inst = status.getMotor( motorId);
|
||||
MotorInstance inst = currentStatus.getMotor( motorId);
|
||||
inst.setIgnitionTime(event.getTime());
|
||||
|
||||
status.setMotorIgnited(true);
|
||||
status.getFlightData().addEvent(event);
|
||||
currentStatus.setMotorIgnited(true);
|
||||
currentStatus.getFlightData().addEvent(event);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LIFTOFF: {
|
||||
// Mark lift-off as occurred
|
||||
status.setLiftoff(true);
|
||||
status.getFlightData().addEvent(event);
|
||||
currentStatus.setLiftoff(true);
|
||||
currentStatus.getFlightData().addEvent(event);
|
||||
break;
|
||||
}
|
||||
|
||||
case LAUNCHROD: {
|
||||
// Mark launch rod as cleared
|
||||
status.setLaunchRodCleared(true);
|
||||
status.getFlightData().addEvent(event);
|
||||
currentStatus.setLaunchRodCleared(true);
|
||||
currentStatus.getFlightData().addEvent(event);
|
||||
break;
|
||||
}
|
||||
|
||||
case BURNOUT: {
|
||||
// If motor burnout occurs without lift-off, abort
|
||||
if (!status.isLiftoff()) {
|
||||
if (!currentStatus.isLiftoff()) {
|
||||
throw new SimulationLaunchException(trans.get("BasicEventSimulationEngine.error.earlyMotorBurnout"));
|
||||
}
|
||||
// Add ejection charge event
|
||||
MotorInstanceId motorId = (MotorInstanceId) event.getData();
|
||||
MotorInstance motor = status.getMotor( motorId);
|
||||
MotorInstance motor = currentStatus.getMotor( motorId);
|
||||
double delay = motor.getEjectionDelay();
|
||||
if (delay != Motor.PLUGGED) {
|
||||
addEvent(new FlightEvent(FlightEvent.Type.EJECTION_CHARGE, status.getSimulationTime() + delay,
|
||||
addEvent(new FlightEvent(FlightEvent.Type.EJECTION_CHARGE, currentStatus.getSimulationTime() + delay,
|
||||
event.getSource(), event.getData()));
|
||||
}
|
||||
status.getFlightData().addEvent(event);
|
||||
currentStatus.getFlightData().addEvent(event);
|
||||
break;
|
||||
}
|
||||
|
||||
case EJECTION_CHARGE: {
|
||||
status.getFlightData().addEvent(event);
|
||||
currentStatus.getFlightData().addEvent(event);
|
||||
break;
|
||||
}
|
||||
|
||||
case STAGE_SEPARATION: {
|
||||
// Record the event.
|
||||
status.getFlightData().addEvent(event);
|
||||
|
||||
RocketComponent stage = event.getSource();
|
||||
int n = stage.getStageNumber();
|
||||
currentStatus.getFlightData().addEvent(event);
|
||||
|
||||
RocketComponent boosterStage = event.getSource();
|
||||
int stageNumber = boosterStage.getStageNumber();
|
||||
|
||||
// Prepare the booster status for simulation.
|
||||
SimulationStatus boosterStatus = new SimulationStatus(status);
|
||||
boosterStatus.setFlightData(new FlightDataBranch(stage.getName(), FlightDataType.TYPE_TIME));
|
||||
|
||||
stages.add(boosterStatus);
|
||||
SimulationStatus boosterStatus = new SimulationStatus(currentStatus);
|
||||
boosterStatus.setFlightData(new FlightDataBranch(boosterStage.getName(), FlightDataType.TYPE_TIME));
|
||||
// Mark the booster status as only having the booster.
|
||||
boosterStatus.getConfiguration().setOnlyStage(stageNumber);
|
||||
toSimulate.add(boosterStatus);
|
||||
|
||||
// Mark the status as having dropped the booster
|
||||
status.getConfiguration().clearOnlyStage(n);
|
||||
currentStatus.getConfiguration().clearStage( stageNumber);
|
||||
|
||||
// Mark the booster status as only having the booster.
|
||||
boosterStatus.getConfiguration().setOnlyStage(n);
|
||||
break;
|
||||
}
|
||||
|
||||
case APOGEE:
|
||||
// Mark apogee as reached
|
||||
status.setApogeeReached(true);
|
||||
status.getFlightData().addEvent(event);
|
||||
currentStatus.setApogeeReached(true);
|
||||
currentStatus.getFlightData().addEvent(event);
|
||||
// This apogee event might be the optimum if recovery has not already happened.
|
||||
if (status.getSimulationConditions().isCalculateExtras() && status.getDeployedRecoveryDevices().size() == 0) {
|
||||
status.getFlightData().setOptimumAltitude(status.getMaxAlt());
|
||||
status.getFlightData().setTimeToOptimumAltitude(status.getMaxAltTime());
|
||||
if (currentStatus.getSimulationConditions().isCalculateExtras() && currentStatus.getDeployedRecoveryDevices().size() == 0) {
|
||||
currentStatus.getFlightData().setOptimumAltitude(currentStatus.getMaxAlt());
|
||||
currentStatus.getFlightData().setTimeToOptimumAltitude(currentStatus.getMaxAltTime());
|
||||
}
|
||||
break;
|
||||
|
||||
@ -432,54 +441,54 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
RocketComponent c = event.getSource();
|
||||
int n = c.getStageNumber();
|
||||
// Ignore event if stage not active
|
||||
if (status.getConfiguration().isStageActive(n)) {
|
||||
if (currentStatus.getConfiguration().isStageActive(n)) {
|
||||
// TODO: HIGH: Check stage activeness for other events as well?
|
||||
|
||||
// Check whether any motor in the active stages is active anymore
|
||||
List<MotorInstance> activeMotors = status.getConfiguration().getActiveMotors();
|
||||
List<MotorInstance> activeMotors = currentStatus.getConfiguration().getActiveMotors();
|
||||
for (MotorInstance curMotor : activeMotors) {
|
||||
RocketComponent comp = ((RocketComponent) curMotor.getMount());
|
||||
int stageNumber = comp.getStageNumber();
|
||||
if (!status.getConfiguration().isStageActive(stageNumber))
|
||||
if (!currentStatus.getConfiguration().isStageActive(stageNumber))
|
||||
continue;
|
||||
status.getWarnings().add(Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING);
|
||||
currentStatus.getWarnings().add(Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING);
|
||||
}
|
||||
|
||||
// Check for launch rod
|
||||
if (!status.isLaunchRodCleared()) {
|
||||
status.getWarnings().add(Warning.RECOVERY_LAUNCH_ROD);
|
||||
if (!currentStatus.isLaunchRodCleared()) {
|
||||
currentStatus.getWarnings().add(Warning.RECOVERY_LAUNCH_ROD);
|
||||
}
|
||||
|
||||
// Check current velocity
|
||||
if (status.getRocketVelocity().length() > 20) {
|
||||
status.getWarnings().add(new Warning.HighSpeedDeployment(status.getRocketVelocity().length()));
|
||||
if (currentStatus.getRocketVelocity().length() > 20) {
|
||||
currentStatus.getWarnings().add(new Warning.HighSpeedDeployment(currentStatus.getRocketVelocity().length()));
|
||||
}
|
||||
|
||||
status.setLiftoff(true);
|
||||
status.getDeployedRecoveryDevices().add((RecoveryDevice) c);
|
||||
currentStatus.setLiftoff(true);
|
||||
currentStatus.getDeployedRecoveryDevices().add((RecoveryDevice) c);
|
||||
|
||||
// If we haven't already reached apogee, then we need to compute the actual coast time
|
||||
// to determine the optimum altitude.
|
||||
if (status.getSimulationConditions().isCalculateExtras() && !status.isApogeeReached()) {
|
||||
if (currentStatus.getSimulationConditions().isCalculateExtras() && !currentStatus.isApogeeReached()) {
|
||||
FlightData coastStatus = computeCoastTime();
|
||||
status.getFlightData().setOptimumAltitude(coastStatus.getMaxAltitude());
|
||||
status.getFlightData().setTimeToOptimumAltitude(coastStatus.getTimeToApogee());
|
||||
currentStatus.getFlightData().setOptimumAltitude(coastStatus.getMaxAltitude());
|
||||
currentStatus.getFlightData().setTimeToOptimumAltitude(coastStatus.getTimeToApogee());
|
||||
}
|
||||
|
||||
this.currentStepper = this.landingStepper;
|
||||
this.status = currentStepper.initialize(status);
|
||||
this.currentStatus = currentStepper.initialize(currentStatus);
|
||||
|
||||
status.getFlightData().addEvent(event);
|
||||
currentStatus.getFlightData().addEvent(event);
|
||||
}
|
||||
break;
|
||||
|
||||
case GROUND_HIT:
|
||||
status.getFlightData().addEvent(event);
|
||||
currentStatus.getFlightData().addEvent(event);
|
||||
break;
|
||||
|
||||
case SIMULATION_END:
|
||||
ret = false;
|
||||
status.getFlightData().addEvent(event);
|
||||
currentStatus.getFlightData().addEvent(event);
|
||||
break;
|
||||
|
||||
case ALTITUDE:
|
||||
@ -487,8 +496,8 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
|
||||
case TUMBLE:
|
||||
this.currentStepper = this.tumbleStepper;
|
||||
this.status = currentStepper.initialize(status);
|
||||
status.getFlightData().addEvent(event);
|
||||
this.currentStatus = currentStepper.initialize(currentStatus);
|
||||
currentStatus.getFlightData().addEvent(event);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -496,7 +505,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
|
||||
|
||||
// If no motor has ignited, abort
|
||||
if (!status.isMotorIgnited()) {
|
||||
if (!currentStatus.isMotorIgnited()) {
|
||||
throw new MotorIgnitionException(trans.get("BasicEventSimulationEngine.error.noIgnition"));
|
||||
}
|
||||
|
||||
@ -509,8 +518,8 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
* @param event the event to add to the queue.
|
||||
*/
|
||||
private void addEvent(FlightEvent event) throws SimulationException {
|
||||
if (SimulationListenerHelper.fireAddFlightEvent(status, event)) {
|
||||
status.getEventQueue().add(event);
|
||||
if (SimulationListenerHelper.fireAddFlightEvent(currentStatus, event)) {
|
||||
currentStatus.getEventQueue().add(event);
|
||||
}
|
||||
}
|
||||
|
||||
@ -524,16 +533,16 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
* @return the flight event to handle, or null
|
||||
*/
|
||||
private FlightEvent nextEvent() {
|
||||
EventQueue queue = status.getEventQueue();
|
||||
EventQueue queue = currentStatus.getEventQueue();
|
||||
FlightEvent event = queue.peek();
|
||||
if (event == null)
|
||||
return null;
|
||||
|
||||
// Jump to event if no motors have been ignited
|
||||
if (!status.isMotorIgnited() && event.getTime() > status.getSimulationTime()) {
|
||||
status.setSimulationTime(event.getTime());
|
||||
if (!currentStatus.isMotorIgnited() && event.getTime() > currentStatus.getSimulationTime()) {
|
||||
currentStatus.setSimulationTime(event.getTime());
|
||||
}
|
||||
if (event.getTime() <= status.getSimulationTime()) {
|
||||
if (event.getTime() <= currentStatus.getSimulationTime()) {
|
||||
return queue.poll();
|
||||
} else {
|
||||
return null;
|
||||
@ -545,30 +554,30 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
private void checkNaN() throws SimulationException {
|
||||
double d = 0;
|
||||
boolean b = false;
|
||||
d += status.getSimulationTime();
|
||||
d += status.getPreviousTimeStep();
|
||||
b |= status.getRocketPosition().isNaN();
|
||||
b |= status.getRocketVelocity().isNaN();
|
||||
b |= status.getRocketOrientationQuaternion().isNaN();
|
||||
b |= status.getRocketRotationVelocity().isNaN();
|
||||
d += status.getEffectiveLaunchRodLength();
|
||||
d += currentStatus.getSimulationTime();
|
||||
d += currentStatus.getPreviousTimeStep();
|
||||
b |= currentStatus.getRocketPosition().isNaN();
|
||||
b |= currentStatus.getRocketVelocity().isNaN();
|
||||
b |= currentStatus.getRocketOrientationQuaternion().isNaN();
|
||||
b |= currentStatus.getRocketRotationVelocity().isNaN();
|
||||
d += currentStatus.getEffectiveLaunchRodLength();
|
||||
|
||||
if (Double.isNaN(d) || b) {
|
||||
log.error("Simulation resulted in NaN value:" +
|
||||
" simulationTime=" + status.getSimulationTime() +
|
||||
" previousTimeStep=" + status.getPreviousTimeStep() +
|
||||
" rocketPosition=" + status.getRocketPosition() +
|
||||
" rocketVelocity=" + status.getRocketVelocity() +
|
||||
" rocketOrientationQuaternion=" + status.getRocketOrientationQuaternion() +
|
||||
" rocketRotationVelocity=" + status.getRocketRotationVelocity() +
|
||||
" effectiveLaunchRodLength=" + status.getEffectiveLaunchRodLength());
|
||||
" simulationTime=" + currentStatus.getSimulationTime() +
|
||||
" previousTimeStep=" + currentStatus.getPreviousTimeStep() +
|
||||
" rocketPosition=" + currentStatus.getRocketPosition() +
|
||||
" rocketVelocity=" + currentStatus.getRocketVelocity() +
|
||||
" rocketOrientationQuaternion=" + currentStatus.getRocketOrientationQuaternion() +
|
||||
" rocketRotationVelocity=" + currentStatus.getRocketRotationVelocity() +
|
||||
" effectiveLaunchRodLength=" + currentStatus.getEffectiveLaunchRodLength());
|
||||
throw new SimulationException(trans.get("BasicEventSimulationEngine.error.NaNResult"));
|
||||
}
|
||||
}
|
||||
|
||||
private FlightData computeCoastTime() {
|
||||
try {
|
||||
SimulationConditions conds = status.getSimulationConditions().clone();
|
||||
SimulationConditions conds = currentStatus.getSimulationConditions().clone();
|
||||
conds.getSimulationListenerList().add(OptimumCoastListener.INSTANCE);
|
||||
BasicEventSimulationEngine e = new BasicEventSimulationEngine();
|
||||
|
||||
|
||||
@ -25,8 +25,9 @@ import net.sf.openrocket.util.WorldCoordinate;
|
||||
*
|
||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||
*/
|
||||
|
||||
public class SimulationStatus implements Monitorable {
|
||||
|
||||
|
||||
private SimulationConditions simulationConditions;
|
||||
private FlightConfiguration configuration;
|
||||
private FlightDataBranch flightData;
|
||||
@ -235,7 +236,7 @@ public class SimulationStatus implements Monitorable {
|
||||
}
|
||||
|
||||
public MotorInstance getMotor( final MotorInstanceId motorId ){
|
||||
return this.getFlightConfiguration().getMotor(motorId);
|
||||
return this.getFlightConfiguration().getMotorInstance(motorId);
|
||||
}
|
||||
|
||||
public double getPreviousTimeStep() {
|
||||
|
||||
@ -9,7 +9,12 @@ import java.util.EventObject;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sf.openrocket.motor.Manufacturer;
|
||||
import net.sf.openrocket.motor.Motor;
|
||||
import net.sf.openrocket.motor.MotorInstance;
|
||||
import net.sf.openrocket.motor.ThrustCurveMotor;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent.Position;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.StateChangeListener;
|
||||
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
|
||||
|
||||
@ -97,7 +102,6 @@ public class ConfigurationTest extends BaseTestCase {
|
||||
// TODO rocket has no motors! assertTrue(config.hasMotors());
|
||||
|
||||
// rocket info tests
|
||||
|
||||
double length = config.getLength();
|
||||
double refLength = config.getReferenceLength();
|
||||
double refArea = config.getReferenceArea();
|
||||
@ -191,16 +195,17 @@ public class ConfigurationTest extends BaseTestCase {
|
||||
|
||||
// test explicitly setting all stages up to second stage active
|
||||
config.setOnlyStage(1);
|
||||
assertThat(config.toStageListDetail() + "Setting single stage active: ", config.isStageActive(0), equalTo(false));
|
||||
assertThat(config.toStageListDetail() + "Setting single stage active: ", config.isStageActive(1), equalTo(true));
|
||||
|
||||
config.clearOnlyStage(0);
|
||||
config.clearStage(0);
|
||||
assertThat(" deactivate stage #0: ", config.isStageActive(0), equalTo(false));
|
||||
assertThat(" deactive stage #0: ", config.isStageActive(1), equalTo(true));
|
||||
assertThat(" active stage #1: ", config.isStageActive(1), equalTo(true));
|
||||
|
||||
// test explicitly setting all two stages active
|
||||
config.setAllStages();
|
||||
assertThat(" activate all stages: check #0: ", config.isStageActive(0), equalTo(true));
|
||||
assertThat(" activate all stages: check #1: ", config.isStageActive(1), equalTo(true));
|
||||
assertThat(" activate all stages: check stage #0: ", config.isStageActive(0), equalTo(true));
|
||||
assertThat(" activate all stages: check stage #1: ", config.isStageActive(1), equalTo(true));
|
||||
|
||||
// test toggling single stage
|
||||
config.setAllStages();
|
||||
@ -218,6 +223,48 @@ public class ConfigurationTest extends BaseTestCase {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Multi stage rocket specific configuration tests
|
||||
*/
|
||||
@Test
|
||||
public void testMotorClusters() {
|
||||
|
||||
/* Setup */
|
||||
Rocket rkt = makeTwoStageMotorRocket();
|
||||
FlightConfiguration config = rkt.getDefaultConfiguration();
|
||||
|
||||
|
||||
config.clearAllStages();
|
||||
int expectedMotorCount = 0;
|
||||
int actualMotorCount = config.getActiveMotors().size();
|
||||
assertThat("motor count doesn't match", actualMotorCount, equalTo(expectedMotorCount));
|
||||
|
||||
config.setOnlyStage(0);
|
||||
expectedMotorCount = 1;
|
||||
actualMotorCount = config.getActiveMotors().size();
|
||||
assertThat("motor count doesn't match: ", actualMotorCount, equalTo(expectedMotorCount));
|
||||
|
||||
config.setOnlyStage(1);
|
||||
expectedMotorCount = 2;
|
||||
actualMotorCount = config.getActiveMotors().size();
|
||||
assertThat("motor count doesn't match: ", actualMotorCount, equalTo(expectedMotorCount));
|
||||
|
||||
config.setAllStages();
|
||||
expectedMotorCount = 3;
|
||||
// {
|
||||
// System.err.println("Booster Stage only: config set detail: "+rkt.getConfigSet().toDebug());
|
||||
// System.err.println("Booster Stage only: config stage detail: "+config.toStageListDetail());
|
||||
// System.err.println("Booster Stage only: config motor detail: "+config.toMotorDetail());
|
||||
// config.enableDebugging();
|
||||
// config.updateMotors();
|
||||
// config.getActiveMotors();
|
||||
// }
|
||||
actualMotorCount = config.getActiveMotors().size();
|
||||
assertThat("motor count doesn't match: ", actualMotorCount, equalTo(expectedMotorCount));
|
||||
|
||||
|
||||
}
|
||||
|
||||
///////////////////// Helper Methods ////////////////////////////
|
||||
//
|
||||
// public void validateStages(Configuration config, int expectedStageCount, BitSet activeStageFlags) {
|
||||
@ -344,7 +391,7 @@ public class ConfigurationTest extends BaseTestCase {
|
||||
|
||||
// Motor mount
|
||||
InnerTube inner = new InnerTube();
|
||||
|
||||
inner.setName("Sustainer MMT");
|
||||
inner.setPositionValue(0.5);
|
||||
inner.setRelativePosition(Position.BOTTOM);
|
||||
inner.setOuterRadius(1.9 / 2);
|
||||
@ -402,11 +449,20 @@ public class ConfigurationTest extends BaseTestCase {
|
||||
// Stage construction
|
||||
rocket.addChild(stage);
|
||||
rocket.setPerfectFinish(false);
|
||||
rocket.enableEvents();
|
||||
|
||||
final int expectedStageCount = 1;
|
||||
FlightConfiguration config = rocket.getDefaultConfiguration();
|
||||
assertThat(" configuration updates stage Count correctly: ", config.getActiveStageCount(), equalTo(expectedStageCount));
|
||||
assertThat(" configuration list contains : ", rocket.getConfigurationSet().size(), equalTo(1));
|
||||
assertThat(" rocket has incorrect stage count: ", rocket.getStageCount(), equalTo(expectedStageCount));
|
||||
|
||||
int expectedConfigurationCount = 0;
|
||||
assertThat(" configuration list contains : ", rocket.getConfigSet().size(), equalTo(expectedConfigurationCount));
|
||||
|
||||
FlightConfiguration newConfig = new FlightConfiguration(rocket,null);
|
||||
rocket.setFlightConfiguration( newConfig.getId(), newConfig);
|
||||
rocket.setDefaultConfiguration( newConfig.getId());
|
||||
assertThat(" configuration updates stage Count correctly: ", newConfig.getActiveStageCount(), equalTo(expectedStageCount));
|
||||
expectedConfigurationCount = 1;
|
||||
assertThat(" configuration list contains : ", rocket.getConfigSet().size(), equalTo(expectedConfigurationCount));
|
||||
|
||||
//FlightConfigurationID fcid = config.getFlightConfigurationID();
|
||||
// Motor m = Application.getMotorSetDatabase().findMotors(null, null, "L540", Double.NaN, Double.NaN).get(0);
|
||||
@ -465,10 +521,66 @@ public class ConfigurationTest extends BaseTestCase {
|
||||
finset.setBaseRotation(Math.PI / 2);
|
||||
boosterTube.addChild(finset);
|
||||
|
||||
// Motor mount
|
||||
InnerTube inner = new InnerTube();
|
||||
inner.setName("Booster MMT");
|
||||
inner.setPositionValue(0.5);
|
||||
inner.setRelativePosition(Position.BOTTOM);
|
||||
inner.setOuterRadius(1.9 / 2);
|
||||
inner.setInnerRadius(1.8 / 2);
|
||||
inner.setLength(7.5);
|
||||
boosterTube.addChild(inner);
|
||||
|
||||
rocket.addChild(stage);
|
||||
|
||||
return rocket;
|
||||
// already set in "makeSingleStageTestRocket()" above...
|
||||
// rocket.enableEvents();
|
||||
// FlightConfiguration newConfig = new FlightConfiguration(rocket,null);
|
||||
// rocket.setFlightConfiguration( newConfig.getId(), newConfig);
|
||||
|
||||
return rocket;
|
||||
}
|
||||
|
||||
public static Rocket makeTwoStageMotorRocket() {
|
||||
Rocket rocket = makeTwoStageTestRocket();
|
||||
FlightConfigurationID fcid = rocket.getDefaultConfiguration().getId();
|
||||
|
||||
{
|
||||
// public ThrustCurveMotor(Manufacturer manufacturer, String designation, String description,
|
||||
// Motor.Type type, double[] delays, double diameter, double length,
|
||||
// double[] time, double[] thrust,
|
||||
// Coordinate[] cg, String digest);
|
||||
ThrustCurveMotor sustainerMotor = new ThrustCurveMotor(
|
||||
Manufacturer.getManufacturer("AeroTech"),"D10", "Desc",
|
||||
Motor.Type.SINGLE, new double[] {3,5,7},0.018, 0.07,
|
||||
new double[] { 0, 1, 2 }, new double[] { 0, 25, 0 },
|
||||
new Coordinate[] {
|
||||
new Coordinate(.035, 0, 0, 0.026),new Coordinate(.035, 0, 0, .021),new Coordinate(.035, 0, 0, 0.016)},
|
||||
"digest D10 test");
|
||||
|
||||
InnerTube sustainerMount = (InnerTube) rocket.getChild(0).getChild(1).getChild(3);
|
||||
sustainerMount.setMotorMount(true);
|
||||
sustainerMount.setMotorInstance(fcid, sustainerMotor.getNewInstance());
|
||||
}
|
||||
|
||||
{
|
||||
// public ThrustCurveMotor(Manufacturer manufacturer, String designation, String description,
|
||||
// Motor.Type type, double[] delays, double diameter, double length,
|
||||
// double[] time, double[] thrust,
|
||||
// Coordinate[] cg, String digest);
|
||||
ThrustCurveMotor boosterMotor = new ThrustCurveMotor(
|
||||
Manufacturer.getManufacturer("AeroTech"),"D21", "Desc",
|
||||
Motor.Type.SINGLE, new double[] {}, 0.018, 0.07,
|
||||
new double[] { 0, 1, 2 }, new double[] { 0, 32, 0 },
|
||||
new Coordinate[] {
|
||||
new Coordinate(.035, 0, 0, 0.025),new Coordinate(.035, 0, 0, .020),new Coordinate(.035, 0, 0, 0.0154)},
|
||||
"digest D21 test");
|
||||
InnerTube boosterMount = (InnerTube) rocket.getChild(1).getChild(0).getChild(2);
|
||||
boosterMount.setMotorMount(true);
|
||||
boosterMount.setMotorInstance(fcid, boosterMotor.getNewInstance());
|
||||
boosterMount.setClusterConfiguration( ClusterConfiguration.CONFIGURATIONS[1]); // double-mount
|
||||
}
|
||||
return rocket;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -177,7 +177,7 @@ public class ComponentAnalysisDialog extends JDialog implements StateChangeListe
|
||||
label.setHorizontalAlignment(JLabel.RIGHT);
|
||||
panel.add(label, "growx, right");
|
||||
|
||||
ParameterSetModel<FlightConfiguration> psm = new ParameterSetModel<FlightConfiguration>( configuration.getRocket().getConfigurationSet());
|
||||
ParameterSetModel<FlightConfiguration> psm = new ParameterSetModel<FlightConfiguration>( configuration.getRocket().getConfigSet());
|
||||
JComboBox<FlightConfiguration> combo = new JComboBox<FlightConfiguration>(psm);
|
||||
panel.add(combo, "wrap");
|
||||
|
||||
|
||||
@ -40,7 +40,7 @@ public class RenameConfigDialog extends JDialog {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String newName = textbox.getText();
|
||||
rocket.getFlightConfiguration(fcid).setName( newName);
|
||||
System.err.println(rocket.getConfigurationSet().toDebug());
|
||||
System.err.println(rocket.getConfigSet().toDebug());
|
||||
RenameConfigDialog.this.setVisible(false);
|
||||
}
|
||||
});
|
||||
|
||||
@ -960,7 +960,7 @@ public class GeneralOptimizationDialog extends JDialog {
|
||||
simulations.add(new Named<Simulation>(s, name));
|
||||
}
|
||||
|
||||
for (FlightConfiguration config : rocket.getConfigurationSet()) {
|
||||
for (FlightConfiguration config : rocket.getConfigSet()) {
|
||||
FlightConfigurationID fcid = config.getFlightConfigurationID();
|
||||
if ( fcid == null) {
|
||||
throw new NullPointerException(" flightconfiguration has a null id... bug.");
|
||||
|
||||
@ -221,6 +221,7 @@ public class MotorConfigurationPanel extends FlightConfigurablePanel<MotorMount>
|
||||
MotorInstance curInstance = mtr.getNewInstance();
|
||||
//System.err.println(" >> new instance: "+curInstance.toString());
|
||||
curInstance.setEjectionDelay(d);
|
||||
curInstance.setIgnitionEvent( IgnitionEvent.AUTOMATIC);
|
||||
curMount.setMotorInstance( fcid, curInstance);
|
||||
|
||||
// DEBUG
|
||||
|
||||
@ -225,7 +225,7 @@ public class DesignReport {
|
||||
List<Simulation> simulations = rocketDocument.getSimulations();
|
||||
|
||||
int motorNumber = 0;
|
||||
for( FlightConfiguration curConfig : rocket.getConfigurationSet()){
|
||||
for( FlightConfiguration curConfig : rocket.getConfigSet()){
|
||||
FlightConfigurationID fcid = curConfig.getFlightConfigurationID();
|
||||
|
||||
PdfPTable parent = new PdfPTable(2);
|
||||
|
||||
@ -306,7 +306,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
|
||||
label.setHorizontalAlignment(JLabel.RIGHT);
|
||||
add(label, "growx, right");
|
||||
|
||||
ParameterSetModel<FlightConfiguration> psm = new ParameterSetModel<FlightConfiguration>( configuration.getRocket().getConfigurationSet());
|
||||
ParameterSetModel<FlightConfiguration> psm = new ParameterSetModel<FlightConfiguration>( configuration.getRocket().getConfigSet());
|
||||
JComboBox<FlightConfiguration> flightConfigurationComboBox = new JComboBox<FlightConfiguration>(psm);
|
||||
add(flightConfigurationComboBox, "wrap, width 16%, wmin 100");
|
||||
|
||||
@ -318,7 +318,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
|
||||
@SuppressWarnings("unchecked")
|
||||
JComboBox<FlightConfigurationID> box = (JComboBox<FlightConfigurationID>) source;
|
||||
FlightConfiguration newConfig = (FlightConfiguration)box.getSelectedItem();
|
||||
document.getRocket().getConfigurationSet().setDefault( newConfig);
|
||||
document.getRocket().getConfigSet().setDefault( newConfig);
|
||||
updateExtras();
|
||||
updateFigures();
|
||||
}
|
||||
|
||||
@ -149,7 +149,7 @@ public class SimulationEditDialog extends JDialog {
|
||||
label.setToolTipText(trans.get("simedtdlg.lbl.ttip.Flightcfg"));
|
||||
panel.add(label, "growx 0, gapright para");
|
||||
|
||||
ParameterSetModel<FlightConfiguration> psm = new ParameterSetModel<FlightConfiguration>( document.getRocket().getConfigurationSet());
|
||||
ParameterSetModel<FlightConfiguration> psm = new ParameterSetModel<FlightConfiguration>( document.getRocket().getConfigSet());
|
||||
final JComboBox<FlightConfiguration> configCombo = new JComboBox<FlightConfiguration>(psm);
|
||||
FlightConfiguration config = document.getRocket().getFlightConfiguration(simulation[0].getId());
|
||||
configCombo.setSelectedItem( config );
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user