From 729effd690548405c5f1017195ba3a85fe819ffa Mon Sep 17 00:00:00 2001 From: Daniel_M_Williams Date: Thu, 3 Dec 2015 21:44:34 -0500 Subject: [PATCH] [Bugfix] Merged FlightConfiguration MotorInstanceConfiguration fixed ignition configuration load / save --- .../AbstractAerodynamicCalculator.java | 6 +- .../file/openrocket/OpenRocketSaver.java | 2 +- .../importt/IgnitionConfigurationHandler.java | 13 - .../importt/MotorConfigurationHandler.java | 2 +- .../openrocket/importt/MotorMountHandler.java | 8 +- .../openrocket/savers/AxialStageSaver.java | 4 +- .../savers/RecoveryDeviceSaver.java | 2 +- .../file/openrocket/savers/RocketSaver.java | 2 +- .../file/rocksim/export/BodyTubeDTO.java | 2 +- .../sf/openrocket/motor/MotorInstance.java | 19 +- .../motor/MotorInstanceConfiguration.java | 241 ------------- .../rocketcomponent/FlightConfiguration.java | 274 ++++++++++++--- .../sf/openrocket/rocketcomponent/Rocket.java | 18 +- .../rocketcomponent/RocketComponent.java | 16 +- .../simulation/AbstractSimulationStepper.java | 1 + .../BasicEventSimulationEngine.java | 319 +++++++++--------- .../simulation/SimulationStatus.java | 5 +- .../rocketcomponent/ConfigurationTest.java | 132 +++++++- .../gui/dialogs/ComponentAnalysisDialog.java | 2 +- .../RenameConfigDialog.java | 2 +- .../GeneralOptimizationDialog.java | 2 +- .../MotorConfigurationPanel.java | 1 + .../sf/openrocket/gui/print/DesignReport.java | 2 +- .../gui/scalefigure/RocketPanel.java | 4 +- .../gui/simulation/SimulationEditDialog.java | 2 +- 25 files changed, 548 insertions(+), 533 deletions(-) delete mode 100644 core/src/net/sf/openrocket/motor/MotorInstanceConfiguration.java diff --git a/core/src/net/sf/openrocket/aerodynamics/AbstractAerodynamicCalculator.java b/core/src/net/sf/openrocket/aerodynamics/AbstractAerodynamicCalculator.java index 202c5dd03..b53acc4c1 100644 --- a/core/src/net/sf/openrocket/aerodynamics/AbstractAerodynamicCalculator.java +++ b/core/src/net/sf/openrocket/aerodynamics/AbstractAerodynamicCalculator.java @@ -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(); diff --git a/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java b/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java index 4acde1906..2c4b97eba 100644 --- a/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java @@ -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; diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/IgnitionConfigurationHandler.java b/core/src/net/sf/openrocket/file/openrocket/importt/IgnitionConfigurationHandler.java index f0317ac0a..c583d630c 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/IgnitionConfigurationHandler.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/IgnitionConfigurationHandler.java @@ -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 attributes, String content, WarningSet warnings) throws SAXException { diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/MotorConfigurationHandler.java b/core/src/net/sf/openrocket/file/openrocket/importt/MotorConfigurationHandler.java index 11c7bd675..b4f0dbd82 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/MotorConfigurationHandler.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/MotorConfigurationHandler.java @@ -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 fcs = rocket.getConfigurationSet(); + ParameterSet fcs = rocket.getConfigSet(); FlightConfiguration fc = fcs.get(fcid); fcs.setDefault(fc); } diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/MotorMountHandler.java b/core/src/net/sf/openrocket/file/openrocket/importt/MotorMountHandler.java index 211c39216..8a1fea22a 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/MotorMountHandler.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/MotorMountHandler.java @@ -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; } diff --git a/core/src/net/sf/openrocket/file/openrocket/savers/AxialStageSaver.java b/core/src/net/sf/openrocket/file/openrocket/savers/AxialStageSaver.java index 60649be25..b9740f33f 100644 --- a/core/src/net/sf/openrocket/file/openrocket/savers/AxialStageSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/savers/AxialStageSaver.java @@ -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; diff --git a/core/src/net/sf/openrocket/file/openrocket/savers/RecoveryDeviceSaver.java b/core/src/net/sf/openrocket/file/openrocket/savers/RecoveryDeviceSaver.java index ed37a1101..d13db610f 100644 --- a/core/src/net/sf/openrocket/file/openrocket/savers/RecoveryDeviceSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/savers/RecoveryDeviceSaver.java @@ -37,7 +37,7 @@ public class RecoveryDeviceSaver extends MassObjectSaver { //dev.getDeploymentConfigurations().printDebug(); // DEBUG - ParameterSet configList = rocket.getConfigurationSet(); + ParameterSet configList = rocket.getConfigSet(); for (FlightConfigurationID fcid : configList.getSortedConfigurationIDs()) { //System.err.println("checking FlightConfiguration:"+fcid.getShortKey()+ " save?"); diff --git a/core/src/net/sf/openrocket/file/openrocket/savers/RocketSaver.java b/core/src/net/sf/openrocket/file/openrocket/savers/RocketSaver.java index 28ff77620..6c3883b7e 100644 --- a/core/src/net/sf/openrocket/file/openrocket/savers/RocketSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/savers/RocketSaver.java @@ -43,7 +43,7 @@ public class RocketSaver extends RocketComponentSaver { // Motor configurations - ParameterSet allConfigs = rocket.getConfigurationSet(); + ParameterSet allConfigs = rocket.getConfigSet(); for (FlightConfigurationID fcid : allConfigs.getSortedConfigurationIDs()) { FlightConfiguration flightConfig = allConfigs.get(fcid); if (fcid == null) diff --git a/core/src/net/sf/openrocket/file/rocksim/export/BodyTubeDTO.java b/core/src/net/sf/openrocket/file/rocksim/export/BodyTubeDTO.java index 18c56f70e..97e404d95 100644 --- a/core/src/net/sf/openrocket/file/rocksim/export/BodyTubeDTO.java +++ b/core/src/net/sf/openrocket/file/rocksim/export/BodyTubeDTO.java @@ -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 attachedParts = new ArrayList(); + List attachedParts = new ArrayList(); /** * Constructor. diff --git a/core/src/net/sf/openrocket/motor/MotorInstance.java b/core/src/net/sf/openrocket/motor/MotorInstance.java index 8c5052285..461b57010 100644 --- a/core/src/net/sf/openrocket/motor/MotorInstance.java +++ b/core/src/net/sf/openrocket/motor/MotorInstance.java @@ -187,28 +187,13 @@ public class MotorInstance implements FlightConfigurableParameter @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; } diff --git a/core/src/net/sf/openrocket/motor/MotorInstanceConfiguration.java b/core/src/net/sf/openrocket/motor/MotorInstanceConfiguration.java deleted file mode 100644 index cdcd60b47..000000000 --- a/core/src/net/sf/openrocket/motor/MotorInstanceConfiguration.java +++ /dev/null @@ -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 - */ -public class MotorInstanceConfiguration implements Cloneable, Iterable, Monitorable { - protected final HashMap motors = new HashMap(); - 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 getAllMotors() { - return motors.values(); - } - - public int getMotorCount() { - return motors.size(); - } - - public Set 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 iterator() { - return this.motors.values().iterator(); - } - - public List getActiveMotors() { - List activeList = new ArrayList(); - 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(); - } - -} diff --git a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java index 8d4121281..6d8e35602 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java @@ -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 stages = new HashMap(); - final protected MotorInstanceConfiguration motors; + protected final HashMap motors = new HashMap(); private int boundsModID = -1; private ArrayList cachedBounds = new ArrayList(); @@ -67,6 +68,8 @@ public class FlightConfiguration implements FlightConfigurableParameterRocket. * @@ -82,13 +85,16 @@ public class FlightConfiguration implements FlightConfigurableParameter= 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 getActiveMotors() { - return this.motors.getActiveMotors(); - } - - public Collection getAllMotors() { - return this.motors.getAllMotors(); - } - - public boolean hasMotors() { - return this.motors.hasMotors(); - } public List getActiveStages() { List activeStages = new ArrayList(); @@ -241,10 +237,6 @@ public class FlightConfiguration implements FlightConfigurableParameterRocket. @@ -267,6 +259,10 @@ public class FlightConfiguration implements FlightConfigurableParameter \n", curMotor.getID().toShortKey())); }else{ @@ -378,7 +377,36 @@ public class FlightConfiguration implements FlightConfigurableParameter getAllMotors() { + return motors.values(); + } + + public int getMotorCount() { + return motors.size(); + } + + public Set 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 getActiveMotors() { + List activeList = new ArrayList(); + 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(); - config.stages.putAll( (Map) 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(); + clone.stages.putAll( (Map) this.stages); + clone.motors.putAll( (Map) 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 getConfigurationSet(){ + public ParameterSet getConfigSet(){ checkState(); return this.configSet; } diff --git a/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java b/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java index 88c0f997d..94316b5bc 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java +++ b/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java @@ -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 { // Stack holds iterators which still have some components left. - private final Stack> iteratorStack = new Stack>(); + private final Deque> iteratorStack = new ArrayDeque>(); private final Rocket root; private final int treeModID; diff --git a/core/src/net/sf/openrocket/simulation/AbstractSimulationStepper.java b/core/src/net/sf/openrocket/simulation/AbstractSimulationStepper.java index 8085dc066..4e07509f6 100644 --- a/core/src/net/sf/openrocket/simulation/AbstractSimulationStepper.java +++ b/core/src/net/sf/openrocket/simulation/AbstractSimulationStepper.java @@ -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 activeMotors = configuration.getActiveMotors(); for (MotorInstance currentMotorInstance : activeMotors) { thrust += currentMotorInstance.getThrust(); diff --git a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java index 5afb89a03..83d94189a 100644 --- a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java +++ b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java @@ -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 stages = new Stack(); -// protected ArrayList burningStages = new ArrayList(); -// protected ArrayList carriedStages = new ArrayList(); + // old: protected Stack stages = new Stack(); + // 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 toSimulate = new ArrayDeque(); @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("<> 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(oldAlt, status.getRocketPosition().z))); + addEvent(new FlightEvent(FlightEvent.Type.ALTITUDE, currentStatus.getSimulationTime(), + currentStatus.getConfiguration().getRocket(), + new Pair(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 activeMotors = status.getConfiguration().getActiveMotors(); + List 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(); diff --git a/core/src/net/sf/openrocket/simulation/SimulationStatus.java b/core/src/net/sf/openrocket/simulation/SimulationStatus.java index 17bac0059..b8b87b701 100644 --- a/core/src/net/sf/openrocket/simulation/SimulationStatus.java +++ b/core/src/net/sf/openrocket/simulation/SimulationStatus.java @@ -25,8 +25,9 @@ import net.sf.openrocket.util.WorldCoordinate; * * @author Sampo Niskanen */ + 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() { diff --git a/core/test/net/sf/openrocket/rocketcomponent/ConfigurationTest.java b/core/test/net/sf/openrocket/rocketcomponent/ConfigurationTest.java index 2286ed633..f063c18b4 100644 --- a/core/test/net/sf/openrocket/rocketcomponent/ConfigurationTest.java +++ b/core/test/net/sf/openrocket/rocketcomponent/ConfigurationTest.java @@ -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; } } diff --git a/swing/src/net/sf/openrocket/gui/dialogs/ComponentAnalysisDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/ComponentAnalysisDialog.java index 8df8fff9d..36807d1cf 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/ComponentAnalysisDialog.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/ComponentAnalysisDialog.java @@ -177,7 +177,7 @@ public class ComponentAnalysisDialog extends JDialog implements StateChangeListe label.setHorizontalAlignment(JLabel.RIGHT); panel.add(label, "growx, right"); - ParameterSetModel psm = new ParameterSetModel( configuration.getRocket().getConfigurationSet()); + ParameterSetModel psm = new ParameterSetModel( configuration.getRocket().getConfigSet()); JComboBox combo = new JComboBox(psm); panel.add(combo, "wrap"); diff --git a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RenameConfigDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RenameConfigDialog.java index a9422e5dd..43ae3b9ec 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RenameConfigDialog.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RenameConfigDialog.java @@ -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); } }); diff --git a/swing/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java index 5e9a1da1d..779dfc6e3 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java @@ -960,7 +960,7 @@ public class GeneralOptimizationDialog extends JDialog { simulations.add(new Named(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."); diff --git a/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/MotorConfigurationPanel.java b/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/MotorConfigurationPanel.java index 0c75d9938..cb859ca54 100644 --- a/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/MotorConfigurationPanel.java +++ b/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/MotorConfigurationPanel.java @@ -221,6 +221,7 @@ public class MotorConfigurationPanel extends FlightConfigurablePanel MotorInstance curInstance = mtr.getNewInstance(); //System.err.println(" >> new instance: "+curInstance.toString()); curInstance.setEjectionDelay(d); + curInstance.setIgnitionEvent( IgnitionEvent.AUTOMATIC); curMount.setMotorInstance( fcid, curInstance); // DEBUG diff --git a/swing/src/net/sf/openrocket/gui/print/DesignReport.java b/swing/src/net/sf/openrocket/gui/print/DesignReport.java index 8d387de9d..13b2d361c 100644 --- a/swing/src/net/sf/openrocket/gui/print/DesignReport.java +++ b/swing/src/net/sf/openrocket/gui/print/DesignReport.java @@ -225,7 +225,7 @@ public class DesignReport { List 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); diff --git a/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java b/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java index fabfdd3d4..fcead5a61 100644 --- a/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java +++ b/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java @@ -306,7 +306,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change label.setHorizontalAlignment(JLabel.RIGHT); add(label, "growx, right"); - ParameterSetModel psm = new ParameterSetModel( configuration.getRocket().getConfigurationSet()); + ParameterSetModel psm = new ParameterSetModel( configuration.getRocket().getConfigSet()); JComboBox flightConfigurationComboBox = new JComboBox(psm); add(flightConfigurationComboBox, "wrap, width 16%, wmin 100"); @@ -318,7 +318,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change @SuppressWarnings("unchecked") JComboBox box = (JComboBox) source; FlightConfiguration newConfig = (FlightConfiguration)box.getSelectedItem(); - document.getRocket().getConfigurationSet().setDefault( newConfig); + document.getRocket().getConfigSet().setDefault( newConfig); updateExtras(); updateFigures(); } diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java index cb18f8cca..a6107d627 100644 --- a/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java +++ b/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java @@ -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 psm = new ParameterSetModel( document.getRocket().getConfigurationSet()); + ParameterSetModel psm = new ParameterSetModel( document.getRocket().getConfigSet()); final JComboBox configCombo = new JComboBox(psm); FlightConfiguration config = document.getRocket().getFlightConfiguration(simulation[0].getId()); configCombo.setSelectedItem( config );