Initial refactoring of MotorInstance and ThrustCurveMotorInstance

This commit is contained in:
Kevin Ruland 2015-12-14 18:41:02 -06:00
parent d12f7b596f
commit 88f84396d0
26 changed files with 475 additions and 363 deletions

View File

@ -73,15 +73,17 @@ class MotorMountHandler extends AbstractElementHandler {
}
Motor motor = motorHandler.getMotor(warnings);
MotorInstance motorInstance = motor.getNewInstance();
MotorInstance motorInstance = new MotorInstance();
motorInstance.setMotor(motor);
RocketComponent mountComponent = (RocketComponent)mount;
motorInstance.setMount(mount);
motorInstance.setID( new MotorInstanceId(mountComponent.getID(), 1));
motorInstance.setEjectionDelay(motorHandler.getDelay(warnings));
mount.setMotorInstance(fcid, motorInstance);
Rocket rkt = ((RocketComponent)mount).getRocket();
rkt.createFlightConfiguration(fcid);
rkt.getFlightConfiguration(fcid).addMotor(motorInstance);
return;
}

View File

@ -1,5 +1,6 @@
package net.sf.openrocket.motor;
import net.sf.openrocket.simulation.MotorState;
import net.sf.openrocket.util.Coordinate;
public interface Motor {
@ -117,7 +118,7 @@ public interface Motor {
public String getDigest();
public MotorInstance getNewInstance();
public MotorState getNewInstance();
public Coordinate getLaunchCG();

View File

@ -3,91 +3,77 @@ package net.sf.openrocket.motor;
import java.util.EventObject;
import java.util.List;
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
import net.sf.openrocket.rocketcomponent.FlightConfigurableParameter;
import net.sf.openrocket.rocketcomponent.IgnitionEvent;
import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.simulation.MotorState;
import net.sf.openrocket.util.ArrayList;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.Inertia;
import net.sf.openrocket.util.StateChangeListener;
/**
* A single motor configuration. This includes the selected motor
* and the ejection charge delay.
*/
public abstract class MotorInstance implements FlightConfigurableParameter<MotorInstance> {
public class MotorInstance implements FlightConfigurableParameter<MotorInstance> {
// deferred to subclasses
//protected MotorMount mount = null;
//protected Motor motor = null;
protected MotorInstanceId id = null;
protected MotorMount mount = null;
protected Motor motor = null;
protected Coordinate position = Coordinate.ZERO;
protected double ejectionDelay = 0.0;
protected MotorInstanceId id = null;
protected boolean ignitionOveride = false;
protected double ignitionDelay = 0.0;
protected IgnitionEvent ignitionEvent = IgnitionEvent.NEVER;
protected Coordinate position = Coordinate.ZERO;
protected double ignitionTime = 0.0;
protected int modID = 0;
private final List<StateChangeListener> listeners = new ArrayList<StateChangeListener>();
/** Immutable configuration with no motor and zero delay. */
public static final MotorInstance EMPTY_INSTANCE = new MotorInstance(){
@Override
public boolean equals( Object other ){
return (this==other);
}
@Override
public Motor getMotor() {
throw new UnsupportedOperationException("Retrieve a motor from an immutable no-motors instance");
}
@Override
public MotorMount getMount() {
throw new UnsupportedOperationException("Retrieve a mount from an immutable no-motors instance");
}
@Override
public double getThrust() {
throw new UnsupportedOperationException("Trying to get thrust from an empty motor instance.");
}
@Override
public Coordinate getCM() {
throw new UnsupportedOperationException("Trying to get Center-of-Mass from an empty motor instance.");
}
@Override
public double getPropellantMass(){
throw new UnsupportedOperationException("Trying to get mass from an empty motor instance.");
}
@Override
public double getLongitudinalInertia() {
throw new UnsupportedOperationException("Trying to get inertia from an empty motor instance.");
}
@Override
public double getRotationalInertia() {
throw new UnsupportedOperationException("Trying to get inertia from an empty motor instance.");
}
@Override
public void step(double time, double acceleration, AtmosphericConditions cond) {
throw new UnsupportedOperationException("Cannot step an abstract base class");
}
};
public MotorInstance( Motor motor ) {
this();
this.motor = motor;
}
protected MotorInstance() {
public MotorInstance() {
this.id = MotorInstanceId.EMPTY_ID;
ejectionDelay = 0.0;
ignitionEvent = IgnitionEvent.NEVER;
ignitionEvent = IgnitionEvent.LAUNCH;
ignitionDelay = 0.0;
modID++;
}
public MotorState getSimulationState() {
MotorState state = motor.getNewInstance();
if( ignitionOveride ) {
state.setIgnitionTime( this.ignitionTime );
state.setIgnitionEvent( this.ignitionEvent );
state.setIgnitionDelay( this.ignitionDelay );
state.setEjectionDelay( this.ejectionDelay );
} else {
MotorInstance defInstance = mount.getDefaultMotorInstance();
state.setIgnitionTime( defInstance.ignitionTime );
state.setIgnitionEvent( defInstance.ignitionEvent );
state.setIgnitionDelay( defInstance.ignitionDelay );
state.setEjectionDelay( defInstance.ejectionDelay );
}
state.setMount( mount );
state.setId( id );
return state;
}
public boolean hasIgnitionOverride() {
return ignitionOveride;
}
public boolean isActive() {
return motor != null;
}
public MotorInstanceId getID() {
return this.id;
}
@ -96,22 +82,30 @@ public abstract class MotorInstance implements FlightConfigurableParameter<Motor
this.id = _id;
}
public void setMotor(Motor motor){
this.motor = motor;
fireChangeEvent();
}
public Motor getMotor() {
return motor;
}
public MotorMount getMount() {
return mount;
}
public void setMount(MotorMount mount) {
this.mount = mount;
}
public double getEjectionDelay() {
return this.ejectionDelay;
}
public void setMotor(Motor motor){}
public abstract Motor getMotor();
public void setEjectionDelay(double delay) {}
public abstract MotorMount getMount();
public void setMount(final MotorMount _mount){}
public Coordinate getOffset(){
return this.position;
public void setEjectionDelay(double delay) {
this.ejectionDelay = delay;
fireChangeEvent();
}
public Coordinate getPosition() {
@ -121,15 +115,22 @@ public abstract class MotorInstance implements FlightConfigurableParameter<Motor
public void setPosition(Coordinate _position) {
this.position = _position;
modID++;
fireChangeEvent();
}
public double getIgnitionTime() {
return this.ignitionTime;
}
public void useDefaultIgnition() {
this.ignitionOveride = false;
}
public void setIgnitionTime(double _time) {
this.ignitionTime = _time;
this.ignitionOveride = true;
modID++;
fireChangeEvent();
}
public double getIgnitionDelay() {
@ -138,6 +139,8 @@ public abstract class MotorInstance implements FlightConfigurableParameter<Motor
public void setIgnitionDelay(final double _delay) {
this.ignitionDelay = _delay;
this.ignitionOveride = true;
fireChangeEvent();
}
public IgnitionEvent getIgnitionEvent() {
@ -146,66 +149,47 @@ public abstract class MotorInstance implements FlightConfigurableParameter<Motor
public void setIgnitionEvent(final IgnitionEvent _event) {
this.ignitionEvent = _event;
this.ignitionOveride = true;
fireChangeEvent();
}
/**
* Step the motor instance forward in time.
*
* @param time the time to step to, from motor ignition.
* @param acceleration the average acceleration during the step.
* @param cond the average atmospheric conditions during the step.
*/
public abstract void step(double newTime, double acceleration, AtmosphericConditions cond);
/**
* Return the time to which this motor has been stepped.
* @return the current step time.
*/
public double getTime() {
return 0;
public Coordinate getOffset( ){
if( null == mount ){
return Coordinate.NaN;
}else{
RocketComponent comp = (RocketComponent) mount;
double delta_x = comp.getLength() + mount.getMotorOverhang() - this.motor.getLength();
return new Coordinate(delta_x, 0, 0);
}
}
/**
* Return the average thrust during the last step.
*/
public abstract double getThrust();
/**
* Return the average CG location during the last step.
*/
public Coordinate getCG() {
return this.getCM();
public double getLongitudinalInertia() {
if ( motor != null ) {
double unitLongitudinalInertia = Inertia.filledCylinderLongitudinal(motor.getDiameter() / 2, motor.getLength());
return unitLongitudinalInertia * Coordinate.ZERO.weight;
}
return 0.0;
}
public abstract Coordinate getCM();
public abstract double getPropellantMass();
/**
* Return the average longitudinal moment of inertia during the last step.
* This is the actual inertia, not the unit inertia!
*/
public abstract double getLongitudinalInertia();
/**
* Return the average rotational moment of inertia during the last step.
* This is the actual inertia, not the unit inertia!
*/
public abstract double getRotationalInertia();
/**
* Return whether this motor still produces thrust. If this method returns false
* the motor has burnt out, and will not produce any significant thrust anymore.
*/
public boolean isActive() {
return false;
}
public boolean isEmpty(){
return true;
public double getRotationalInertia() {
if ( motor != null ) {
double unitRotationalInertia = Inertia.filledCylinderRotational(motor.getDiameter() / 2);
return unitRotationalInertia * Coordinate.ZERO.weight;
}
return 0.0;
}
public double getPropellantMass(){
if ( motor != null ) {
return (motor.getLaunchCG().weight - motor.getEmptyCG().weight);
}
return 0.0;
}
public boolean isEmpty(){
return motor == null;
}
public boolean hasMotor(){
return ! this.isEmpty();
}
@ -222,7 +206,7 @@ public abstract class MotorInstance implements FlightConfigurableParameter<Motor
}
return false;
}
@Override
public int hashCode() {
return this.id.hashCode();
@ -233,8 +217,16 @@ public abstract class MotorInstance implements FlightConfigurableParameter<Motor
* identical to this instance and can be used independently from this one.
*/
@Override
public MotorInstance clone( ){
return EMPTY_INSTANCE;
public MotorInstance clone( ) {
MotorInstance clone = new MotorInstance();
clone.motor = this.motor;
clone.mount = this.mount;
clone.ejectionDelay = this.ejectionDelay;
clone.ignitionOveride = this.ignitionOveride;
clone.ignitionDelay = this.ignitionDelay;
clone.ignitionEvent = this.ignitionEvent;
clone.ignitionTime = this.ignitionTime;
return clone;
}
@Override
@ -255,19 +247,8 @@ public abstract class MotorInstance implements FlightConfigurableParameter<Motor
}
}
public String toDebug(){ return toString();}
@Override
public String toString(){
return MotorInstanceId.EMPTY_ID.getComponentId();
}
public int getModID() {
return modID;
}
public void reset() {
}
}

View File

@ -13,7 +13,7 @@ public class MotorSet extends ParameterSet<MotorInstance> {
public static final int DEFAULT_MOTOR_EVENT_TYPE = ComponentChangeEvent.MOTOR_CHANGE | ComponentChangeEvent.EVENT_CHANGE;
public MotorSet(RocketComponent component ) {
super(component, DEFAULT_MOTOR_EVENT_TYPE, MotorInstance.EMPTY_INSTANCE);
super(component, DEFAULT_MOTOR_EVENT_TYPE, new MotorInstance());
}
/**
@ -45,7 +45,7 @@ public class MotorSet extends ParameterSet<MotorInstance> {
MotorInstance curInstance = this.map.get(loopFCID);
String designation;
if( MotorInstance.EMPTY_INSTANCE == curInstance){
if( null == curInstance.getMotor() ){
designation = "EMPTY_INSTANCE";
}else{
designation = curInstance.getMotor().getDesignation(curInstance.getEjectionDelay());

View File

@ -250,7 +250,7 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
@Override
public MotorInstance getNewInstance() {
public ThrustCurveMotorInstance getNewInstance() {
return new ThrustCurveMotorInstance(this);
}

View File

@ -1,19 +1,27 @@
package net.sf.openrocket.motor;
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
import net.sf.openrocket.rocketcomponent.IgnitionEvent;
import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.simulation.MotorState;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.Inertia;
import net.sf.openrocket.util.MathUtil;
import net.sf.openrocket.util.Utils;
public class ThrustCurveMotorInstance extends MotorInstance {
public class ThrustCurveMotorInstance implements MotorState {
// private static final Logger log = LoggerFactory.getLogger(ThrustCurveMotorInstance.class);
private int timeIndex = -1;
protected MotorMount mount = null;
protected MotorInstanceId id = null;
private double ignitionTime;
private double ignitionDelay;
private IgnitionEvent ignitionEvent;
private double ejectionDelay;
protected ThrustCurveMotor motor = null;
// Previous time step value
@ -47,46 +55,88 @@ public class ThrustCurveMotorInstance extends MotorInstance {
unitRotationalInertia = Inertia.filledCylinderRotational(source.getDiameter() / 2);
unitLongitudinalInertia = Inertia.filledCylinderLongitudinal(source.getDiameter() / 2, source.getLength());
this.id = MotorInstanceId.ERROR_ID;
}
@Override
public double getIgnitionTime() {
return ignitionTime;
}
@Override
public void setIgnitionTime(double ignitionTime) {
this.ignitionTime = ignitionTime;
}
@Override
public MotorMount getMount() {
return mount;
}
@Override
public void setMount(MotorMount mount) {
this.mount = mount;
}
@Override
public IgnitionEvent getIgnitionEvent() {
return ignitionEvent;
}
@Override
public void setIgnitionEvent(IgnitionEvent event) {
this.ignitionEvent = event;
}
@Override
public double getIgnitionDelay() {
return ignitionDelay;
}
@Override
public void setIgnitionDelay(double delay) {
this.ignitionDelay = delay;
}
@Override
public double getEjectionDelay() {
return ejectionDelay;
}
@Override
public void setEjectionDelay(double delay) {
this.ejectionDelay = delay;
}
@Override
public void setId(MotorInstanceId id) {
this.id = id;
}
@Override
public MotorInstanceId getID() {
return id;
}
public double getTime() {
return prevTime;
}
@Override
public Coordinate getCG() {
return stepCG;
}
@Override
public Coordinate getCM() {
return stepCG;
}
@Override
public double getPropellantMass(){
return (motor.getLaunchCG().weight - motor.getEmptyCG().weight);
}
@Override
public Coordinate getOffset( ){
if( null == mount ){
return Coordinate.NaN;
}else{
RocketComponent comp = (RocketComponent) mount;
double delta_x = comp.getLength() + mount.getMotorOverhang() - this.motor.getLength();
return new Coordinate(delta_x, 0, 0);
}
}
@Override
public double getLongitudinalInertia() {
return unitLongitudinalInertia * stepCG.weight;
}
@Override
public double getRotationalInertia() {
return unitRotationalInertia * stepCG.weight;
}
@ -100,60 +150,21 @@ public class ThrustCurveMotorInstance extends MotorInstance {
public boolean isActive() {
return prevTime < motor.getCutOffTime();
}
@Override
public void setMotor(Motor motor) {
if( !( motor instanceof ThrustCurveMotor )){
return;
}
if (Utils.equals(this.motor, motor)) {
return;
}
this.motor = (ThrustCurveMotor)motor;
fireChangeEvent();
}
@Override
public Motor getMotor(){
return this.motor;
}
@Override
public boolean isEmpty(){
return false;
}
@Override
public MotorMount getMount() {
return this.mount;
}
@Override
public void setMount(final MotorMount _mount) {
this.mount = _mount;
}
@Override
public void setEjectionDelay(double delay) {
if (MathUtil.equals(ejectionDelay, delay)) {
return;
}
this.ejectionDelay = delay;
fireChangeEvent();
}
@Override
public void step(double nextTime, double acceleration, AtmosphericConditions cond) {
if (MathUtil.equals(prevTime, nextTime)) {
return;
}
modID++;
double[] time = motor.getTimePoints();
double[] thrust = motor.getThrustPoints();
Coordinate[] cg = motor.getCGPoints();
@ -220,23 +231,6 @@ public class ThrustCurveMotorInstance extends MotorInstance {
prevTime = nextTime;
}
@Override
public MotorInstance clone() {
ThrustCurveMotorInstance clone = new ThrustCurveMotorInstance( this.motor);
clone.id = this.id;
clone.mount = this.mount;
clone.ignitionEvent = this.ignitionEvent;
clone.ignitionDelay = this.ignitionDelay;
clone.ejectionDelay = this.ejectionDelay;
clone.position = this.position;
clone.ignitionTime = Double.POSITIVE_INFINITY;
//clone.ignitionTime = this.ignitionTime;
return clone;
}
@Override
public void reset(){
timeIndex = 0;
prevTime = 0;
@ -246,25 +240,9 @@ public class ThrustCurveMotorInstance extends MotorInstance {
stepCG = instCG;
}
@Override
public String toDebug(){
String prefix = " ";
StringBuilder sb = new StringBuilder();
final RocketComponent mountComp = (RocketComponent)this.mount;
sb.append(String.format("%sMotor= %s(%s)(in %s)\n", prefix, this.motor.getDesignation(), this.id.toShortKey(), mountComp.getName()));
sb.append(String.format("%s Ignite: %s at %+f\n",prefix, this.ignitionEvent.name, this.ignitionDelay));
//sb.append(String.format("%s Eject at: %+f\n",prefix, this.ejectionDelay));
sb.append(String.format("%s L:%f W:%f @:%f mm\n",prefix, motor.getLength(), motor.getDiameter(), this.position.multiply(1000).x ));
sb.append(String.format("%s currentTime: %f\n", prefix, this.prevTime));
sb.append("\n");
return sb.toString();
}
@Override
public String toString(){
return this.motor.getDesignation() + this.id.toShortKey();
return this.motor.getDesignation();
}
}

View File

@ -1,5 +1,6 @@
package net.sf.openrocket.motor;
import net.sf.openrocket.simulation.MotorState;
import net.sf.openrocket.util.BugException;
import net.sf.openrocket.util.Coordinate;
@ -74,7 +75,7 @@ public class ThrustCurveMotorPlaceholder implements Motor {
}
@Override
public MotorInstance getNewInstance() {
public MotorState getNewInstance() {
throw new BugException("Called getInstance on PlaceholderMotor");
}

View File

@ -375,7 +375,7 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
@Override
public void setMotorInstance(final FlightConfigurationID fcid, final MotorInstance newMotorInstance){
if((null == newMotorInstance)||(newMotorInstance.equals( MotorInstance.EMPTY_INSTANCE ))){
if((null == newMotorInstance)){
this.motors.set( fcid, null);
}else{
if( null == newMotorInstance.getMount()){

View File

@ -357,44 +357,6 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
return this.fcid.toShortKey();
}
// DEBUG / DEVEL
public String toDebug() {
return toMotorDetail();
}
// DEBUG / DEVEL
public String toStageListDetail() {
StringBuilder buf = new StringBuilder();
buf.append(String.format("\nDumping %d stages for config: %s: (#: %d)\n", this.stages.size(), this.getName(), this.instanceNumber));
for (StageFlags flags : this.stages.values()) {
AxialStage curStage = flags.stage;
buf.append(String.format(" [%2d]: %-24s: %4s\n", curStage.getStageNumber(), curStage.getName(), (flags.active?" on": "off")));
}
buf.append("\n\n");
return buf.toString();
}
// DEBUG / DEVEL
public String toMotorDetail(){
StringBuilder buff = new StringBuilder();
buff.append(String.format("\nDumping %2d Motors for configuration %s: (#: %s)\n", this.motors.size(), this, this.instanceNumber));
final int intanceCount = motors.size();
int motorInstanceNumber=0;
for( MotorInstance curMotor : this.motors.values() ){
if( curMotor.isEmpty() ){
buff.append( String.format( " ..[%2d/%2d][%8s] <empty> \n", motorInstanceNumber+1, intanceCount, curMotor.getID().toShortKey()));
}else{
buff.append( String.format( " ..[%2d/%2d](%6s) %-10s (in: %s)(id: %8s)\n",
motorInstanceNumber+1, intanceCount,
(curMotor.isActive()? "active": "inactv"),curMotor.getMotor().getDesignation(),
((RocketComponent)curMotor.getMount()).getName(), curMotor.getID().toShortKey() ));
}
++motorInstanceNumber;
}
return buff.toString();
}
public String getMotorsOneline(){
StringBuilder buff = new StringBuilder("[");
boolean first = true;
@ -493,10 +455,6 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
return getAllMotorCount();
}
public int getActiveMotorCount(){
return getActiveMotors().size();
}
public int getAllMotorCount(){
return motors.size();
}
@ -523,7 +481,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
return activeList;
}
public void updateMotors() {
this.motors.clear();
@ -535,27 +493,8 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
continue;
}
// this merely accounts for instancing of *this* component:
// int instancCount = comp.getInstanceCount();
this.motors.put( sourceInstance.getID(), sourceInstance);
// this includes *all* the instancing between here and the rocket root.
Coordinate[] instanceLocations= compMount.getLocations();
sourceInstance.reset();
int motorInstanceNumber = 1;
//final int instanceCount = instanceLocations.length;
for ( Coordinate curMountLocation : instanceLocations ){
MotorInstance cloneInstance = sourceInstance.clone();
cloneInstance.setID( new MotorInstanceId( compMount.getName(), motorInstanceNumber) );
// motor location w/in mount: parent.refpoint -> motor.refpoint
Coordinate curMotorOffset = cloneInstance.getOffset();
cloneInstance.setPosition( curMountLocation.add(curMotorOffset) );
this.motors.put( cloneInstance.getID(), cloneInstance);
motorInstanceNumber ++;
}
}
}
}

View File

@ -0,0 +1,72 @@
package net.sf.openrocket.rocketcomponent;
import java.util.EventObject;
import java.util.List;
import net.sf.openrocket.util.ArrayList;
import net.sf.openrocket.util.StateChangeListener;
public class IgnitionConfiguration implements FlightConfigurableParameter<IgnitionConfiguration> {
protected double ignitionDelay = 0.0;
protected IgnitionEvent ignitionEvent = IgnitionEvent.NEVER;
protected double ignitionTime = 0.0;
private final List<StateChangeListener> listeners = new ArrayList<StateChangeListener>();
public double getIgnitionDelay() {
return ignitionDelay;
}
public void setIgnitionDelay(double ignitionDelay) {
this.ignitionDelay = ignitionDelay;
fireChangeEvent();
}
public IgnitionEvent getIgnitionEvent() {
return ignitionEvent;
}
public void setIgnitionEvent(IgnitionEvent ignitionEvent) {
this.ignitionEvent = ignitionEvent;
fireChangeEvent();
}
public double getIgnitionTime() {
return ignitionTime;
}
public void setIgnitionTime(double ignitionTime) {
this.ignitionTime = ignitionTime;
fireChangeEvent();
}
@Override
public IgnitionConfiguration clone() {
IgnitionConfiguration clone = new IgnitionConfiguration();
clone.ignitionDelay = this.ignitionDelay;
clone.ignitionEvent = this.ignitionEvent;
clone.ignitionTime = this.ignitionTime;
return clone;
}
@Override
public void addChangeListener(StateChangeListener listener) {
listeners.add(listener);
}
@Override
public void removeChangeListener(StateChangeListener listener) {
listeners.remove(listener);
}
private void fireChangeEvent() {
EventObject event = new EventObject(this);
Object[] list = listeners.toArray();
for (Object l : list) {
((StateChangeListener) l).stateChanged(event);
}
}
}

View File

@ -9,23 +9,23 @@ import net.sf.openrocket.startup.Application;
public enum IgnitionEvent {
// //// Automatic (launch or ejection charge)
// AUTOMATIC( "AUTOMATIC", "MotorMount.IgnitionEvent.AUTOMATIC"){
// @Override
// public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
// int count = source.getRocket().getStageCount();
// AxialStage stage = (AxialStage)source;
//
// if ( stage instanceof ParallelStage ){
// return LAUNCH.isActivationEvent(e, source);
// }else if (????){
// // no good option here. The non-sequential nature of
// // parallel stages prevents us from using the simple test as previousyl
// return LAUNCH.isActivationEvent(e, source);
// } else {
// return EJECTION_CHARGE.isActivationEvent(e, source);
// }
// }
// },
AUTOMATIC( "AUTOMATIC", "MotorMount.IgnitionEvent.AUTOMATIC"){
@Override
public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
int count = source.getRocket().getStageCount();
AxialStage stage = (AxialStage)source.getStage();
if ( stage instanceof ParallelStage ){
return LAUNCH.isActivationEvent(e, source);
}else if (stage.getStageNumber() == count -1){
// no good option here. The non-sequential nature of
// parallel stages prevents us from using the simple test as previousyl
return LAUNCH.isActivationEvent(e, source);
} else {
return EJECTION_CHARGE.isActivationEvent(e, source);
}
}
},
LAUNCH ( "LAUNCH", "MotorMount.IgnitionEvent.LAUNCH"){
@Override
public boolean isActivationEvent( FlightEvent fe, RocketComponent source){

View File

@ -283,7 +283,7 @@ public class InnerTube extends ThicknessRingComponent implements Clusterable, Ra
@Override
public void setMotorInstance(final FlightConfigurationID fcid, final MotorInstance newMotorInstance){
if((null == newMotorInstance)||(newMotorInstance== MotorInstance.EMPTY_INSTANCE )){
if((null == newMotorInstance)){
this.motors.set( fcid, null);
}else{
if( null == newMotorInstance.getMount()){

View File

@ -0,0 +1,72 @@
package net.sf.openrocket.rocketcomponent;
import java.util.EventObject;
import java.util.List;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.util.ArrayList;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.StateChangeListener;
public class MotorConfiguration implements FlightConfigurableParameter<MotorConfiguration> {
protected Coordinate position = Coordinate.ZERO;
protected double ejectionDelay = 0.0;
protected Motor motor = null;
private final List<StateChangeListener> listeners = new ArrayList<StateChangeListener>();
public Coordinate getPosition() {
return position;
}
public void setPosition(Coordinate position) {
this.position = position;
fireChangeEvent();
}
public double getEjectionDelay() {
return ejectionDelay;
}
public void setEjectionDelay(double ejectionDelay) {
this.ejectionDelay = ejectionDelay;
fireChangeEvent();
}
public Motor getMotor() {
return motor;
}
public void setMotor(Motor motor) {
this.motor = motor;
fireChangeEvent();
}
@Override
public MotorConfiguration clone() {
MotorConfiguration clone = new MotorConfiguration();
clone.position = this.position;
clone.ejectionDelay = this.ejectionDelay;
return clone;
}
@Override
public void addChangeListener(StateChangeListener listener) {
listeners.add(listener);
}
@Override
public void removeChangeListener(StateChangeListener listener) {
listeners.remove(listener);
}
private void fireChangeEvent() {
EventObject event = new EventObject(this);
Object[] list = listeners.toArray();
for (Object l : list) {
((StateChangeListener) l).stateChanged(event);
}
}
}

View File

@ -172,8 +172,8 @@ public abstract class AbstractSimulationStepper implements SimulationStepper {
thrust = 0;
final double currentTime = status.getSimulationTime() + timestep;
Collection<MotorInstance> activeMotorList = status.getConfiguration().getActiveMotors();
for (MotorInstance currentMotorInstance : activeMotorList ) {
Collection<MotorState> activeMotorList = status.getActiveMotors();
for (MotorState currentMotorInstance : activeMotorList ) {
// old: transplanted from MotorInstanceConfiguration
double instanceTime = currentTime - currentMotorInstance.getIgnitionTime();
if (instanceTime >= 0) {

View File

@ -195,7 +195,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
// Check for burnt out motors
for( MotorInstance motor : currentStatus.getConfiguration().getAllMotors()){
for( MotorState motor : currentStatus.getAllMotors()){
MotorInstanceId motorId = motor.getID();
if (!motor.isActive() && currentStatus.addBurntOutMotor(motorId)) {
addEvent(new FlightEvent(FlightEvent.Type.BURNOUT, currentStatus.getSimulationTime(),
@ -276,7 +276,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
if (event.getType() == FlightEvent.Type.IGNITION) {
MotorMount mount = (MotorMount) event.getSource();
MotorInstanceId motorId = (MotorInstanceId) event.getData();
MotorInstance instance = currentStatus.getMotor(motorId);
MotorState instance = currentStatus.getMotor(motorId);
if (!SimulationListenerHelper.fireMotorIgnition(currentStatus, motorId, mount, instance)) {
continue;
}
@ -289,7 +289,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
}
// Check for motor ignition events, add ignition events to queue
for (MotorInstance inst : currentStatus.getFlightConfiguration().getActiveMotors() ){
for (MotorState inst : currentStatus.getActiveMotors() ){
IgnitionEvent ignitionEvent = inst.getIgnitionEvent();
MotorMount mount = inst.getMount();
RocketComponent component = (RocketComponent) mount;
@ -342,7 +342,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
case IGNITION: {
// Ignite the motor
MotorInstanceId motorId = (MotorInstanceId) event.getData();
MotorInstance inst = currentStatus.getMotor( motorId);
MotorState inst = currentStatus.getMotor( motorId);
inst.setIgnitionTime(event.getTime());
//System.err.println("Igniting motor: "+inst.getMotor().getDesignation()+" @"+currentStatus.getSimulationTime());
@ -373,7 +373,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
}
// Add ejection charge event
MotorInstanceId motorId = (MotorInstanceId) event.getData();
MotorInstance motor = currentStatus.getMotor( motorId);
MotorState motor = currentStatus.getMotor( motorId);
double delay = motor.getEjectionDelay();
if (delay != Motor.PLUGGED) {
addEvent(new FlightEvent(FlightEvent.Type.EJECTION_CHARGE, currentStatus.getSimulationTime() + delay,

View File

@ -0,0 +1,31 @@
package net.sf.openrocket.simulation;
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
import net.sf.openrocket.motor.MotorInstanceId;
import net.sf.openrocket.rocketcomponent.IgnitionEvent;
import net.sf.openrocket.rocketcomponent.MotorMount;
public interface MotorState {
public void step(double nextTime, double acceleration, AtmosphericConditions cond);
public double getThrust();
public boolean isActive();
public double getIgnitionTime();
public void setIgnitionTime( double ignitionTime );
public void setMount(MotorMount mount);
public MotorMount getMount();
public void setId(MotorInstanceId id);
public MotorInstanceId getID();
public IgnitionEvent getIgnitionEvent();
public void setIgnitionEvent( IgnitionEvent event );
public double getIgnitionDelay();
public void setIgnitionDelay( double delay );
public double getEjectionDelay();
public void setEjectionDelay( double delay);
}

View File

@ -1,7 +1,10 @@
package net.sf.openrocket.simulation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -27,7 +30,7 @@ import net.sf.openrocket.util.WorldCoordinate;
*/
public class SimulationStatus implements Monitorable {
private SimulationConditions simulationConditions;
private FlightConfiguration configuration;
private FlightDataBranch flightData;
@ -48,6 +51,7 @@ public class SimulationStatus implements Monitorable {
// Set of burnt out motors
Set<MotorInstanceId> motorBurntOut = new HashSet<MotorInstanceId>();
List<MotorState> motorState = new ArrayList<MotorState>();
/** Nanosecond time when the simulation was started. */
private long simulationStartWallTime = Long.MIN_VALUE;
@ -144,6 +148,9 @@ public class SimulationStatus implements Monitorable {
this.launchRodCleared = false;
this.apogeeReached = false;
for( MotorInstance motorInstance : this.configuration.getActiveMotors() ) {
this.motorState.add( motorInstance.getSimulationState() );
}
this.warnings = new WarningSet();
}
@ -183,6 +190,10 @@ public class SimulationStatus implements Monitorable {
this.deployedRecoveryDevices.clear();
this.deployedRecoveryDevices.addAll(orig.deployedRecoveryDevices);
// FIXME - is this right?
this.motorState.clear();
this.motorState.addAll(orig.motorState);
this.eventQueue.clear();
this.eventQueue.addAll(orig.eventQueue);
@ -214,6 +225,20 @@ public class SimulationStatus implements Monitorable {
this.configuration = configuration;
}
public Collection<MotorState> getAllMotors() {
return motorState;
}
public Collection<MotorState> getActiveMotors() {
List<MotorState> activeList = new ArrayList<MotorState>();
for( MotorState inst : this.motorState ){
if( inst.isActive() ){
activeList.add( inst );
}
}
return activeList;
}
public FlightConfiguration getConfiguration() {
return configuration;
@ -235,8 +260,13 @@ public class SimulationStatus implements Monitorable {
return flightData;
}
public MotorInstance getMotor( final MotorInstanceId motorId ){
return this.getFlightConfiguration().getMotorInstance(motorId);
public MotorState getMotor( final MotorInstanceId motorId ){
for( MotorState state : motorState ) {
if ( motorId.equals(state.getID() )) {
return state;
}
}
return null;
}
public double getPreviousTimeStep() {

View File

@ -6,16 +6,19 @@ import java.util.Set;
import javax.script.Invocable;
import javax.script.ScriptException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sf.openrocket.aerodynamics.AerodynamicForces;
import net.sf.openrocket.aerodynamics.FlightConditions;
import net.sf.openrocket.masscalc.MassData;
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
import net.sf.openrocket.motor.MotorInstanceId;
import net.sf.openrocket.motor.MotorInstance;
import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
import net.sf.openrocket.simulation.AccelerationData;
import net.sf.openrocket.simulation.FlightEvent;
import net.sf.openrocket.simulation.MotorState;
import net.sf.openrocket.simulation.SimulationStatus;
import net.sf.openrocket.simulation.exception.SimulationException;
import net.sf.openrocket.simulation.exception.SimulationListenerException;
@ -25,9 +28,6 @@ import net.sf.openrocket.simulation.listeners.SimulationListener;
import net.sf.openrocket.util.BugException;
import net.sf.openrocket.util.Coordinate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ScriptingSimulationListener implements SimulationListener, SimulationComputationListener, SimulationEventListener, Cloneable {
private final static Logger logger = LoggerFactory.getLogger(ScriptingSimulationListener.class);
@ -105,7 +105,7 @@ public class ScriptingSimulationListener implements SimulationListener, Simulati
}
@Override
public boolean motorIgnition(SimulationStatus status, MotorInstanceId motorId, MotorMount mount, MotorInstance instance) throws SimulationException {
public boolean motorIgnition(SimulationStatus status, MotorInstanceId motorId, MotorMount mount, MotorState instance) throws SimulationException {
return invoke(Boolean.class, true, "motorIgnition", status, motorId, mount, instance);
}

View File

@ -5,11 +5,11 @@ import net.sf.openrocket.aerodynamics.FlightConditions;
import net.sf.openrocket.masscalc.MassData;
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
import net.sf.openrocket.motor.MotorInstanceId;
import net.sf.openrocket.motor.MotorInstance;
import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
import net.sf.openrocket.simulation.AccelerationData;
import net.sf.openrocket.simulation.FlightEvent;
import net.sf.openrocket.simulation.MotorState;
import net.sf.openrocket.simulation.SimulationStatus;
import net.sf.openrocket.simulation.exception.SimulationException;
import net.sf.openrocket.util.BugException;
@ -72,7 +72,7 @@ public class AbstractSimulationListener implements SimulationListener, Simulatio
}
@Override
public boolean motorIgnition(SimulationStatus status, MotorInstanceId motorId, MotorMount mount, MotorInstance instance) throws SimulationException {
public boolean motorIgnition(SimulationStatus status, MotorInstanceId motorId, MotorMount mount, MotorState instance) throws SimulationException {
return true;
}

View File

@ -1,10 +1,10 @@
package net.sf.openrocket.simulation.listeners;
import net.sf.openrocket.motor.MotorInstanceId;
import net.sf.openrocket.motor.MotorInstance;
import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
import net.sf.openrocket.simulation.FlightEvent;
import net.sf.openrocket.simulation.MotorState;
import net.sf.openrocket.simulation.SimulationStatus;
import net.sf.openrocket.simulation.exception.SimulationException;
@ -44,7 +44,7 @@ public interface SimulationEventListener {
* @return <code>true</code> to ignite the motor, <code>false</code> to abort ignition
*/
public boolean motorIgnition(SimulationStatus status, MotorInstanceId motorId, MotorMount mount,
MotorInstance instance) throws SimulationException;
MotorState instance) throws SimulationException;
/**

View File

@ -10,11 +10,11 @@ import net.sf.openrocket.aerodynamics.Warning;
import net.sf.openrocket.masscalc.MassData;
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
import net.sf.openrocket.motor.MotorInstanceId;
import net.sf.openrocket.motor.MotorInstance;
import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
import net.sf.openrocket.simulation.AccelerationData;
import net.sf.openrocket.simulation.FlightEvent;
import net.sf.openrocket.simulation.MotorState;
import net.sf.openrocket.simulation.SimulationStatus;
import net.sf.openrocket.simulation.exception.SimulationException;
import net.sf.openrocket.util.Coordinate;
@ -168,7 +168,7 @@ public class SimulationListenerHelper {
* @return <code>true</code> to handle the event normally, <code>false</code> to skip event.
*/
public static boolean fireMotorIgnition(SimulationStatus status, MotorInstanceId motorId, MotorMount mount,
MotorInstance instance) throws SimulationException {
MotorState instance) throws SimulationException {
boolean b;
int modID = status.getModID(); // Contains also motor instance

View File

@ -101,7 +101,7 @@ public class TestRockets {
new Coordinate[] {
new Coordinate(.311, 0, 0, 4.808),new Coordinate(.311, 0, 0, 3.389),new Coordinate(.311, 0, 0, 1.970)},
"digest M1350 test");
return mtr.getNewInstance();
return new MotorInstance(mtr);
}
// This function is used for unit, integration tests, DO NOT CHANGE (without updating tests).
@ -117,7 +117,7 @@ public class TestRockets {
new Coordinate[] {
new Coordinate(.062, 0, 0, 0.123),new Coordinate(.062, 0, 0, .0935),new Coordinate(.062, 0, 0, 0.064)},
"digest G77 test");
return mtr.getNewInstance();
return new MotorInstance(mtr);
}
//
@ -420,10 +420,11 @@ public class TestRockets {
new Coordinate(0.0035,0,0,30.0),
new Coordinate(0.0035,0,0,21.0)},
"digest_D12");
MotorInstance inst = motor.getNewInstance();
MotorInstance inst = new MotorInstance(motor);
inst.setEjectionDelay(5);
return inst;
}
public static Rocket makeSmallFlyable() {
double noseconeLength = 0.10, noseconeRadius = 0.01;
double bodytubeLength = 0.20, bodytubeRadius = 0.01, bodytubeThickness = 0.001;
@ -465,7 +466,7 @@ public class TestRockets {
FlightConfigurationID fcid = config.getFlightConfigurationID();
ThrustCurveMotor motor = getTestMotor();
MotorInstance instance = motor.getNewInstance();
MotorInstance instance = new MotorInstance(motor);
instance.setEjectionDelay(5);
bodytube.setMotorInstance(fcid, instance);
@ -979,7 +980,7 @@ public class TestRockets {
// create motor config and add a motor to it
ThrustCurveMotor motor = getTestMotor();
MotorInstance motorInst = motor.getNewInstance();
MotorInstance motorInst = new MotorInstance(motor);
motorInst.setEjectionDelay(5);
// add motor config to inner tube (motor mount)
@ -1014,7 +1015,7 @@ public class TestRockets {
// create motor config and add a motor to it
ThrustCurveMotor motor = getTestMotor();
MotorInstance motorConfig = motor.getNewInstance();
MotorInstance motorConfig = new MotorInstance(motor);
motorConfig.setEjectionDelay(5);
// add motor config to inner tube (motor mount)
@ -1171,7 +1172,7 @@ public class TestRockets {
bodyTube.addChild(innerTube);
// make inner tube with motor mount flag set
MotorInstance inst = getTestMotor().getNewInstance();
MotorInstance inst = new MotorInstance(getTestMotor());
innerTube.setMotorInstance(fcid, inst);
// set ignition parameters for motor mount

View File

@ -10,8 +10,8 @@ import net.sf.openrocket.file.motor.GeneralMotorLoader;
import net.sf.openrocket.file.motor.MotorLoader;
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.motor.MotorInstance;
import net.sf.openrocket.motor.ThrustCurveMotor;
import net.sf.openrocket.simulation.MotorState;
import net.sf.openrocket.util.BugException;
import net.sf.openrocket.util.MathUtil;
@ -61,8 +61,8 @@ public class MotorCorrelation {
* @return the scaled cross-correlation of the two thrust curves.
*/
public static double crossCorrelation(Motor motor1, Motor motor2) {
MotorInstance m1 = motor1.getNewInstance();
MotorInstance m2 = motor2.getNewInstance();
MotorState m1 = motor1.getNewInstance();
MotorState m2 = motor2.getNewInstance();
AtmosphericConditions cond = new AtmosphericConditions();

View File

@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals;
import org.junit.Test;
import net.sf.openrocket.simulation.MotorState;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.Inertia;
@ -41,7 +42,7 @@ public class ThrustCurveMotorTest {
@Test
public void testInstance() {
MotorInstance instance = motor.getNewInstance();
ThrustCurveMotorInstance instance = motor.getNewInstance();
verify(instance, 0, 0.05, 0.02);
instance.step(0.0, 0, null);
@ -63,7 +64,7 @@ public class ThrustCurveMotorTest {
verify(instance, 0, 0.03, 0.03);
}
private void verify(MotorInstance instance, double thrust, double mass, double cgx) {
private void verify(ThrustCurveMotorInstance instance, double thrust, double mass, double cgx) {
assertEquals("Testing thrust", thrust, instance.getThrust(), EPS);
assertEquals("Testing mass", mass, instance.getCG().weight, EPS);
assertEquals("Testing cg x", cgx, instance.getCG().x, EPS);

View File

@ -195,8 +195,8 @@ 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));
assertThat("Setting single stage active: ", config.isStageActive(0), equalTo(false));
assertThat("Setting single stage active: ", config.isStageActive(1), equalTo(true));
config.clearStage(0);
assertThat(" deactivate stage #0: ", config.isStageActive(0), equalTo(false));
@ -560,7 +560,7 @@ public class ConfigurationTest extends BaseTestCase {
InnerTube sustainerMount = (InnerTube) rocket.getChild(0).getChild(1).getChild(3);
sustainerMount.setMotorMount(true);
sustainerMount.setMotorInstance(fcid, sustainerMotor.getNewInstance());
sustainerMount.setMotorInstance(fcid, new MotorInstance(sustainerMotor));
}
{
@ -577,7 +577,7 @@ public class ConfigurationTest extends BaseTestCase {
"digest D21 test");
InnerTube boosterMount = (InnerTube) rocket.getChild(1).getChild(0).getChild(2);
boosterMount.setMotorMount(true);
boosterMount.setMotorInstance(fcid, boosterMotor.getNewInstance());
boosterMount.setMotorInstance(fcid, new MotorInstance(boosterMotor));
boosterMount.setClusterConfiguration( ClusterConfiguration.CONFIGURATIONS[1]); // double-mount
}
return rocket;

View File

@ -215,7 +215,7 @@ public class MotorConfigurationPanel extends FlightConfigurablePanel<MotorMount>
Motor mtr = motorChooserDialog.getSelectedMotor();
double d = motorChooserDialog.getSelectedDelay();
if (mtr != null) {
MotorInstance curInstance = mtr.getNewInstance();
MotorInstance curInstance = new MotorInstance(mtr);
curInstance.setEjectionDelay(d);
curInstance.setIgnitionEvent( IgnitionEvent.NEVER);
curMount.setMotorInstance( fcid, curInstance);
@ -262,9 +262,7 @@ public class MotorConfigurationPanel extends FlightConfigurablePanel<MotorMount>
}
MotorInstance curInstance = curMount.getMotorInstance(fcid);
MotorInstance defInstance = curInstance.getMount().getDefaultMotorInstance();
curInstance.setIgnitionDelay( defInstance.getIgnitionDelay());
curInstance.setIgnitionEvent( defInstance.getIgnitionEvent());
curInstance.useDefaultIgnition();
fireTableDataChanged();
}
@ -315,14 +313,19 @@ public class MotorConfigurationPanel extends FlightConfigurablePanel<MotorMount>
IgnitionEvent ignitionEvent = curInstance.getIgnitionEvent();
Double ignitionDelay = curInstance.getIgnitionDelay();
boolean isDefault = (defInstance.getIgnitionEvent() == curInstance.getIgnitionEvent());
boolean useDefault = !curInstance.hasIgnitionOverride();
if ( useDefault ) {
ignitionEvent = defInstance.getIgnitionEvent();
ignitionDelay = defInstance.getIgnitionDelay();
}
JLabel label = new JLabel();
String str = trans.get("MotorMount.IgnitionEvent.short." + ignitionEvent.name());
if (ignitionEvent != IgnitionEvent.NEVER && ignitionDelay > 0.001) {
str = str + " + " + UnitGroup.UNITS_SHORT_TIME.toStringUnit(ignitionDelay);
}
if (isDefault) {
if (useDefault) {
shaded(label);
String def = trans.get("MotorConfigurationTableModel.table.ignition.default");
str = def.replace("{0}", str);