[Bugfix] Refactored Configurations:

-Configuration refactor
  -stages are toggled individually
  -removed set-up-to-stage method
-MotorInstance refactor: multiple Lists -> one map<MotorId,MotorInstance>
    moved most of the fields to MotorInstance.java
This commit is contained in:
Daniel_M_Williams 2015-09-16 15:12:28 -04:00
parent 85dff39fb9
commit 6c11fb2751
32 changed files with 847 additions and 764 deletions

View File

@ -74,11 +74,16 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
new LinkedHashMap<RocketComponent, AerodynamicForces>(); new LinkedHashMap<RocketComponent, AerodynamicForces>();
// Add all components to the map // Add all components to the map
for (RocketComponent c : configuration) { for (RocketComponent component : configuration.getActiveComponents()) {
f = new AerodynamicForces();
f.setComponent(c);
map.put(c, f); // Skip non-aerodynamic components
if (!component.isAerodynamic())
continue;
f = new AerodynamicForces();
f.setComponent(component);
map.put(component, f);
} }
@ -172,7 +177,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
if (calcMap == null) if (calcMap == null)
buildCalcMap(configuration); buildCalcMap(configuration);
for (RocketComponent component : configuration) { for (RocketComponent component : configuration.getActiveComponents()) {
// Skip non-aerodynamic components // Skip non-aerodynamic components
if (!component.isAerodynamic()) if (!component.isAerodynamic())
@ -367,7 +372,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
double[] roughnessLimited = new double[Finish.values().length]; double[] roughnessLimited = new double[Finish.values().length];
Arrays.fill(roughnessLimited, Double.NaN); Arrays.fill(roughnessLimited, Double.NaN);
for (RocketComponent c : configuration) { for (RocketComponent c : configuration.getActiveComponents()) {
// Consider only SymmetricComponents and FinSets: // Consider only SymmetricComponents and FinSets:
if (!(c instanceof SymmetricComponent) && if (!(c instanceof SymmetricComponent) &&
@ -469,7 +474,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
base = calculateBaseCD(conditions.getMach()); base = calculateBaseCD(conditions.getMach());
total = 0; total = 0;
for (RocketComponent c : configuration) { for (RocketComponent c : configuration.getActiveComponents()) {
if (!c.isAerodynamic()) if (!c.isAerodynamic())
continue; continue;
@ -517,7 +522,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
base = calculateBaseCD(conditions.getMach()); base = calculateBaseCD(conditions.getMach());
total = 0; total = 0;
for (RocketComponent c : configuration) { for (RocketComponent c : configuration.getActiveComponents()) {
if (!(c instanceof SymmetricComponent)) if (!(c instanceof SymmetricComponent))
continue; continue;
@ -646,7 +651,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
cacheLength = 0; cacheLength = 0;
cacheDiameter = 0; cacheDiameter = 0;
for (RocketComponent c : configuration) { for (RocketComponent c : configuration.getActiveComponents()) {
if (c instanceof SymmetricComponent) { if (c instanceof SymmetricComponent) {
SymmetricComponent s = (SymmetricComponent) c; SymmetricComponent s = (SymmetricComponent) c;
area += s.getComponentPlanformArea(); area += s.getComponentPlanformArea();
@ -665,7 +670,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
// Fins // Fins
// TODO: LOW: This could be optimized a lot... // TODO: LOW: This could be optimized a lot...
for (RocketComponent c : configuration) { for (RocketComponent c : configuration.getActiveComponents()) {
if (c instanceof FinSet) { if (c instanceof FinSet) {
FinSet f = (FinSet) c; FinSet f = (FinSet) c;
mul += 0.6 * Math.min(f.getFinCount(), 4) * f.getFinArea() * mul += 0.6 * Math.min(f.getFinCount(), 4) * f.getFinArea() *

View File

@ -2,7 +2,6 @@ package net.sf.openrocket.document;
import java.util.EventListener; import java.util.EventListener;
import java.util.EventObject; import java.util.EventObject;
import java.util.Iterator;
import java.util.List; import java.util.List;
import net.sf.openrocket.aerodynamics.AerodynamicCalculator; import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
@ -10,14 +9,9 @@ import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
import net.sf.openrocket.aerodynamics.WarningSet; import net.sf.openrocket.aerodynamics.WarningSet;
import net.sf.openrocket.formatting.RocketDescriptor; import net.sf.openrocket.formatting.RocketDescriptor;
import net.sf.openrocket.masscalc.MassCalculator; import net.sf.openrocket.masscalc.MassCalculator;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.motor.MotorInstanceConfiguration; import net.sf.openrocket.motor.MotorInstanceConfiguration;
import net.sf.openrocket.rocketcomponent.Configuration; import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.rocketcomponent.IgnitionConfiguration;
import net.sf.openrocket.rocketcomponent.MotorConfiguration;
import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.Rocket;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.simulation.BasicEventSimulationEngine; import net.sf.openrocket.simulation.BasicEventSimulationEngine;
import net.sf.openrocket.simulation.DefaultSimulationOptionFactory; import net.sf.openrocket.simulation.DefaultSimulationOptionFactory;
import net.sf.openrocket.simulation.FlightData; import net.sf.openrocket.simulation.FlightData;
@ -266,28 +260,14 @@ public class Simulation implements ChangeSource, Cloneable {
} }
} }
Configuration c = new Configuration(this.getRocket());
MotorInstanceConfiguration motors = new MotorInstanceConfiguration(c);
c.setFlightConfigurationID(options.getMotorConfigurationID());
//Make sure this simulation has motors. //Make sure this simulation has motors.
Configuration c = new Configuration(this.getRocket()); if (0 == motors.getMotorCount()) {
MotorInstanceConfiguration motors = new MotorInstanceConfiguration();
c.setFlightConfigurationID(options.getMotorConfigurationID());
final String flightConfigId = c.getFlightConfigurationID();
Iterator<MotorMount> iterator = c.motorIterator();
boolean no_motors = true;
while (iterator.hasNext()) {
MotorMount mount = iterator.next();
RocketComponent component = (RocketComponent) mount;
MotorConfiguration motorConfig = mount.getMotorConfiguration().get(flightConfigId);
IgnitionConfiguration ignitionConfig = mount.getIgnitionConfiguration().get(flightConfigId);
Motor motor = motorConfig.getMotor();
if (motor != null)
no_motors = false;
}
if (no_motors)
status = Status.CANT_RUN; status = Status.CANT_RUN;
}
return status; return status;
} }

View File

@ -4,16 +4,13 @@ import static net.sf.openrocket.util.MathUtil.pow2;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.Map; import java.util.Map;
import net.sf.openrocket.motor.Motor; import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.motor.MotorId;
import net.sf.openrocket.motor.MotorInstance; import net.sf.openrocket.motor.MotorInstance;
import net.sf.openrocket.motor.MotorInstanceConfiguration; import net.sf.openrocket.motor.MotorInstanceConfiguration;
import net.sf.openrocket.rocketcomponent.AxialStage; import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.rocketcomponent.Configuration; import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.simulation.MassData; import net.sf.openrocket.simulation.MassData;
import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.Coordinate;
@ -80,35 +77,21 @@ public class MassCalculator implements Monitorable {
checkCache(configuration); checkCache(configuration);
calculateStageCache(configuration); calculateStageCache(configuration);
Coordinate totalCG = null; Coordinate dryCG = null;
// Stage contribution // Stage contribution
for (int stage : configuration.getActiveStages()) { for (AxialStage stage : configuration.getActiveStages()) {
totalCG = cgCache[stage].average(totalCG); int stageNumber = stage.getStageNumber();
dryCG = cgCache[stageNumber].average(dryCG);
} }
if (totalCG == null) if (dryCG == null)
totalCG = Coordinate.NUL; dryCG = Coordinate.NUL;
// Add motor CGs MotorInstanceConfiguration motorConfig = new MotorInstanceConfiguration(configuration);
String motorId = configuration.getFlightConfigurationID(); Coordinate motorCG = getMotorCG(configuration, motorConfig, MassCalcType.LAUNCH_MASS);
if (type != MassCalcType.NO_MOTORS && motorId != null) {
Iterator<MotorMount> iterator = configuration.motorIterator();
while (iterator.hasNext()) {
MotorMount mount = iterator.next();
RocketComponent comp = (RocketComponent) mount;
Motor motor = mount.getMotorConfiguration().get(motorId).getMotor();
if (motor == null)
continue;
Coordinate motorCG = type.getCG(motor).add(mount.getMotorPosition(motorId));
Coordinate[] cgs = comp.toAbsolute(motorCG);
for (Coordinate cg : cgs) {
totalCG = totalCG.average(cg);
}
}
}
Coordinate totalCG = dryCG.average(motorCG);
return totalCG; return totalCG;
} }
@ -123,23 +106,27 @@ public class MassCalculator implements Monitorable {
checkCache(configuration); checkCache(configuration);
calculateStageCache(configuration); calculateStageCache(configuration);
Coordinate totalCG = getCG(configuration, MassCalcType.NO_MOTORS); Coordinate dryCG = getCG(configuration, MassCalcType.NO_MOTORS);
Coordinate motorCG = getMotorCG(configuration, motors, MassCalcType.LAUNCH_MASS);
Coordinate totalCG = dryCG.average(motorCG);
return totalCG;
}
public Coordinate getMotorCG(Configuration config, MotorInstanceConfiguration motors, MassCalcType type) {
Coordinate motorCG = Coordinate.ZERO;
// Add motor CGs // Add motor CGs
if (motors != null) { if (motors != null) {
for (MotorId id : motors.getMotorIDs()) { for (MotorInstance inst : config.getActiveMotors(motors)) {
int stage = ((RocketComponent) motors.getMotorMount(id)).getStageNumber(); int stage = ((RocketComponent) inst.getMount()).getStageNumber();
if (configuration.isStageActive(stage)) { if (config.isStageActive(stage)) {
Coordinate position = inst.getPosition();
MotorInstance motor = motors.getMotorInstance(id); Coordinate curCG = type.getCG(inst.getMotor()).add(position);
Coordinate position = motors.getMotorPosition(id); motorCG = motorCG.average(curCG);
Coordinate cg = motor.getCG().add(position);
totalCG = totalCG.average(cg);
} }
} }
} }
return totalCG; return motorCG;
} }
/** /**
@ -158,21 +145,21 @@ public class MassCalculator implements Monitorable {
double totalInertia = 0; double totalInertia = 0;
// Stages // Stages
for (int stage : configuration.getActiveStages()) { for (AxialStage stage : configuration.getActiveStages()) {
Coordinate stageCG = cgCache[stage]; int stageNumber = stage.getStageNumber();
Coordinate stageCG = cgCache[stageNumber];
totalInertia += (longitudinalInertiaCache[stage] + totalInertia += (longitudinalInertiaCache[stageNumber] +
stageCG.weight * MathUtil.pow2(stageCG.x - totalCG.x)); stageCG.weight * MathUtil.pow2(stageCG.x - totalCG.x));
} }
// Motors // Motors
if (motors != null) { if (motors != null) {
for (MotorId id : motors.getMotorIDs()) { for (MotorInstance motor : configuration.getActiveMotors(motors)) {
int stage = ((RocketComponent) motors.getMotorMount(id)).getStageNumber(); int stage = ((RocketComponent) motor.getMount()).getStageNumber();
if (configuration.isStageActive(stage)) { if (configuration.isStageActive(stage)) {
MotorInstance motor = motors.getMotorInstance(id); Coordinate position = motor.getPosition();
Coordinate position = motors.getMotorPosition(id);
Coordinate cg = motor.getCG().add(position); Coordinate cg = motor.getCG().add(position);
double inertia = motor.getLongitudinalInertia(); double inertia = motor.getLongitudinalInertia();
@ -200,10 +187,11 @@ public class MassCalculator implements Monitorable {
double totalInertia = 0; double totalInertia = 0;
// Stages // Stages
for (int stage : configuration.getActiveStages()) { for (AxialStage stage : configuration.getActiveStages()) {
Coordinate stageCG = cgCache[stage]; int stageNumber = stage.getStageNumber();
Coordinate stageCG = cgCache[stageNumber];
totalInertia += (rotationalInertiaCache[stage] + totalInertia += (rotationalInertiaCache[stageNumber] +
stageCG.weight * (MathUtil.pow2(stageCG.y - totalCG.y) + stageCG.weight * (MathUtil.pow2(stageCG.y - totalCG.y) +
MathUtil.pow2(stageCG.z - totalCG.z))); MathUtil.pow2(stageCG.z - totalCG.z)));
} }
@ -211,11 +199,10 @@ public class MassCalculator implements Monitorable {
// Motors // Motors
if (motors != null) { if (motors != null) {
for (MotorId id : motors.getMotorIDs()) { for (MotorInstance motor : configuration.getActiveMotors(motors)) {
int stage = ((RocketComponent) motors.getMotorMount(id)).getStageNumber(); int stage = ((RocketComponent) motor.getMount()).getStageNumber();
if (configuration.isStageActive(stage)) { if (configuration.isStageActive(stage)) {
MotorInstance motor = motors.getMotorInstance(id); Coordinate position = motor.getPosition();
Coordinate position = motors.getMotorPosition(id);
Coordinate cg = motor.getCG().add(position); Coordinate cg = motor.getCG().add(position);
double inertia = motor.getRotationalInertia(); double inertia = motor.getRotationalInertia();
@ -241,9 +228,8 @@ public class MassCalculator implements Monitorable {
// add up the masses of all motors in the rocket // add up the masses of all motors in the rocket
if (motors != null) { if (motors != null) {
for (MotorId id : motors.getMotorIDs()) { for (MotorInstance motor : configuration.getActiveMotors(motors)) {
MotorInstance motor = motors.getMotorInstance(id); mass = mass + motor.getCG().weight - motor.getMotor().getEmptyCG().weight;
mass = mass + motor.getCG().weight - motor.getParentMotor().getEmptyCG().weight;
} }
} }
return mass; return mass;
@ -266,13 +252,13 @@ public class MassCalculator implements Monitorable {
Map<RocketComponent, Coordinate> map = new HashMap<RocketComponent, Coordinate>(); Map<RocketComponent, Coordinate> map = new HashMap<RocketComponent, Coordinate>();
for (RocketComponent c : configuration) { for (RocketComponent comp : configuration.getActiveComponents()) {
Coordinate[] cgs = c.toAbsolute(c.getCG()); Coordinate[] cgs = comp.toAbsolute(comp.getCG());
Coordinate totalCG = Coordinate.NUL; Coordinate totalCG = Coordinate.NUL;
for (Coordinate cg : cgs) { for (Coordinate cg : cgs) {
totalCG = totalCG.average(cg); totalCG = totalCG.average(cg);
} }
map.put(c, totalCG); map.put(comp, totalCG);
} }
map.put(configuration.getRocket(), getCG(configuration, type)); map.put(configuration.getRocket(), getCG(configuration, type));
@ -284,7 +270,8 @@ public class MassCalculator implements Monitorable {
private void calculateStageCache(Configuration config) { private void calculateStageCache(Configuration config) {
if (cgCache == null) { if (cgCache == null) {
ArrayList<AxialStage> stageList = config.getRocket().getStageList(); ArrayList<AxialStage> stageList = new ArrayList<AxialStage>();
stageList.addAll(config.getRocket().getStageList());
int stageCount = stageList.size(); int stageCount = stageList.size();
cgCache = new Coordinate[stageCount]; cgCache = new Coordinate[stageCount];

View File

@ -12,6 +12,14 @@ public final class MotorId {
private final String componentId; private final String componentId;
private final int number; private final int number;
private final String COMPONENT_ERROR_ID = "Error Motor Instance";
private final int ERROR_NUMBER = -1;
public final static MotorId ERROR_ID = new MotorId();
public MotorId() {
this.componentId = COMPONENT_ERROR_ID;
this.number = ERROR_NUMBER;
}
/** /**
* Sole constructor. * Sole constructor.
@ -20,7 +28,6 @@ public final class MotorId {
* @param number a positive motor doun5 number * @param number a positive motor doun5 number
*/ */
public MotorId(String componentId, int number) { public MotorId(String componentId, int number) {
super();
if (componentId == null) { if (componentId == null) {
throw new IllegalArgumentException("Component ID was null"); throw new IllegalArgumentException("Component ID was null");

View File

@ -1,10 +1,123 @@
package net.sf.openrocket.motor; package net.sf.openrocket.motor;
import net.sf.openrocket.models.atmosphere.AtmosphericConditions; import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
import net.sf.openrocket.rocketcomponent.IgnitionConfiguration;
import net.sf.openrocket.rocketcomponent.IgnitionConfiguration.IgnitionEvent;
import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.Monitorable; import net.sf.openrocket.util.Monitorable;
public interface MotorInstance extends Cloneable, Monitorable { public abstract class MotorInstance implements Cloneable, Monitorable {
protected MotorId id = null;
protected Motor parentMotor = null;
protected MotorMount mount = null;
protected IgnitionConfiguration.IgnitionEvent ignitionEvent = null;
protected double ejectionDelay = 0.0;
protected double ignitionDelay = 0.0;
protected Coordinate position = null;
protected double ignitionTime = 0.0;
protected int modID = 0;
public MotorInstance() {
modID++;
}
/**
* 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 MotorInstance(MotorId _id, Motor _motor, MotorMount _mount, double _ejectionDelay,
IgnitionEvent _ignitionEvent, double _ignitionDelay, Coordinate _position) {
this.id = _id;
this.parentMotor = _motor;
this.mount = _mount;
this.ejectionDelay = _ejectionDelay;
this.ignitionEvent = _ignitionEvent;
this.ignitionDelay = _ignitionDelay;
this.position = _position;
this.ignitionTime = Double.POSITIVE_INFINITY;
modID++;
}
public MotorId getID() {
return this.id;
}
public void setID(final MotorId _id) {
this.id = _id;
}
public double getEjectionDelay() {
return this.ejectionDelay;
}
public void setEjectionDelay(final double newDelay) {
this.ejectionDelay = newDelay;
}
@Override
public int getModID() {
return this.modID;
}
public Motor getMotor() {
return this.parentMotor;
}
public MotorMount getMount() {
return this.mount;
}
public void setMount(final MotorMount _mount) {
this.mount = _mount;
}
public Coordinate getPosition() {
return this.position;
}
public void setPosition(Coordinate _position) {
this.position = _position;
modID++;
}
public double getIgnitionTime() {
return this.ignitionTime;
}
public void setIgnitionTime(double _time) {
this.ignitionTime = _time;
modID++;
}
public double getIgnitionDelay() {
return ignitionDelay;
}
public void setIgnitionDelay(final double _delay) {
this.ignitionDelay = _delay;
}
public IgnitionEvent getIgnitionEvent() {
return ignitionEvent;
}
public void setIgnitionEvent(final IgnitionEvent _event) {
this.ignitionEvent = _event;
}
/** /**
* Step the motor instance forward in time. * Step the motor instance forward in time.
@ -13,51 +126,49 @@ public interface MotorInstance extends Cloneable, Monitorable {
* @param acceleration the average acceleration during the step. * @param acceleration the average acceleration during the step.
* @param cond the average atmospheric conditions during the step. * @param cond the average atmospheric conditions during the step.
*/ */
public void step(double time, double acceleration, AtmosphericConditions cond); public abstract void step(double time, double acceleration, AtmosphericConditions cond);
/** /**
* Return the time to which this motor has been stepped. * Return the time to which this motor has been stepped.
* @return the current step time. * @return the current step time.
*/ */
public double getTime(); public abstract double getTime();
/** /**
* Return the average thrust during the last step. * Return the average thrust during the last step.
*/ */
public double getThrust(); public abstract double getThrust();
/** /**
* Return the average CG location during the last step. * Return the average CG location during the last step.
*/ */
public Coordinate getCG(); public abstract Coordinate getCG();
/** /**
* Return the average longitudinal moment of inertia during the last step. * Return the average longitudinal moment of inertia during the last step.
* This is the actual inertia, not the unit inertia! * This is the actual inertia, not the unit inertia!
*/ */
public double getLongitudinalInertia(); public abstract double getLongitudinalInertia();
/** /**
* Return the average rotational moment of inertia during the last step. * Return the average rotational moment of inertia during the last step.
* This is the actual inertia, not the unit inertia! * This is the actual inertia, not the unit inertia!
*/ */
public double getRotationalInertia(); public abstract double getRotationalInertia();
/** /**
* Return whether this motor still produces thrust. If this method returns false * 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. * the motor has burnt out, and will not produce any significant thrust anymore.
*/ */
public boolean isActive(); public abstract boolean isActive();
/** /**
* Create a new instance of this motor instance. The state of the motor is * Create a new instance of this motor instance. The state of the motor is
* identical to this instance and can be used independently from this one. * identical to this instance and can be used independently from this one.
*/ */
public MotorInstance clone(); @Override
public abstract MotorInstance clone();
public Motor getParentMotor();
} }

View File

@ -1,13 +1,16 @@
package net.sf.openrocket.motor; package net.sf.openrocket.motor;
import java.util.ArrayList; import java.util.Collection;
import java.util.Collections; import java.util.HashMap;
import java.util.List; import java.util.Iterator;
import java.util.Set;
import net.sf.openrocket.models.atmosphere.AtmosphericConditions; import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.rocketcomponent.IgnitionConfiguration; import net.sf.openrocket.rocketcomponent.IgnitionConfiguration;
import net.sf.openrocket.rocketcomponent.IgnitionConfiguration.IgnitionEvent; import net.sf.openrocket.rocketcomponent.MotorConfiguration;
import net.sf.openrocket.rocketcomponent.MotorMount; import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.Monitorable; import net.sf.openrocket.util.Monitorable;
@ -17,21 +20,55 @@ import net.sf.openrocket.util.Monitorable;
* *
* @author Sampo Niskanen <sampo.niskanen@iki.fi> * @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/ */
public final class MotorInstanceConfiguration implements Monitorable, Cloneable { public class MotorInstanceConfiguration implements Cloneable, Iterable<MotorInstance>, Monitorable {
protected final HashMap<MotorId, MotorInstance> motors = new HashMap<MotorId, MotorInstance>();
private final List<MotorId> ids = new ArrayList<MotorId>();
private final List<MotorId> unmodifiableIds = Collections.unmodifiableList(ids);
private final List<MotorInstance> motors = new ArrayList<MotorInstance>();
private final List<Double> ejectionDelays = new ArrayList<Double>();
private final List<MotorMount> mounts = new ArrayList<MotorMount>();
private final List<IgnitionConfiguration.IgnitionEvent> ignitionEvents = new ArrayList<IgnitionConfiguration.IgnitionEvent>();
private final List<Double> ignitionDelays = new ArrayList<Double>();
private final List<Coordinate> positions = new ArrayList<Coordinate>();
private final List<Double> ignitionTimes = new ArrayList<Double>();
private int modID = 0; private int modID = 0;
private MotorInstanceConfiguration() {
}
/**
* Create a new motor instance configuration for the rocket configuration.
*
* @param configuration the rocket configuration.
*/
public MotorInstanceConfiguration(Configuration configuration) {
// motors == this
final String flightConfigId = configuration.getFlightConfigurationID();
Iterator<RocketComponent> iterator = configuration.getRocket().iterator(false);
while (iterator.hasNext()) {
RocketComponent component = iterator.next();
if (component instanceof MotorMount) {
MotorMount mount = (MotorMount) component;
MotorConfiguration motorConfig = mount.getMotorConfiguration().get(flightConfigId);
IgnitionConfiguration ignitionConfig = mount.getIgnitionConfiguration().get(flightConfigId);
Motor motor = motorConfig.getMotor();
if (motor != null) {
int count = mount.getMotorConfiguration().size();
Coordinate[] positions = component.toAbsolute(mount.getMotorPosition(flightConfigId));
for (int i = 0; i < positions.length; i++) {
Coordinate position = positions[i];
MotorId id = new MotorId(component.getID(), i + 1);
MotorInstance inst = motor.getInstance();
inst.setID(id);
inst.setEjectionDelay(motorConfig.getEjectionDelay());
inst.setMount(mount);
inst.setIgnitionDelay(ignitionConfig.getIgnitionDelay());
inst.setIgnitionEvent(ignitionConfig.getIgnitionEvent());
inst.setPosition(position);
motors.put(id, inst);
}
}
}
}
}
/** /**
* Add a motor instance to this configuration. The motor is placed at * Add a motor instance to this configuration. The motor is placed at
@ -45,89 +82,70 @@ public final class MotorInstanceConfiguration implements Monitorable, Cloneable
* @param position the position of the motor in absolute coordinates. * @param position the position of the motor in absolute coordinates.
* @throws IllegalArgumentException if a motor with the specified ID already exists. * @throws IllegalArgumentException if a motor with the specified ID already exists.
*/ */
public void addMotor(MotorId id, MotorInstance motor, double ejectionDelay, MotorMount mount, // public void addMotor(MotorId _id, Motor _motor, double _ejectionDelay, MotorMount _mount,
IgnitionEvent ignitionEvent, double ignitionDelay, Coordinate position) { // IgnitionEvent _ignitionEvent, double _ignitionDelay, Coordinate _position) {
if (this.ids.contains(id)) { //
// 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) {
MotorId id = motor.getID();
if (this.motors.containsKey(id)) {
throw new IllegalArgumentException("MotorInstanceConfiguration already " + throw new IllegalArgumentException("MotorInstanceConfiguration already " +
"contains a motor with id " + id); "contains a motor with id " + id);
} }
this.ids.add(id); this.motors.put(id, motor);
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);
modID++; modID++;
} }
/** public Collection<MotorInstance> getAllMotors() {
* Return a list of all motor IDs in this configuration (not only ones in active stages). return motors.values();
*/ }
public List<MotorId> getMotorIDs() {
return unmodifiableIds; public int getMotorCount() {
return motors.size();
}
public Set<MotorId> getMotorIDs() {
return this.motors.keySet();
} }
public MotorInstance getMotorInstance(MotorId id) { public MotorInstance getMotorInstance(MotorId id) {
return motors.get(indexOf(id)); return motors.get(id);
} }
public double getEjectionDelay(MotorId id) { public boolean hasMotors() {
return ejectionDelays.get(indexOf(id)); return (0 < motors.size());
} }
public MotorMount getMotorMount(MotorId id) {
return mounts.get(indexOf(id));
}
public Coordinate getMotorPosition(MotorId id) {
return positions.get(indexOf(id));
}
public void setMotorPosition(MotorId id, Coordinate position) {
positions.set(indexOf(id), position);
modID++;
}
public double getMotorIgnitionTime(MotorId id) {
return ignitionTimes.get(indexOf(id));
}
public void setMotorIgnitionTime(MotorId id, double time) {
this.ignitionTimes.set(indexOf(id), time);
modID++;
}
public double getMotorIgnitionDelay(MotorId id) {
return ignitionDelays.get(indexOf(id));
}
public IgnitionEvent getMotorIgnitionEvent(MotorId id) {
return ignitionEvents.get(indexOf(id));
}
private int indexOf(MotorId id) {
int index = ids.indexOf(id);
if (index < 0) {
throw new IllegalArgumentException("MotorInstanceConfiguration does not " +
"contain a motor with id " + id);
}
return index;
}
/** /**
* Step all of the motor instances to the specified time minus their ignition time. * Step all of the motor instances to the specified time minus their ignition time.
* @param time the "global" time * @param time the "global" time
*/ */
public void step(double time, double acceleration, AtmosphericConditions cond) { public void step(double time, double acceleration, AtmosphericConditions cond) {
for (int i = 0; i < motors.size(); i++) { for (MotorInstance inst : motors.values()) {
double t = time - ignitionTimes.get(i); double t = time - inst.getIgnitionTime();
if (t >= 0) { if (t >= 0) {
motors.get(i).step(t, acceleration, cond); inst.step(t, acceleration, cond);
} }
} }
modID++; modID++;
@ -136,7 +154,7 @@ public final class MotorInstanceConfiguration implements Monitorable, Cloneable
@Override @Override
public int getModID() { public int getModID() {
int id = modID; int id = modID;
for (MotorInstance motor : motors) { for (MotorInstance motor : motors.values()) {
id += motor.getModID(); id += motor.getModID();
} }
return id; return id;
@ -149,18 +167,17 @@ public final class MotorInstanceConfiguration implements Monitorable, Cloneable
@Override @Override
public MotorInstanceConfiguration clone() { public MotorInstanceConfiguration clone() {
MotorInstanceConfiguration clone = new MotorInstanceConfiguration(); MotorInstanceConfiguration clone = new MotorInstanceConfiguration();
clone.ids.addAll(this.ids); for (MotorInstance motor : this.motors.values()) {
clone.mounts.addAll(this.mounts); clone.motors.put(motor.id, motor.clone());
clone.positions.addAll(this.positions);
clone.ejectionDelays.addAll(this.ejectionDelays);
clone.ignitionTimes.addAll(this.ignitionTimes);
clone.ignitionEvents.addAll(this.ignitionEvents);
clone.ignitionDelays.addAll(this.ignitionDelays);
for (MotorInstance motor : this.motors) {
clone.motors.add(motor.clone());
} }
clone.modID = this.modID; clone.modID = this.modID;
return clone; return clone;
} }
@Override
public Iterator<MotorInstance> iterator() {
return this.motors.values().iterator();
}
} }

View File

@ -415,9 +415,9 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
//////// Motor instance implementation //////// //////// Motor instance implementation ////////
private class ThrustCurveMotorInstance implements MotorInstance { private class ThrustCurveMotorInstance extends MotorInstance {
private int position; private int timeIndex;
// Previous time step value // Previous time step value
private double prevTime; private double prevTime;
@ -434,13 +434,12 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
private final double unitRotationalInertia; private final double unitRotationalInertia;
private final double unitLongitudinalInertia; private final double unitLongitudinalInertia;
private final Motor parentMotor;
private int modID = 0; private int modID = 0;
public ThrustCurveMotorInstance() { public ThrustCurveMotorInstance() {
log.debug("ThrustCurveMotor: Creating motor instance of " + ThrustCurveMotor.this); log.debug("ThrustCurveMotor: Creating motor instance of " + ThrustCurveMotor.this);
position = 0; timeIndex = 0;
prevTime = 0; prevTime = 0;
instThrust = 0; instThrust = 0;
stepThrust = 0; stepThrust = 0;
@ -451,11 +450,6 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
parentMotor = ThrustCurveMotor.this; parentMotor = ThrustCurveMotor.this;
} }
@Override
public Motor getParentMotor() {
return parentMotor;
}
@Override @Override
public double getTime() { public double getTime() {
return prevTime; return prevTime;
@ -500,7 +494,7 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
modID++; modID++;
if (position >= time.length - 1) { if (timeIndex >= time.length - 1) {
// Thrust has ended // Thrust has ended
prevTime = nextTime; prevTime = nextTime;
stepThrust = 0; stepThrust = 0;
@ -511,33 +505,33 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
// Compute average & instantaneous thrust // Compute average & instantaneous thrust
if (nextTime < time[position + 1]) { if (nextTime < time[timeIndex + 1]) {
// Time step between time points // Time step between time points
double nextF = MathUtil.map(nextTime, time[position], time[position + 1], double nextF = MathUtil.map(nextTime, time[timeIndex], time[timeIndex + 1],
thrust[position], thrust[position + 1]); thrust[timeIndex], thrust[timeIndex + 1]);
stepThrust = (instThrust + nextF) / 2; stepThrust = (instThrust + nextF) / 2;
instThrust = nextF; instThrust = nextF;
} else { } else {
// Portion of previous step // Portion of previous step
stepThrust = (instThrust + thrust[position + 1]) / 2 * (time[position + 1] - prevTime); stepThrust = (instThrust + thrust[timeIndex + 1]) / 2 * (time[timeIndex + 1] - prevTime);
// Whole steps // Whole steps
position++; timeIndex++;
while ((position < time.length - 1) && (nextTime >= time[position + 1])) { while ((timeIndex < time.length - 1) && (nextTime >= time[timeIndex + 1])) {
stepThrust += (thrust[position] + thrust[position + 1]) / 2 * stepThrust += (thrust[timeIndex] + thrust[timeIndex + 1]) / 2 *
(time[position + 1] - time[position]); (time[timeIndex + 1] - time[timeIndex]);
position++; timeIndex++;
} }
// End step // End step
if (position < time.length - 1) { if (timeIndex < time.length - 1) {
instThrust = MathUtil.map(nextTime, time[position], time[position + 1], instThrust = MathUtil.map(nextTime, time[timeIndex], time[timeIndex + 1],
thrust[position], thrust[position + 1]); thrust[timeIndex], thrust[timeIndex + 1]);
stepThrust += (thrust[position] + instThrust) / 2 * stepThrust += (thrust[timeIndex] + instThrust) / 2 *
(nextTime - time[position]); (nextTime - time[timeIndex]);
} else { } else {
// Thrust ended during this step // Thrust ended during this step
instThrust = 0; instThrust = 0;
@ -549,9 +543,9 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
// Compute average and instantaneous CG (simple average between points) // Compute average and instantaneous CG (simple average between points)
Coordinate nextCG; Coordinate nextCG;
if (position < time.length - 1) { if (timeIndex < time.length - 1) {
nextCG = MathUtil.map(nextTime, time[position], time[position + 1], nextCG = MathUtil.map(nextTime, time[timeIndex], time[timeIndex + 1],
cg[position], cg[position + 1]); cg[timeIndex], cg[timeIndex + 1]);
} else { } else {
nextCG = cg[cg.length - 1]; nextCG = cg[cg.length - 1];
} }
@ -564,11 +558,12 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
@Override @Override
public MotorInstance clone() { public MotorInstance clone() {
try { throw new BugException("CloneNotSupportedException");
return (MotorInstance) super.clone(); //try {
} catch (CloneNotSupportedException e) { // return (MotorInstance) super.clone();
throw new BugException("CloneNotSupportedException", e); //} catch (CloneNotSupportedException e) {
} // throw new BugException("CloneNotSupportedException", e);
//}
} }
@Override @Override

View File

@ -91,7 +91,7 @@ public class StabilityDomain implements SimulationDomain {
absolute = cpx - cgx; absolute = cpx - cgx;
double diameter = 0; double diameter = 0;
for (RocketComponent c : configuration) { for (RocketComponent c : configuration.getActiveComponents()) {
if (c instanceof SymmetricComponent) { if (c instanceof SymmetricComponent) {
double d1 = ((SymmetricComponent) c).getForeRadius() * 2; double d1 = ((SymmetricComponent) c).getForeRadius() * 2;
double d2 = ((SymmetricComponent) c).getAftRadius() * 2; double d2 = ((SymmetricComponent) c).getAftRadius() * 2;

View File

@ -84,7 +84,7 @@ public class StabilityParameter implements OptimizableParameter {
if (!absolute) { if (!absolute) {
double diameter = 0; double diameter = 0;
for (RocketComponent c : configuration) { for (RocketComponent c : configuration.getActiveComponents()) {
if (c instanceof SymmetricComponent) { if (c instanceof SymmetricComponent) {
double d1 = ((SymmetricComponent) c).getForeRadius() * 2; double d1 = ((SymmetricComponent) c).getForeRadius() * 2;
double d2 = ((SymmetricComponent) c).getAftRadius() * 2; double d2 = ((SymmetricComponent) c).getAftRadius() * 2;

View File

@ -15,13 +15,11 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
private FlightConfigurationImpl<StageSeparationConfiguration> separationConfigurations; private FlightConfigurationImpl<StageSeparationConfiguration> separationConfigurations;
protected int stageNumber; protected int stageNumber;
private static int stageCount;
public AxialStage() { public AxialStage() {
this.separationConfigurations = new FlightConfigurationImpl<StageSeparationConfiguration>(this, ComponentChangeEvent.EVENT_CHANGE, new StageSeparationConfiguration()); this.separationConfigurations = new FlightConfigurationImpl<StageSeparationConfiguration>(this, ComponentChangeEvent.EVENT_CHANGE, new StageSeparationConfiguration());
this.relativePosition = Position.AFTER; this.relativePosition = Position.AFTER;
stageNumber = AxialStage.stageCount; this.stageNumber = 0;
AxialStage.stageCount++;
} }
@Override @Override
@ -35,10 +33,6 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
return trans.get("Stage.Stage"); return trans.get("Stage.Stage");
} }
public static int getStageCount() {
return AxialStage.stageCount;
}
public FlightConfiguration<StageSeparationConfiguration> getStageSeparationConfiguration() { public FlightConfiguration<StageSeparationConfiguration> getStageSeparationConfiguration() {
return separationConfigurations; return separationConfigurations;
} }
@ -107,23 +101,21 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
if (null == this.parent) { if (null == this.parent) {
return -1; return -1;
} else if (this.isCenterline()) { } else if (this.isCenterline()) {
if (0 < this.stageNumber) {
return --this.stageNumber; return --this.stageNumber;
} else {
return this.parent.getStageNumber();
} }
} }
return -1;
}
public static void resetStageCount() {
AxialStage.stageCount = 0;
}
@Override @Override
public int getStageNumber() { public int getStageNumber() {
return this.stageNumber; return this.stageNumber;
} }
public void setStageNumber(final int newStageNumber) {
this.stageNumber = newStageNumber;
}
@Override @Override
public Coordinate[] shiftCoordinates(Coordinate[] c) { public Coordinate[] shiftCoordinates(Coordinate[] c) {
checkState(); checkState();

View File

@ -130,32 +130,6 @@ public class BoosterSet extends AxialStage implements FlightConfigurableComponen
return this.getAxialOffset(); return this.getAxialOffset();
} }
/**
* Stages may be positioned relative to other stages. In that case, this will set the stage number
* against which this stage is positioned.
*
* @return the stage number which this stage is positioned relative to
*/
@Override
public int getRelativeToStage() {
if (null == this.parent) {
return -1;
} else if (this.parent instanceof BoosterSet) {
return this.parent.parent.getChildPosition(this.parent);
} else if (this.isCenterline()) {
if (0 < this.stageNumber) {
return --this.stageNumber;
}
}
return -1;
}
@Override
public int getStageNumber() {
return this.stageNumber;
}
@Override @Override
public Coordinate[] shiftCoordinates(Coordinate[] c) { public Coordinate[] shiftCoordinates(Coordinate[] c) {
checkState(); checkState();

View File

@ -1,13 +1,13 @@
package net.sf.openrocket.rocketcomponent; package net.sf.openrocket.rocketcomponent;
import java.util.BitSet;
import java.util.Collection; import java.util.Collection;
import java.util.EventListener; import java.util.EventListener;
import java.util.EventObject; import java.util.EventObject;
import java.util.Iterator; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException;
import net.sf.openrocket.motor.MotorInstance;
import net.sf.openrocket.motor.MotorInstanceConfiguration;
import net.sf.openrocket.util.ArrayList; import net.sf.openrocket.util.ArrayList;
import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.BugException;
import net.sf.openrocket.util.ChangeSource; import net.sf.openrocket.util.ChangeSource;
@ -16,26 +16,38 @@ import net.sf.openrocket.util.MathUtil;
import net.sf.openrocket.util.Monitorable; import net.sf.openrocket.util.Monitorable;
import net.sf.openrocket.util.StateChangeListener; import net.sf.openrocket.util.StateChangeListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* A class defining a rocket configuration, including motors and which stages are active. * A class defining a rocket configuration, including which stages are active.
* *
* TODO: HIGH: Remove motor ignition times from this class.
* *
* @author Sampo Niskanen <sampo.niskanen@iki.fi> * @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/ */
public class Configuration implements Cloneable, ChangeSource, ComponentChangeListener, public class Configuration implements Cloneable, ChangeSource, ComponentChangeListener, Monitorable {
Iterable<RocketComponent>, Monitorable { private static final Logger log = LoggerFactory.getLogger(Configuration.class);
private Rocket rocket;
private BitSet stagesActive = new BitSet();
private String flightConfigurationId = null;
protected Rocket rocket;
protected String flightConfigurationId = null;
private List<EventListener> listenerList = new ArrayList<EventListener>(); private List<EventListener> listenerList = new ArrayList<EventListener>();
protected class StageFlags {
public boolean active = true;
public int prev = -1;
public AxialStage stage = null;
public StageFlags(AxialStage _stage, int _prev, boolean _active) {
this.stage = _stage;
this.prev = _prev;
this.active = _active;
}
}
/* Cached data */ /* Cached data */
protected HashMap<Integer, StageFlags> stageMap = new HashMap<Integer, StageFlags>();
private int boundsModID = -1; private int boundsModID = -1;
private ArrayList<Coordinate> cachedBounds = new ArrayList<Coordinate>(); private ArrayList<Coordinate> cachedBounds = new ArrayList<Coordinate>();
private double cachedLength = -1; private double cachedLength = -1;
@ -43,7 +55,6 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
private int refLengthModID = -1; private int refLengthModID = -1;
private double cachedRefLength = -1; private double cachedRefLength = -1;
private int modID = 0; private int modID = 0;
@ -55,98 +66,156 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
*/ */
public Configuration(Rocket rocket) { public Configuration(Rocket rocket) {
this.rocket = rocket; this.rocket = rocket;
setAllStages(); updateStageMap();
rocket.addComponentChangeListener(this); rocket.addComponentChangeListener(this);
} }
public Rocket getRocket() { public Rocket getRocket() {
return rocket; return rocket;
} }
public void clearAllStages() {
this.setAllStages(false);
}
public void setAllStages() { public void setAllStages() {
stagesActive.clear(); this.setAllStages(true);
stagesActive.set(0, AxialStage.getStageCount());
fireChangeEvent();
} }
public void setAllStages(final boolean _value) {
/** for (StageFlags cur : stageMap.values()) {
* Set all stages up to and including the given stage number. For example, cur.active = _value;
* <code>setToStage(0)</code> will set only the first stage active.
*
* @param stage the stage number.
*/
public void setToStage(int stage) {
stagesActive.clear();
stagesActive.set(0, stage + 1, true);
// stages.set(stage+1, rocket.getStageCount(), false);
fireChangeEvent();
} }
public void setOnlyStage(int stage) {
stagesActive.clear();
stagesActive.set(stage, stage + 1, true);
fireChangeEvent(); fireChangeEvent();
} }
/** /**
* Check whether the up-most stage of the rocket is in this configuration. * This method flags a stage inactive. Other stages are unaffected.
* *
* @return <code>true</code> if the first stage is active in this configuration. * @param stageNumber stage number to inactivate
*/ */
public boolean isHead() { public void clearOnlyStage(final int stageNumber) {
return isStageActive(0); setStage(stageNumber, false);
}
/**
* This method flags a stage active. Other stages are unaffected.
*
* @param stageNumber stage number to activate
*/
public void setOnlyStage(final int stageNumber) {
setStage(stageNumber, true);
}
/**
* This method flags the specified stage as requested. Other stages are unaffected.
*
* @param stageNumber stage number to flag
* @param _active inactive (<code>false</code>) or active (<code>true</code>)
*/
public void setStage(final int stageNumber, final boolean _active) {
if ((0 <= stageNumber) && (stageMap.containsKey(stageNumber))) {
log.error("debug: setting stage " + stageNumber + " to " + _active);
stageMap.get(stageNumber).active = _active;
fireChangeEvent();
return;
}
log.error("error: attempt to retrieve via a bad stage number: " + stageNumber);
} }
public void toggleStage(final int stageNumber) {
if ((0 <= stageNumber) && (stageMap.containsKey(stageNumber))) {
StageFlags flags = stageMap.get(stageNumber);
log.error("debug: toggling stage " + stageNumber + " to " + !flags.active);
flags.active = !flags.active;
fireChangeEvent();
return;
}
log.error("error: attempt to retrieve via a bad stage number: " + stageNumber);
}
/**
* Check whether the stage is active.
*/
public boolean isStageActive(final AxialStage stage) {
return this.isStageActive(stage.getStageNumber());
}
/** /**
* Check whether the stage specified by the index is active. * Check whether the stage specified by the index is active.
*/ */
public boolean isStageActive(int stage) { public boolean isStageActive(int stageNumber) {
if (stage >= AxialStage.getStageCount()) if (stageNumber >= this.rocket.getStageCount()) {
return false; return false;
return stagesActive.get(stage); }
return stageMap.get(stageNumber).active;
} }
public int getStageCount() { public List<RocketComponent> getActiveComponents() {
return AxialStage.getStageCount(); ArrayList<RocketComponent> toReturn = new ArrayList<RocketComponent>();
for (StageFlags curFlags : this.stageMap.values()) {
if (curFlags.active) {
toReturn.add(curFlags.stage);
}
}
return toReturn;
}
public List<MotorInstance> getActiveMotors(final MotorInstanceConfiguration mic) {
ArrayList<MotorInstance> toReturn = new ArrayList<MotorInstance>();
for (MotorInstance inst : mic.getAllMotors()) {
MotorMount mount = inst.getMount();
if (mount instanceof RocketComponent) {
RocketComponent comp = (RocketComponent) mount;
if (this.isStageActive(comp.getStage().getStageNumber())) {
toReturn.add(inst);
}
}
}
return toReturn;
}
public List<AxialStage> getActiveStages() {
List<AxialStage> activeStages = new ArrayList<AxialStage>();
for (StageFlags flags : this.stageMap.values()) {
activeStages.add(flags.stage);
}
return activeStages;
} }
public int getActiveStageCount() { public int getActiveStageCount() {
int count = 0; int activeCount = 0;
int s = AxialStage.getStageCount(); for (StageFlags cur : this.stageMap.values()) {
if (cur.active) {
for (int i = 0; i < s; i++) { activeCount++;
if (stagesActive.get(i))
count++;
}
return count;
}
public int[] getActiveStages() {
// temporary hack fix
//int stageCount = Stage.getStageCount();
int stageCount = getRocket().getChildCount();
List<Integer> active = new ArrayList<Integer>();
int[] ret;
for (int i = 0; i < stageCount; i++) {
if (stagesActive.get(i)) {
active.add(i);
} }
} }
return activeCount;
ret = new int[active.size()];
for (int i = 0; i < ret.length; i++) {
ret[i] = active.get(i);
} }
return ret; /**
* Retrieve the bottom-most active stage.
* @return
*/
public AxialStage getBottomStage() {
AxialStage bottomStage = null;
for (StageFlags curFlags : this.stageMap.values()) {
if (curFlags.active) {
bottomStage = curFlags.stage;
}
}
return bottomStage;
}
public int getStageCount() {
return stageMap.size();
} }
@ -221,8 +290,38 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
((StateChangeListener) l).stateChanged(e); ((StateChangeListener) l).stateChanged(e);
} }
} }
updateStageMap();
} }
private void updateStageMap() {
if (this.rocket.getStageCount() == this.stageMap.size()) {
// no changes needed
return;
}
this.stageMap.clear();
for (AxialStage curStage : this.rocket.getStageList()) {
int prevStageNum = curStage.getStageNumber() - 1;
if (curStage.getParent() instanceof AxialStage) {
prevStageNum = curStage.getParent().getStageNumber();
}
StageFlags flagsToAdd = new StageFlags(curStage, prevStageNum, true);
this.stageMap.put(curStage.getStageNumber(), flagsToAdd);
}
}
// DEBUG / DEVEL
public String toDebug() {
StringBuilder buf = new StringBuilder();
buf.append(String.format("\nDumping stage config: \n"));
for (StageFlags flags : this.stageMap.values()) {
AxialStage curStage = flags.stage;
buf.append(String.format(" [%d]: %24s: %b\n", curStage.getStageNumber(), curStage.getName(), flags.active));
}
buf.append("\n\n");
return buf.toString();
}
@Override @Override
public void componentChanged(ComponentChangeEvent e) { public void componentChanged(ComponentChangeEvent e) {
@ -232,26 +331,6 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
/////////////// Helper methods /////////////// /////////////// Helper methods ///////////////
/**
* Return whether this configuration has any motors defined to it.
*
* @return true if this configuration has active motor mounts with motors defined to them.
*/
public boolean hasMotors() {
for (RocketComponent c : this) {
if (c instanceof MotorMount) {
MotorMount mount = (MotorMount) c;
if (!mount.isMotorMount())
continue;
if (mount.getMotor(this.flightConfigurationId) != null) {
return true;
}
}
}
return false;
}
/** /**
* Return whether a component is in the currently active stages. * Return whether a component is in the currently active stages.
*/ */
@ -272,7 +351,7 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
cachedBounds.clear(); cachedBounds.clear();
double minX = Double.POSITIVE_INFINITY, maxX = Double.NEGATIVE_INFINITY; double minX = Double.POSITIVE_INFINITY, maxX = Double.NEGATIVE_INFINITY;
for (RocketComponent component : this) { for (RocketComponent component : this.getActiveComponents()) {
for (Coordinate coord : component.getComponentBounds()) { for (Coordinate coord : component.getComponentBounds()) {
cachedBounds.add(coord); cachedBounds.add(coord);
if (coord.x < minX) if (coord.x < minX)
@ -308,57 +387,17 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
/**
* Return an iterator that iterates over the currently active components.
* The <code>Rocket</code> and <code>Stage</code> components are not returned,
* but instead all components that are within currently active stages.
*/
@Override
public Iterator<RocketComponent> iterator() {
List<RocketComponent> accumulator = new ArrayList<RocketComponent>();
accumulator = this.getActiveComponents(accumulator, rocket.getChildren());
return accumulator.iterator();
}
private List<RocketComponent> getActiveComponents(List<RocketComponent> accumulator, final List<RocketComponent> toScan) {
for (RocketComponent rc : toScan) {
if (rc instanceof AxialStage) {
if (!isStageActive(rc.getStageNumber())) {
continue;
}
} else {
accumulator.add(rc);
}
// recurse to children
getActiveComponents(accumulator, rc.getChildren());
}
return accumulator;
}
/**
* Return an iterator that iterates over all <code>MotorMount</code>s within the
* current configuration that have an active motor.
*
* @return an iterator over active motor mounts.
*/
public Iterator<MotorMount> motorIterator() {
return new MotorIterator();
}
/** /**
* Perform a deep-clone. The object references are also cloned and no * Perform a deep-clone. The object references are also cloned and no
* listeners are listening on the cloned object. The rocket instance remains the same. * listeners are listening on the cloned object. The rocket instance remains the same.
*/ */
@SuppressWarnings("unchecked")
@Override @Override
public Configuration clone() { public Configuration clone() {
try { try {
Configuration config = (Configuration) super.clone(); Configuration config = (Configuration) super.clone();
config.listenerList = new ArrayList<EventListener>(); config.listenerList = new ArrayList<EventListener>();
config.stagesActive = (BitSet) this.stagesActive.clone(); config.stageMap = (HashMap<Integer, StageFlags>) this.stageMap.clone();
config.cachedBounds = new ArrayList<Coordinate>(); config.cachedBounds = new ArrayList<Coordinate>();
config.boundsModID = -1; config.boundsModID = -1;
config.refLengthModID = -1; config.refLengthModID = -1;
@ -375,51 +414,5 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
return modID + rocket.getModID(); return modID + rocket.getModID();
} }
private class MotorIterator implements Iterator<MotorMount> {
private final Iterator<RocketComponent> iterator;
private MotorMount next = null;
public MotorIterator() {
this.iterator = iterator();
}
@Override
public boolean hasNext() {
getNext();
return (next != null);
}
@Override
public MotorMount next() {
getNext();
if (next == null) {
throw new NoSuchElementException("iterator called for too long");
}
MotorMount ret = next;
next = null;
return ret;
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove unsupported");
}
private void getNext() {
if (next != null)
return;
while (iterator.hasNext()) {
RocketComponent c = iterator.next();
if (c instanceof MotorMount) {
MotorMount mount = (MotorMount) c;
if (mount.isMotorMount() && mount.getMotor(flightConfigurationId) != null) {
next = mount;
return;
}
}
}
}
}
} }

View File

@ -8,7 +8,7 @@ public enum ReferenceType {
NOSECONE { NOSECONE {
@Override @Override
public double getReferenceLength(Configuration config) { public double getReferenceLength(Configuration config) {
for (RocketComponent c: config) { for (RocketComponent c : config.getActiveComponents()) {
if (c instanceof SymmetricComponent) { if (c instanceof SymmetricComponent) {
SymmetricComponent s = (SymmetricComponent) c; SymmetricComponent s = (SymmetricComponent) c;
if (s.getForeRadius() >= 0.0005) if (s.getForeRadius() >= 0.0005)
@ -25,7 +25,7 @@ public enum ReferenceType {
@Override @Override
public double getReferenceLength(Configuration config) { public double getReferenceLength(Configuration config) {
double r = 0; double r = 0;
for (RocketComponent c: config) { for (RocketComponent c : config.getActiveComponents()) {
if (c instanceof SymmetricComponent) { if (c instanceof SymmetricComponent) {
SymmetricComponent s = (SymmetricComponent) c; SymmetricComponent s = (SymmetricComponent) c;
r = Math.max(r, s.getForeRadius()); r = Math.max(r, s.getForeRadius());

View File

@ -80,7 +80,7 @@ public class Rocket extends RocketComponent {
// Does the rocket have a perfect finish (a notable amount of laminar flow) // Does the rocket have a perfect finish (a notable amount of laminar flow)
private boolean perfectFinish = false; private boolean perfectFinish = false;
private final HashMap<Integer, AxialStage> stageMap = new HashMap<Integer, AxialStage>();
///////////// Constructor ///////////// ///////////// Constructor /////////////
@ -93,7 +93,6 @@ public class Rocket extends RocketComponent {
functionalModID = modID; functionalModID = modID;
defaultConfiguration = new Configuration(this); defaultConfiguration = new Configuration(this);
AxialStage.resetStageCount();
} }
@ -130,7 +129,7 @@ public class Rocket extends RocketComponent {
*/ */
public int getStageCount() { public int getStageCount() {
checkState(); checkState();
return AxialStage.getStageCount(); return this.stageMap.size();
} }
/** /**
@ -195,29 +194,34 @@ public class Rocket extends RocketComponent {
return functionalModID; return functionalModID;
} }
public ArrayList<AxialStage> getStageList() { public Collection<AxialStage> getStageList() {
ArrayList<AxialStage> toReturn = new ArrayList<AxialStage>(); return this.stageMap.values();
toReturn = Rocket.getStages(toReturn, this);
return toReturn;
} }
private static ArrayList<AxialStage> getStages(ArrayList<AxialStage> accumulator, final RocketComponent parent) { private int getNewStageNumber() {
if ((null == accumulator) || (null == parent)) { int guess = 0;
return new ArrayList<AxialStage>(); while (stageMap.containsKey(guess)) {
guess++;
}
return guess;
} }
for (RocketComponent curChild : parent.getChildren()) { public void trackStage(final AxialStage newStage) {
if (curChild instanceof AxialStage) { int stageNumber = newStage.getStageNumber();
AxialStage curStage = (AxialStage) curChild; AxialStage value = stageMap.get(stageNumber);
accumulator.add(curStage);
if (newStage.equals(value)) {
// stage is already added. skip.
} else {
stageNumber = getNewStageNumber();
newStage.setStageNumber(stageNumber);
this.stageMap.put(stageNumber, newStage);
} }
getStages(accumulator, curChild);
}
return accumulator;
} }
public void forgetStage(final AxialStage oldStage) {
this.stageMap.remove(oldStage.getStageNumber());
}
public ReferenceType getReferenceType() { public ReferenceType getReferenceType() {
checkState(); checkState();

View File

@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory;
public abstract class RocketComponent implements ChangeSource, Cloneable, Iterable<RocketComponent> { public abstract class RocketComponent implements ChangeSource, Cloneable, Iterable<RocketComponent> {
@SuppressWarnings("unused")
private static final Logger log = LoggerFactory.getLogger(RocketComponent.class); private static final Logger log = LoggerFactory.getLogger(RocketComponent.class);
// Because of changes to Java 1.7.0-45's mechanism to construct DataFlavor objects (used in Drag and Drop) // Because of changes to Java 1.7.0-45's mechanism to construct DataFlavor objects (used in Drag and Drop)
@ -985,8 +986,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
* it should override this with a public method that simply calls this * it should override this with a public method that simply calls this
* supermethod AND fire a suitable ComponentChangeEvent. * supermethod AND fire a suitable ComponentChangeEvent.
* *
* @deprecated name is ambiguous in three-dimensional space: value may refer to any of the three dimensions. Please use 'setPositionX' instead. * @deprecated name is ambiguous in three-dimensional space: value may refer to any of the three dimensions. Please use 'setAxialOffset' instead.
*
* @param value the position value of the component. * @param value the position value of the component.
*/ */
public void setPositionValue(double value) { public void setPositionValue(double value) {
@ -1346,6 +1346,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
children.add(index, component); children.add(index, component);
component.parent = this; component.parent = this;
if (component instanceof AxialStage) {
AxialStage nStage = (AxialStage) component;
this.getRocket().trackStage(nStage);
}
this.checkComponentStructure(); this.checkComponentStructure();
component.checkComponentStructure(); component.checkComponentStructure();
@ -1363,6 +1368,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
RocketComponent component = children.remove(n); RocketComponent component = children.remove(n);
component.parent = null; component.parent = null;
if (component instanceof AxialStage) {
AxialStage nStage = (AxialStage) component;
this.getRocket().forgetStage(nStage);
}
this.checkComponentStructure(); this.checkComponentStructure();
component.checkComponentStructure(); component.checkComponentStructure();

View File

@ -1,12 +1,12 @@
package net.sf.openrocket.simulation; package net.sf.openrocket.simulation;
import java.util.List;
import net.sf.openrocket.masscalc.MassCalculator; import net.sf.openrocket.masscalc.MassCalculator;
import net.sf.openrocket.models.atmosphere.AtmosphericConditions; import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
import net.sf.openrocket.motor.MotorId;
import net.sf.openrocket.motor.MotorInstance; import net.sf.openrocket.motor.MotorInstance;
import net.sf.openrocket.motor.MotorInstanceConfiguration; import net.sf.openrocket.motor.MotorInstanceConfiguration;
import net.sf.openrocket.rocketcomponent.Configuration; import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.simulation.exception.SimulationException; import net.sf.openrocket.simulation.exception.SimulationException;
import net.sf.openrocket.simulation.listeners.SimulationListenerHelper; import net.sf.openrocket.simulation.listeners.SimulationListenerHelper;
import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.BugException;
@ -171,19 +171,18 @@ public abstract class AbstractSimulationStepper implements SimulationStepper {
} }
Configuration configuration = status.getConfiguration(); Configuration configuration = status.getConfiguration();
MotorInstanceConfiguration mic = status.getMotorConfiguration();
// Iterate over the motors and calculate combined thrust // Iterate over the motors and calculate combined thrust
MotorInstanceConfiguration mic = status.getMotorConfiguration();
if (!stepMotors) { if (!stepMotors) {
mic = mic.clone(); mic = mic.clone();
} }
mic.step(status.getSimulationTime() + timestep, acceleration, atmosphericConditions); mic.step(status.getSimulationTime() + timestep, acceleration, atmosphericConditions);
thrust = 0; thrust = 0;
for (MotorId id : mic.getMotorIDs()) {
if (configuration.isComponentActive((RocketComponent) mic.getMotorMount(id))) { List<MotorInstance> activeMotors = configuration.getActiveMotors(mic);
MotorInstance motor = mic.getMotorInstance(id); for (MotorInstance currentMotorInstance : activeMotors) {
thrust += motor.getThrust(); thrust += currentMotorInstance.getThrust();
}
} }
// Post-listeners // Post-listeners

View File

@ -1,6 +1,6 @@
package net.sf.openrocket.simulation; package net.sf.openrocket.simulation;
import java.util.Iterator; import java.util.List;
import net.sf.openrocket.aerodynamics.Warning; import net.sf.openrocket.aerodynamics.Warning;
import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.l10n.Translator;
@ -8,14 +8,13 @@ import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.motor.MotorId; import net.sf.openrocket.motor.MotorId;
import net.sf.openrocket.motor.MotorInstance; import net.sf.openrocket.motor.MotorInstance;
import net.sf.openrocket.motor.MotorInstanceConfiguration; import net.sf.openrocket.motor.MotorInstanceConfiguration;
import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.rocketcomponent.Configuration; import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.rocketcomponent.DeploymentConfiguration; import net.sf.openrocket.rocketcomponent.DeploymentConfiguration;
import net.sf.openrocket.rocketcomponent.IgnitionConfiguration; import net.sf.openrocket.rocketcomponent.IgnitionConfiguration;
import net.sf.openrocket.rocketcomponent.MotorConfiguration;
import net.sf.openrocket.rocketcomponent.MotorMount; import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.RecoveryDevice; import net.sf.openrocket.rocketcomponent.RecoveryDevice;
import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration; import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration;
import net.sf.openrocket.simulation.exception.MotorIgnitionException; import net.sf.openrocket.simulation.exception.MotorIgnitionException;
import net.sf.openrocket.simulation.exception.SimulationException; import net.sf.openrocket.simulation.exception.SimulationException;
@ -68,7 +67,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
// Set up rocket configuration // Set up rocket configuration
Configuration configuration = setupConfiguration(simulationConditions); Configuration configuration = setupConfiguration(simulationConditions);
flightConfigurationId = configuration.getFlightConfigurationID(); flightConfigurationId = configuration.getFlightConfigurationID();
MotorInstanceConfiguration motorConfiguration = setupMotorConfiguration(configuration); MotorInstanceConfiguration motorConfiguration = new MotorInstanceConfiguration(configuration);
if (motorConfiguration.getMotorIDs().isEmpty()) { if (motorConfiguration.getMotorIDs().isEmpty()) {
throw new MotorIgnitionException(trans.get("BasicEventSimulationEngine.error.noMotorsDefined")); throw new MotorIgnitionException(trans.get("BasicEventSimulationEngine.error.noMotorsDefined"));
} }
@ -199,7 +198,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
MotorInstance motor = status.getMotorConfiguration().getMotorInstance(motorId); MotorInstance motor = status.getMotorConfiguration().getMotorInstance(motorId);
if (!motor.isActive() && status.addBurntOutMotor(motorId)) { if (!motor.isActive() && status.addBurntOutMotor(motorId)) {
addEvent(new FlightEvent(FlightEvent.Type.BURNOUT, status.getSimulationTime(), addEvent(new FlightEvent(FlightEvent.Type.BURNOUT, status.getSimulationTime(),
(RocketComponent) status.getMotorConfiguration().getMotorMount(motorId), motorId)); (RocketComponent) status.getMotorConfiguration().getMotorInstance(motorId).getMount(), motorId));
} }
} }
@ -221,7 +220,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
if (wantToTumble) { if (wantToTumble) {
final boolean tooMuchThrust = t > THRUST_TUMBLE_CONDITION; final boolean tooMuchThrust = t > THRUST_TUMBLE_CONDITION;
final boolean isSustainer = status.getConfiguration().isStageActive(0); //final boolean isSustainer = status.getConfiguration().isStageActive(0);
final boolean isApogee = status.isApogeeReached(); final boolean isApogee = status.isApogeeReached();
if (tooMuchThrust) { if (tooMuchThrust) {
status.getWarnings().add(Warning.TUMBLE_UNDER_THRUST); status.getWarnings().add(Warning.TUMBLE_UNDER_THRUST);
@ -261,37 +260,6 @@ public class BasicEventSimulationEngine implements SimulationEngine {
/**
* Create a new motor instance configuration for the rocket configuration.
*
* @param configuration the rocket configuration.
* @return a new motor instance configuration with all motors in place.
*/
private MotorInstanceConfiguration setupMotorConfiguration(Configuration configuration) {
MotorInstanceConfiguration motors = new MotorInstanceConfiguration();
final String flightConfigId = configuration.getFlightConfigurationID();
Iterator<MotorMount> iterator = configuration.motorIterator();
while (iterator.hasNext()) {
MotorMount mount = iterator.next();
RocketComponent component = (RocketComponent) mount;
MotorConfiguration motorConfig = mount.getMotorConfiguration().get(flightConfigId);
IgnitionConfiguration ignitionConfig = mount.getIgnitionConfiguration().get(flightConfigId);
Motor motor = motorConfig.getMotor();
if (motor != null) {
Coordinate[] positions = component.toAbsolute(mount.getMotorPosition(flightConfigId));
for (int i = 0; i < positions.length; i++) {
Coordinate position = positions[i];
MotorId id = new MotorId(component.getID(), i + 1);
motors.addMotor(id, motor.getInstance(), motorConfig.getEjectionDelay(), mount,
ignitionConfig.getIgnitionEvent(), ignitionConfig.getIgnitionDelay(), position);
}
}
}
return motors;
}
/** /**
* Handles events occurring during the flight from the event queue. * Handles events occurring during the flight from the event queue.
* Each event that has occurred before or at the current simulation time is * Each event that has occurred before or at the current simulation time is
@ -340,12 +308,13 @@ public class BasicEventSimulationEngine implements SimulationEngine {
// Check for motor ignition events, add ignition events to queue // Check for motor ignition events, add ignition events to queue
for (MotorId id : status.getMotorConfiguration().getMotorIDs()) { for (MotorId id : status.getMotorConfiguration().getMotorIDs()) {
IgnitionConfiguration.IgnitionEvent ignitionEvent = status.getMotorConfiguration().getMotorIgnitionEvent(id); MotorInstance inst = status.getMotorConfiguration().getMotorInstance(id);
MotorMount mount = status.getMotorConfiguration().getMotorMount(id); IgnitionConfiguration.IgnitionEvent ignitionEvent = inst.getIgnitionEvent();
MotorMount mount = inst.getMount();
RocketComponent component = (RocketComponent) mount; RocketComponent component = (RocketComponent) mount;
if (ignitionEvent.isActivationEvent(event, component)) { if (ignitionEvent.isActivationEvent(event, component)) {
double ignitionDelay = status.getMotorConfiguration().getMotorIgnitionDelay(id); double ignitionDelay = inst.getIgnitionDelay();
addEvent(new FlightEvent(FlightEvent.Type.IGNITION, addEvent(new FlightEvent(FlightEvent.Type.IGNITION,
status.getSimulationTime() + ignitionDelay, status.getSimulationTime() + ignitionDelay,
component, id)); component, id));
@ -354,11 +323,12 @@ public class BasicEventSimulationEngine implements SimulationEngine {
// Check for stage separation event // Check for stage separation event
for (int stageNo : status.getConfiguration().getActiveStages()) {
for (AxialStage stage : status.getConfiguration().getActiveStages()) {
int stageNo = stage.getStageNumber();
if (stageNo == 0) if (stageNo == 0)
continue; continue;
AxialStage stage = (AxialStage) status.getConfiguration().getRocket().getChild(stageNo);
StageSeparationConfiguration separationConfig = stage.getStageSeparationConfiguration().get(flightConfigurationId); StageSeparationConfiguration separationConfig = stage.getStageSeparationConfiguration().get(flightConfigurationId);
if (separationConfig.getSeparationEvent().isSeparationEvent(event, stage)) { if (separationConfig.getSeparationEvent().isSeparationEvent(event, stage)) {
addEvent(new FlightEvent(FlightEvent.Type.STAGE_SEPARATION, addEvent(new FlightEvent(FlightEvent.Type.STAGE_SEPARATION,
@ -368,9 +338,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
// Check for recovery device deployment, add events to queue // Check for recovery device deployment, add events to queue
Iterator<RocketComponent> rci = status.getConfiguration().iterator(); for (RocketComponent c : status.getConfiguration().getActiveComponents()) {
while (rci.hasNext()) {
RocketComponent c = rci.next();
if (!(c instanceof RecoveryDevice)) if (!(c instanceof RecoveryDevice))
continue; continue;
DeploymentConfiguration deployConfig = ((RecoveryDevice) c).getDeploymentConfiguration().get(flightConfigurationId); DeploymentConfiguration deployConfig = ((RecoveryDevice) c).getDeploymentConfiguration().get(flightConfigurationId);
@ -393,8 +361,10 @@ public class BasicEventSimulationEngine implements SimulationEngine {
case IGNITION: { case IGNITION: {
// Ignite the motor // Ignite the motor
MotorId motorId = (MotorId) event.getData(); MotorId motorId = (MotorId) event.getData();
MotorInstanceConfiguration config = status.getMotorConfiguration(); MotorInstanceConfiguration motorConfig = status.getMotorConfiguration();
config.setMotorIgnitionTime(motorId, event.getTime()); MotorInstance inst = motorConfig.getMotorInstance(motorId);
inst.setIgnitionTime(event.getTime());
status.setMotorIgnited(true); status.setMotorIgnited(true);
status.getFlightData().addEvent(event); status.getFlightData().addEvent(event);
@ -422,7 +392,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
} }
// Add ejection charge event // Add ejection charge event
MotorId motorId = (MotorId) event.getData(); MotorId motorId = (MotorId) event.getData();
double delay = status.getMotorConfiguration().getEjectionDelay(motorId); double delay = status.getMotorConfiguration().getMotorInstance(motorId).getEjectionDelay();
if (delay != Motor.PLUGGED) { if (delay != Motor.PLUGGED) {
addEvent(new FlightEvent(FlightEvent.Type.EJECTION_CHARGE, status.getSimulationTime() + delay, addEvent(new FlightEvent(FlightEvent.Type.EJECTION_CHARGE, status.getSimulationTime() + delay,
event.getSource(), event.getData())); event.getSource(), event.getData()));
@ -450,7 +420,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
stages.add(boosterStatus); stages.add(boosterStatus);
// Mark the status as having dropped the booster // Mark the status as having dropped the booster
status.getConfiguration().setToStage(n - 1); status.getConfiguration().clearOnlyStage(n);
// Mark the booster status as only having the booster. // Mark the booster status as only having the booster.
boosterStatus.getConfiguration().setOnlyStage(n); boosterStatus.getConfiguration().setOnlyStage(n);
@ -476,12 +446,14 @@ public class BasicEventSimulationEngine implements SimulationEngine {
// TODO: HIGH: Check stage activeness for other events as well? // TODO: HIGH: Check stage activeness for other events as well?
// Check whether any motor in the active stages is active anymore // Check whether any motor in the active stages is active anymore
for (MotorId motorId : status.getMotorConfiguration().getMotorIDs()) { List<MotorInstance> activeMotors = status.getConfiguration().getActiveMotors(status.getMotorConfiguration());
int stage = ((RocketComponent) status.getMotorConfiguration(). for (MotorInstance curInstance : activeMotors) {
getMotorMount(motorId)).getStageNumber(); MotorId curID = curInstance.getID();
RocketComponent comp = ((RocketComponent) curInstance.getMount());
int stage = comp.getStageNumber();
if (!status.getConfiguration().isStageActive(stage)) if (!status.getConfiguration().isStageActive(stage))
continue; continue;
if (!status.getMotorConfiguration().getMotorInstance(motorId).isActive()) if (!status.getMotorConfiguration().getMotorInstance(curID).isActive())
continue; continue;
status.getWarnings().add(Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING); status.getWarnings().add(Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING);
} }

View File

@ -119,7 +119,7 @@ public class SimulationStatus implements Monitorable {
*/ */
double length = this.simulationConditions.getLaunchRodLength(); double length = this.simulationConditions.getLaunchRodLength();
double lugPosition = Double.NaN; double lugPosition = Double.NaN;
for (RocketComponent c : this.configuration) { for (RocketComponent c : this.configuration.getActiveComponents()) {
if (c instanceof LaunchLug) { if (c instanceof LaunchLug) {
double pos = c.toAbsolute(new Coordinate(c.getLength()))[0].x; double pos = c.toAbsolute(new Coordinate(c.getLength()))[0].x;
if (Double.isNaN(lugPosition) || pos > lugPosition) { if (Double.isNaN(lugPosition) || pos > lugPosition) {

View File

@ -6,8 +6,9 @@ import java.util.Map;
import net.sf.openrocket.aerodynamics.AerodynamicCalculator; import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
import net.sf.openrocket.aerodynamics.AerodynamicForces; import net.sf.openrocket.aerodynamics.AerodynamicForces;
import net.sf.openrocket.aerodynamics.FlightConditions; import net.sf.openrocket.aerodynamics.FlightConditions;
import net.sf.openrocket.motor.MotorId; import net.sf.openrocket.motor.MotorInstance;
import net.sf.openrocket.motor.MotorInstanceConfiguration; import net.sf.openrocket.motor.MotorInstanceConfiguration;
import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.simulation.FlightDataBranch; import net.sf.openrocket.simulation.FlightDataBranch;
import net.sf.openrocket.simulation.FlightDataType; import net.sf.openrocket.simulation.FlightDataType;
@ -20,7 +21,9 @@ import net.sf.openrocket.util.Coordinate;
public class DampingMoment extends AbstractSimulationListener { public class DampingMoment extends AbstractSimulationListener {
private static final FlightDataType type = FlightDataType.getType("Damping moment coefficient", "Cdm", UnitGroup.UNITS_COEFFICIENT); private static final FlightDataType type = FlightDataType.getType("Damping moment coefficient", "Cdm", UnitGroup.UNITS_COEFFICIENT);
private static final FlightDataType[] typeList = { type };
// unused
//private static final FlightDataType[] typeList = { type };
@Override @Override
public FlightConditions postFlightConditions(SimulationStatus status, FlightConditions flightConditions) throws SimulationException { public FlightConditions postFlightConditions(SimulationStatus status, FlightConditions flightConditions) throws SimulationException {
@ -66,11 +69,12 @@ public class DampingMoment extends AbstractSimulationListener {
// find the maximum distance from nose to nozzle. // find the maximum distance from nose to nozzle.
double nozzleDistance = 0; double nozzleDistance = 0;
for (MotorId id : status.getMotorConfiguration().getMotorIDs()) { Configuration config = status.getConfiguration();
MotorInstanceConfiguration config = status.getMotorConfiguration(); MotorInstanceConfiguration motorConfig = status.getMotorConfiguration();
Coordinate position = config.getMotorPosition(id); for (MotorInstance inst : config.getActiveMotors(motorConfig)) {
Coordinate position = inst.getPosition();
double x = position.x + config.getMotorInstance(id).getParentMotor().getLength(); double x = position.x + inst.getMotor().getLength();
if (x > nozzleDistance) { if (x > nozzleDistance) {
nozzleDistance = x; nozzleDistance = x;
} }

View File

@ -78,7 +78,7 @@ public class RollControlListener extends AbstractSimulationListener {
// Find the fin set named CONTROL // Find the fin set named CONTROL
FinSet finset = null; FinSet finset = null;
for (RocketComponent c : status.getConfiguration()) { for (RocketComponent c : status.getConfiguration().getActiveComponents()) {
if ((c instanceof FinSet) && (c.getName().equals(CONTROL_FIN_NAME))) { if ((c instanceof FinSet) && (c.getName().equals(CONTROL_FIN_NAME))) {
finset = (FinSet) c; finset = (FinSet) c;
break; break;

View File

@ -98,7 +98,7 @@ public class CaliberUnit extends GeneralUnit {
* @return the caliber of the rocket, or the default caliber. * @return the caliber of the rocket, or the default caliber.
*/ */
public static double calculateCaliber(Configuration config) { public static double calculateCaliber(Configuration config) {
return calculateCaliber(config.iterator()); return calculateCaliber(config.getActiveComponents().iterator());
} }
/** /**

View File

@ -647,7 +647,6 @@ public class BoosterSetTest extends BaseTestCase {
assertEquals(" init order error: " + treeDump + " Booster B: resultant positions: ", expectedOffset, resultantOffsetB, EPSILON); assertEquals(" init order error: " + treeDump + " Booster B: resultant positions: ", expectedOffset, resultantOffsetB, EPSILON);
} }
@Test @Test
public void testStageNumbering() { public void testStageNumbering() {
Rocket rocket = createTestRocket(); Rocket rocket = createTestRocket();
@ -679,8 +678,29 @@ public class BoosterSetTest extends BaseTestCase {
actualStageNumber = boosterB.getStageNumber(); actualStageNumber = boosterB.getStageNumber();
assertEquals(" init order error: Booster B: resultant positions: ", expectedStageNumber, actualStageNumber); assertEquals(" init order error: Booster B: resultant positions: ", expectedStageNumber, actualStageNumber);
} //rocket.getDefaultConfiguration().dumpConfig();
core.removeChild(2);
String treedump = rocket.toDebugTree();
int expectedStageCount = 3;
int actualStageCount = rocket.getStageCount();
assertEquals(" Stage tracking error: removed booster A, but count not updated: " + treedump, expectedStageCount, actualStageCount);
actualStageCount = rocket.getDefaultConfiguration().getStageCount();
assertEquals(" Stage tracking error: removed booster A, but configuration not updated: " + treedump, expectedStageCount, actualStageCount);
BoosterSet boosterC = createBooster();
boosterC.setName("Booster C Stage");
core.addChild(boosterC);
boosterC.setAxialOffset(Position.BOTTOM, 0);
expectedStageNumber = 2;
actualStageNumber = boosterC.getStageNumber();
assertEquals(" init order error: Booster B: resultant positions: ", expectedStageNumber, actualStageNumber);
//rocket.getDefaultConfiguration().dumpConfig();
}
@Test @Test
public void testToAbsolute() { public void testToAbsolute() {

View File

@ -1,11 +1,12 @@
package net.sf.openrocket.rocketcomponent; package net.sf.openrocket.rocketcomponent;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.util.BitSet; import java.util.BitSet;
import java.util.EventObject; import java.util.EventObject;
import java.util.Iterator;
import net.sf.openrocket.rocketcomponent.RocketComponent.Position; import net.sf.openrocket.rocketcomponent.RocketComponent.Position;
import net.sf.openrocket.util.StateChangeListener; import net.sf.openrocket.util.StateChangeListener;
@ -72,20 +73,9 @@ public class ConfigurationTest extends BaseTestCase {
Configuration config = r1.getDefaultConfiguration(); Configuration config = r1.getDefaultConfiguration();
/* Test */ /* Test */
// Test rocket component iterator // Test rocket component iterator
// TODO: validate iterator iterates correctly // the component iterator is no longer a custom iterator....
for (Iterator<RocketComponent> i = config.iterator(); i.hasNext();) { // use the standard iterator over the Collection<> returned by config.getActiveComponents()
i.next();
}
// Rocket component iterator remove method is unsupported, should throw exception
try {
Iterator<RocketComponent> configIterator = config.iterator();
configIterator.remove();
} catch (UnsupportedOperationException e) {
assertTrue(e.getMessage().equals("remove unsupported"));
}
// Test motor iterator // Test motor iterator
/* TODO: no motors in model Iterator<MotorMount> motorIterator() /* TODO: no motors in model Iterator<MotorMount> motorIterator()
@ -95,14 +85,14 @@ public class ConfigurationTest extends BaseTestCase {
} }
*/ */
// Motor iterator remove method is unsupported, should throw exception // // Motor iterator remove method is unsupported, should throw exception
try { // try {
Iterator<MotorMount> motorIterator = config.motorIterator(); // Iterator<MotorMount> motorIterator = config.motorIterator();
motorIterator.remove(); // motorIterator.remove();
} catch (UnsupportedOperationException e) { // } catch (UnsupportedOperationException e) {
assertTrue(e.getMessage().equals("remove unsupported")); // assertTrue(e.getMessage().equals("remove unsupported"));
} // }
//
/* Cleanup */ /* Cleanup */
config.release(); config.release();
@ -119,7 +109,7 @@ public class ConfigurationTest extends BaseTestCase {
Configuration configClone = config.clone(); // TODO validate clone worked Configuration configClone = config.clone(); // TODO validate clone worked
assertFalse(config.getRocket() == null); assertFalse(config.getRocket() == null);
assertFalse(config.hasMotors()); // assertFalse(config.hasMotors());
config.release(); config.release();
} }
@ -211,31 +201,34 @@ public class ConfigurationTest extends BaseTestCase {
Rocket r1 = makeSingleStageTestRocket(); Rocket r1 = makeSingleStageTestRocket();
Configuration config = r1.getDefaultConfiguration(); Configuration config = r1.getDefaultConfiguration();
BitSet activeStageFlags = new BitSet();
activeStageFlags.set(0, false); // first stage
/* Test */ /* Test */
// test cloning of single stage rocket // test cloning of single stage rocket
Configuration configClone = config.clone(); // TODO validate clone worked Configuration configClone = config.clone(); // TODO validate clone worked
configClone.release();
// test explicitly setting only first stage active // test explicitly setting only first stage active
config.clearAllStages();
config.setOnlyStage(0); config.setOnlyStage(0);
activeStageFlags.clear();
activeStageFlags.set(0, true);
validateStages(config, 1, activeStageFlags); //config.dumpConfig();
//System.err.println("treedump: \n" + treedump);
// test that getStageCount() returns correct value
int expectedStageCount = 1;
int stageCount = config.getStageCount();
assertTrue("stage count doesn't match", stageCount == expectedStageCount);
expectedStageCount = 1;
stageCount = config.getActiveStageCount();
assertThat("active stage count doesn't match", stageCount, equalTo(expectedStageCount));
// test explicitly setting all stages up to first stage active // test explicitly setting all stages up to first stage active
config.setToStage(0); config.setOnlyStage(0);
activeStageFlags.clear();
activeStageFlags.set(0, true);
validateStages(config, 1, activeStageFlags);
// test explicitly setting all stages active // test explicitly setting all stages active
config.setAllStages(); config.setAllStages();
activeStageFlags.clear();
activeStageFlags.set(0, true);
validateStages(config, 1, activeStageFlags);
// Cleanup // Cleanup
config.release(); config.release();
@ -252,43 +245,57 @@ public class ConfigurationTest extends BaseTestCase {
Rocket r1 = makeTwoStageTestRocket(); Rocket r1 = makeTwoStageTestRocket();
Configuration config = r1.getDefaultConfiguration(); Configuration config = r1.getDefaultConfiguration();
BitSet activeStageFlags = new BitSet();
activeStageFlags.set(0, false); // booster (first) stage
activeStageFlags.set(1, false); // sustainer (second) stage
/* Test */
// test cloning of two stage rocket // test cloning of two stage rocket
Configuration configClone = config.clone(); // TODO validate clone worked Configuration configClone = config.clone(); // TODO validate clone worked
configClone.release();
int expectedStageCount;
int stageCount;
expectedStageCount = 2;
stageCount = config.getStageCount();
assertThat("stage count doesn't match", stageCount, equalTo(expectedStageCount));
config.clearAllStages();
assertThat(" clear all stages: check #0: ", config.isStageActive(0), equalTo(false));
assertThat(" clear all stages: check #1: ", config.isStageActive(1), equalTo(false));
// test explicitly setting only first stage active // test explicitly setting only first stage active
config.setOnlyStage(0); config.setOnlyStage(0);
activeStageFlags.clear();
activeStageFlags.set(0, true);
validateStages(config, 2, activeStageFlags);
// test explicitly setting all stages up to first stage active expectedStageCount = 1;
config.setToStage(0); stageCount = config.getActiveStageCount();
activeStageFlags.clear(); assertThat("active stage count doesn't match", stageCount, equalTo(expectedStageCount));
activeStageFlags.set(0, true);
validateStages(config, 2, activeStageFlags); assertThat(" setting single stage active: ", config.isStageActive(0), equalTo(true));
// test explicitly setting all stages up to second stage active // test explicitly setting all stages up to second stage active
config.setToStage(1); config.setOnlyStage(1);
activeStageFlags.clear(); assertThat(config.toDebug() + "Setting single stage active: ", config.isStageActive(1), equalTo(true));
activeStageFlags.set(0, 2, true);
validateStages(config, 2, activeStageFlags); config.clearOnlyStage(0);
assertThat(" deactivate stage #0: ", config.isStageActive(0), equalTo(false));
assertThat(" deactive stage #0: ", config.isStageActive(1), equalTo(true));
// test explicitly setting all two stages active // test explicitly setting all two stages active
config.setAllStages(); config.setAllStages();
activeStageFlags.clear(); assertThat(" activate all stages: check #0: ", config.isStageActive(0), equalTo(true));
activeStageFlags.set(0, 2, true); assertThat(" activate all stages: check #1: ", config.isStageActive(1), equalTo(true));
validateStages(config, 2, activeStageFlags);
// test toggling single stage
config.setAllStages();
config.toggleStage(0);
assertThat(" toggle stage #0: ", config.isStageActive(0), equalTo(false));
config.toggleStage(0);
assertThat(" toggle stage #0: ", config.isStageActive(0), equalTo(true));
config.toggleStage(0);
assertThat(" toggle stage #0: ", config.isStageActive(0), equalTo(false));
// Cleanup // Cleanup
config.release(); config.release();
} }
///////////////////// Helper Methods //////////////////////////// ///////////////////// Helper Methods ////////////////////////////
@ -307,43 +314,45 @@ public class ConfigurationTest extends BaseTestCase {
} }
} }
assertTrue(config.getActiveStageCount() == expectedActiveStageCount); assertTrue(config.getActiveStageCount() == expectedActiveStageCount);
int[] stages = config.getActiveStages();
assertTrue(stages.length == expectedActiveStageCount);
// test if isHead() detects first stage being active or inactive assertTrue("this test is not yet written.", false);
if (activeStageFlags.get(0)) { // int[] stages = config.getActiveStages();
assertTrue(config.isHead()); //
} else { // assertTrue(stages.length == expectedActiveStageCount);
assertFalse(config.isHead()); //
} // // test if isHead() detects first stage being active or inactive
// if (activeStageFlags.get(0)) {
// test if isStageActive() detects stage x being active or inactive // assertTrue(config.isHead());
for (int i = 0; i < expectedStageCount; i++) { // } else {
if (activeStageFlags.get(i)) { // assertFalse(config.isHead());
assertTrue(config.isStageActive(i)); // }
} else { //
assertFalse(config.isStageActive(i)); // // test if isStageActive() detects stage x being active or inactive
} // for (int i = 0; i < expectedStageCount; i++) {
} // if (activeStageFlags.get(i)) {
// assertTrue(config.isStageActive(i));
// test boundary conditions // } else {
// assertFalse(config.isStageActive(i));
// stage -1 should not exist, and isStageActive() should throw exception // }
boolean IndexOutOfBoundsExceptionFlag = false; // }
try { //
assertFalse(config.isStageActive(-1)); // // test boundary conditions
} catch (IndexOutOfBoundsException e) { //
IndexOutOfBoundsExceptionFlag = true; // // stage -1 should not exist, and isStageActive() should throw exception
} // boolean IndexOutOfBoundsExceptionFlag = false;
assertTrue(IndexOutOfBoundsExceptionFlag); // try {
// assertFalse(config.isStageActive(-1));
// n+1 stage should not exist, isStageActive() should return false // } catch (IndexOutOfBoundsException e) {
// TODO: isStageActive(stageCount + 1) really should throw IndexOutOfBoundsException // IndexOutOfBoundsExceptionFlag = true;
assertFalse(config.isStageActive(stageCount + 1)); // }
// assertTrue(IndexOutOfBoundsExceptionFlag);
//
// // n+1 stage should not exist, isStageActive() should return false
// // TODO: isStageActive(stageCount + 1) really should throw IndexOutOfBoundsException
// assertFalse(config.isStageActive(stageCount + 1));
} }
//////////////////// Test Rocket Creation Methods ///////////////////////// //////////////////// Test Rocket Creation Methods /////////////////////////
public static Rocket makeEmptyRocket() { public static Rocket makeEmptyRocket() {

View File

@ -11,12 +11,15 @@ import javax.swing.JToggleButton;
import net.miginfocom.swing.MigLayout; import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.rocketcomponent.Configuration; import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.startup.Application; import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.StateChangeListener; import net.sf.openrocket.util.StateChangeListener;
public class StageSelector extends JPanel implements StateChangeListener { public class StageSelector extends JPanel implements StateChangeListener {
private static final long serialVersionUID = -2898763402479628711L;
private static final Translator trans = Application.getTranslator(); private static final Translator trans = Application.getTranslator();
private final Configuration configuration; private final Configuration configuration;
@ -40,13 +43,11 @@ public class StageSelector extends JPanel implements StateChangeListener {
if (buttons.size() == stages) if (buttons.size() == stages)
return; return;
while (buttons.size() > stages) { buttons.clear();
JToggleButton button = buttons.remove(buttons.size() - 1); this.removeAll();
this.remove(button); for(AxialStage stage : configuration.getRocket().getStageList()){
} int stageNum = stage.getStageNumber();
JToggleButton button = new JToggleButton(new StageAction(stageNum));
while (buttons.size() < stages) {
JToggleButton button = new JToggleButton(new StageAction(buttons.size()));
this.add(button); this.add(button);
buttons.add(button); buttons.add(button);
} }
@ -55,8 +56,6 @@ public class StageSelector extends JPanel implements StateChangeListener {
} }
@Override @Override
public void stateChanged(EventObject e) { public void stateChanged(EventObject e) {
updateButtons(); updateButtons();
@ -64,10 +63,11 @@ public class StageSelector extends JPanel implements StateChangeListener {
private class StageAction extends AbstractAction implements StateChangeListener { private class StageAction extends AbstractAction implements StateChangeListener {
private final int stage; private static final long serialVersionUID = 7433006728984943763L;
private final int stageNumber;
public StageAction(final int stage) { public StageAction(final int stage) {
this.stage = stage; this.stageNumber = stage;
configuration.addChangeListener(this); configuration.addChangeListener(this);
stateChanged(null); stateChanged(null);
} }
@ -75,37 +75,20 @@ public class StageSelector extends JPanel implements StateChangeListener {
@Override @Override
public Object getValue(String key) { public Object getValue(String key) {
if (key.equals(NAME)) { if (key.equals(NAME)) {
//// Stage // Stage
return trans.get("StageAction.Stage") + " " + (stage + 1); return trans.get("StageAction.Stage") + " " + (stageNumber );
} }
return super.getValue(key); return super.getValue(key);
} }
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
configuration.setToStage(stage); configuration.toggleStage(stageNumber);
// boolean state = (Boolean)getValue(SELECTED_KEY);
// if (state == true) {
// // Was disabled, now enabled
// configuration.setToStage(stage);
// } else {
// // Was enabled, check what to do
// if (configuration.isStageActive(stage + 1)) {
// configuration.setToStage(stage);
// } else {
// if (stage == 0)
// configuration.setAllStages();
// else
// configuration.setToStage(stage-1);
// }
// }
// stateChanged(null);
} }
@Override @Override
public void stateChanged(EventObject e) { public void stateChanged(EventObject e) {
this.putValue(SELECTED_KEY, configuration.isStageActive(stage)); this.putValue(SELECTED_KEY, configuration.isStageActive(stageNumber));
} }
} }
} }

View File

@ -513,7 +513,7 @@ public class ComponentAnalysisDialog extends JDialog implements StateChangeListe
cgData.clear(); cgData.clear();
dragData.clear(); dragData.clear();
rollData.clear(); rollData.clear();
for (RocketComponent c : configuration) { for (RocketComponent c : configuration.getActiveComponents()) {
forces = aeroData.get(c); forces = aeroData.get(c);
Coordinate cg = massData.get(c); Coordinate cg = massData.get(c);

View File

@ -2,7 +2,6 @@ package net.sf.openrocket.gui.figure3d;
import java.awt.Point; import java.awt.Point;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Set; import java.util.Set;
import java.util.Vector; import java.util.Vector;
@ -62,7 +61,7 @@ public abstract class RocketRenderer {
// Store a vector of pickable parts. // Store a vector of pickable parts.
final Vector<RocketComponent> pickParts = new Vector<RocketComponent>(); final Vector<RocketComponent> pickParts = new Vector<RocketComponent>();
for (RocketComponent c : configuration) { for (RocketComponent c : configuration.getActiveComponents()) {
if (ignore != null && ignore.contains(c)) if (ignore != null && ignore.contains(c))
continue; continue;
@ -116,7 +115,7 @@ public abstract class RocketRenderer {
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_SPECULAR, colorBlack, 0); gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_SPECULAR, colorBlack, 0);
gl.glLineWidth(5.0f); gl.glLineWidth(5.0f);
for (RocketComponent c : configuration) { for (RocketComponent c : configuration.getActiveComponents()) {
if (selection.contains(c)) { if (selection.contains(c)) {
// Draw as lines, set Z to nearest // Draw as lines, set Z to nearest
gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_LINE); gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_LINE);
@ -141,7 +140,7 @@ public abstract class RocketRenderer {
gl.glCullFace(GL.GL_BACK); gl.glCullFace(GL.GL_BACK);
// Draw all inner components // Draw all inner components
for (RocketComponent c : configuration) { for (RocketComponent c : configuration.getActiveComponents()) {
if (isDrawn(c)) { if (isDrawn(c)) {
if (!isDrawnTransparent(c)) { if (!isDrawnTransparent(c)) {
renderComponent(gl, c, 1.0f); renderComponent(gl, c, 1.0f);
@ -153,7 +152,7 @@ public abstract class RocketRenderer {
// Draw T&T front faces blended, without depth test // Draw T&T front faces blended, without depth test
gl.glEnable(GL.GL_BLEND); gl.glEnable(GL.GL_BLEND);
for (RocketComponent c : configuration) { for (RocketComponent c : configuration.getActiveComponents()) {
if (isDrawn(c)) { if (isDrawn(c)) {
if (isDrawnTransparent(c)) { if (isDrawnTransparent(c)) {
renderComponent(gl, c, 0.2f); renderComponent(gl, c, 0.2f);
@ -166,9 +165,11 @@ public abstract class RocketRenderer {
private void renderMotors(GL2 gl, Configuration configuration) { private void renderMotors(GL2 gl, Configuration configuration) {
String motorID = configuration.getFlightConfigurationID(); String motorID = configuration.getFlightConfigurationID();
Iterator<MotorMount> iterator = configuration.motorIterator();
while (iterator.hasNext()) { for( RocketComponent comp : configuration.getActiveComponents()){
MotorMount mount = iterator.next(); if( comp instanceof MotorMount){
MotorMount mount = (MotorMount) comp;
Motor motor = mount.getMotorConfiguration().get(motorID).getMotor(); Motor motor = mount.getMotorConfiguration().get(motorID).getMotor();
double length = motor.getLength(); double length = motor.getLength();
@ -182,6 +183,7 @@ public abstract class RocketRenderer {
gl.glPopMatrix(); gl.glPopMatrix();
} }
} }
}
} }

View File

@ -14,7 +14,6 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Vector; import java.util.Vector;
import javax.media.opengl.DebugGL2;
import javax.media.opengl.GL; import javax.media.opengl.GL;
import javax.media.opengl.GL2; import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLAutoDrawable;
@ -44,7 +43,6 @@ import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.rocketcomponent.Configuration; import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.rocketcomponent.MotorMount; import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.startup.Application; import net.sf.openrocket.startup.Application;
import net.sf.openrocket.startup.Preferences; import net.sf.openrocket.startup.Preferences;
import net.sf.openrocket.util.Color; import net.sf.openrocket.util.Color;
@ -416,22 +414,24 @@ public class PhotoPanel extends JPanel implements GLEventListener {
rr.render(drawable, configuration, new HashSet<RocketComponent>()); rr.render(drawable, configuration, new HashSet<RocketComponent>());
//Figure out the lowest stage shown //Figure out the lowest stage shown
final int currentStageNumber = configuration.getActiveStages()[configuration.getActiveStages().length-1]; final int bottomStageNumber = configuration.getBottomStage().getStageNumber();
final AxialStage currentStage = (AxialStage)configuration.getRocket().getChild(currentStageNumber); //final int currentStageNumber = configuration.getActiveStages()[configuration.getActiveStages().length-1];
//final AxialStage currentStage = (AxialStage)configuration.getRocket().getChild( bottomStageNumber);
final String motorID = configuration.getFlightConfigurationID(); final String motorID = configuration.getFlightConfigurationID();
final Iterator<MotorMount> iterator = configuration.motorIterator();
motor: while (iterator.hasNext()) {
final MotorMount mount = iterator.next(); final Iterator<RocketComponent> iter = configuration.getActiveComponents().iterator();
while( iter.hasNext()){
RocketComponent comp = iter.next();
if( comp instanceof MotorMount){
final MotorMount mount = (MotorMount) comp;
int curStageNumber = comp.getStageNumber();
//If this mount is not in currentStage continue on to the next one. //If this mount is not in currentStage continue on to the next one.
RocketComponent parent = ((RocketComponent)mount); if( curStageNumber != bottomStageNumber ){
while ( null != (parent = parent.getParent()) ){ continue;
if ( parent instanceof AxialStage ){
if ( parent != currentStage )
continue motor;
break;
}
} }
final Motor motor = mount.getMotorConfiguration().get(motorID).getMotor(); final Motor motor = mount.getMotorConfiguration().get(motorID).getMotor();
@ -449,6 +449,7 @@ public class PhotoPanel extends JPanel implements GLEventListener {
gl.glPopMatrix(); gl.glPopMatrix();
} }
} }
}
gl.glDisable(GL.GL_BLEND); gl.glDisable(GL.GL_BLEND);
gl.glFrontFace(GL.GL_CCW); gl.glFrontFace(GL.GL_CCW);

View File

@ -13,6 +13,7 @@ import java.awt.geom.Rectangle2D;
import net.sf.openrocket.aerodynamics.Warning; import net.sf.openrocket.aerodynamics.Warning;
import net.sf.openrocket.aerodynamics.WarningSet; import net.sf.openrocket.aerodynamics.WarningSet;
import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.motor.MotorInstanceConfiguration;
import net.sf.openrocket.rocketcomponent.Configuration; import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.simulation.FlightData; import net.sf.openrocket.simulation.FlightData;
import net.sf.openrocket.startup.Application; import net.sf.openrocket.startup.Application;
@ -47,7 +48,9 @@ public class RocketInfo implements FigureElement {
private double cg = 0, cp = 0; private double cg = 0, cp = 0;
private double length = 0, diameter = 0; private double length = 0, diameter = 0;
private double mass = 0; private double mass = 0;
private double aoa = Double.NaN, theta = Double.NaN, mach = Application.getPreferences().getDefaultMach(); private double aoa = Double.NaN;
private double theta = Double.NaN;
private double mach = Application.getPreferences().getDefaultMach();
private WarningSet warnings = null; private WarningSet warnings = null;
@ -151,7 +154,8 @@ public class RocketInfo implements FigureElement {
UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(diameter)); UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(diameter));
String massText; String massText;
if (configuration.hasMotors()) MotorInstanceConfiguration mic = new MotorInstanceConfiguration(configuration);
if (mic.hasMotors())
//// Mass with motors //// Mass with motors
massText = trans.get("RocketInfo.massText1") +" "; massText = trans.get("RocketInfo.massText1") +" ";
else else

View File

@ -16,6 +16,7 @@ import net.sf.openrocket.gui.scalefigure.RocketPanel;
import net.sf.openrocket.masscalc.MassCalculator; import net.sf.openrocket.masscalc.MassCalculator;
import net.sf.openrocket.masscalc.MassCalculator.MassCalcType; import net.sf.openrocket.masscalc.MassCalculator.MassCalcType;
import net.sf.openrocket.motor.Motor; import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.motor.MotorInstanceConfiguration;
import net.sf.openrocket.rocketcomponent.Configuration; import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.rocketcomponent.MotorMount; import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.Rocket;
@ -192,7 +193,9 @@ public class DesignReport {
canvas.showText("" + rocket.getStageCount()); canvas.showText("" + rocket.getStageCount());
if (configuration.hasMotors()) {
MotorInstanceConfiguration mic = new MotorInstanceConfiguration(configuration);
if (mic.hasMotors()){
if (configuration.getStageCount() > 1) { if (configuration.getStageCount() > 1) {
canvas.newlineShowText(MASS_WITH_MOTORS); canvas.newlineShowText(MASS_WITH_MOTORS);
} else { } else {
@ -341,7 +344,8 @@ public class DesignReport {
for (RocketComponent c : rocket) { for (RocketComponent c : rocket) {
if (c instanceof AxialStage) { if (c instanceof AxialStage) {
config.setToStage(stage); config.clearAllStages();
config.setOnlyStage(stage);
stage++; stage++;
stageMass = massCalc.getCG(config, MassCalcType.LAUNCH_MASS).weight; stageMass = massCalc.getCG(config, MassCalcType.LAUNCH_MASS).weight;
// Calculate total thrust-to-weight from only lowest stage motors // Calculate total thrust-to-weight from only lowest stage motors

View File

@ -23,6 +23,8 @@ import net.sf.openrocket.gui.figureelements.FigureElement;
import net.sf.openrocket.gui.util.ColorConversion; import net.sf.openrocket.gui.util.ColorConversion;
import net.sf.openrocket.gui.util.SwingPreferences; import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.motor.Motor; import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.motor.MotorInstance;
import net.sf.openrocket.motor.MotorInstanceConfiguration;
import net.sf.openrocket.rocketcomponent.ComponentAssembly; import net.sf.openrocket.rocketcomponent.ComponentAssembly;
import net.sf.openrocket.rocketcomponent.Configuration; import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.rocketcomponent.MotorMount; import net.sf.openrocket.rocketcomponent.MotorMount;
@ -339,13 +341,13 @@ public class RocketFigure extends AbstractScaleFigure {
RenderingHints.VALUE_STROKE_NORMALIZE); RenderingHints.VALUE_STROKE_NORMALIZE);
// Draw motors // Draw motors
String motorID = configuration.getFlightConfigurationID();
Color fillColor = ((SwingPreferences)Application.getPreferences()).getMotorFillColor(); Color fillColor = ((SwingPreferences)Application.getPreferences()).getMotorFillColor();
Color borderColor = ((SwingPreferences)Application.getPreferences()).getMotorBorderColor(); Color borderColor = ((SwingPreferences)Application.getPreferences()).getMotorBorderColor();
Iterator<MotorMount> iterator = configuration.motorIterator();
while (iterator.hasNext()) { MotorInstanceConfiguration mic = new MotorInstanceConfiguration(configuration);
MotorMount mount = iterator.next(); for( MotorInstance curInstance : configuration.getActiveMotors(mic)){
Motor motor = mount.getMotor(motorID); MotorMount mount = curInstance.getMount();
Motor motor = curInstance.getMotor();
double motorLength = motor.getLength(); double motorLength = motor.getLength();
double motorRadius = motor.getDiameter() / 2; double motorRadius = motor.getDiameter() / 2;

View File

@ -56,6 +56,7 @@ import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.masscalc.MassCalculator; import net.sf.openrocket.masscalc.MassCalculator;
import net.sf.openrocket.masscalc.MassCalculator.MassCalcType; import net.sf.openrocket.masscalc.MassCalculator.MassCalcType;
import net.sf.openrocket.motor.MotorInstanceConfiguration;
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent; import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
import net.sf.openrocket.rocketcomponent.ComponentChangeListener; import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
import net.sf.openrocket.rocketcomponent.Configuration; import net.sf.openrocket.rocketcomponent.Configuration;
@ -640,7 +641,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
length = maxX - minX; length = maxX - minX;
} }
for (RocketComponent c : configuration) { for (RocketComponent c : configuration.getActiveComponents()) {
if (c instanceof SymmetricComponent) { if (c instanceof SymmetricComponent) {
double d1 = ((SymmetricComponent) c).getForeRadius() * 2; double d1 = ((SymmetricComponent) c).getForeRadius() * 2;
double d2 = ((SymmetricComponent) c).getAftRadius() * 2; double d2 = ((SymmetricComponent) c).getAftRadius() * 2;
@ -692,8 +693,10 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
// Stop previous computation (if any) // Stop previous computation (if any)
stopBackgroundSimulation(); stopBackgroundSimulation();
MotorInstanceConfiguration mic = new MotorInstanceConfiguration( configuration);
// Check that configuration has motors // Check that configuration has motors
if (!configuration.hasMotors()) { if (!mic.hasMotors()){
extraText.setFlightData(FlightData.NaN_DATA); extraText.setFlightData(FlightData.NaN_DATA);
extraText.setCalculatingData(false); extraText.setCalculatingData(false);
return; return;

View File

@ -8,6 +8,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent; import java.awt.event.WindowEvent;
import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -30,6 +31,8 @@ import net.sf.openrocket.gui.dialogs.DetailDialog;
import net.sf.openrocket.gui.util.GUIUtil; import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.gui.util.SwingPreferences; import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.motor.MotorInstance;
import net.sf.openrocket.motor.MotorInstanceConfiguration;
import net.sf.openrocket.rocketcomponent.Configuration; import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.rocketcomponent.IgnitionConfiguration; import net.sf.openrocket.rocketcomponent.IgnitionConfiguration;
import net.sf.openrocket.rocketcomponent.MotorMount; import net.sf.openrocket.rocketcomponent.MotorMount;
@ -306,11 +309,13 @@ public class SimulationRunDialog extends JDialog {
// Calculate estimate of motor burn time // Calculate estimate of motor burn time
double launchBurn = 0; double launchBurn = 0;
double otherBurn = 0; double otherBurn = 0;
Configuration config = simulation.getConfiguration();
String id = simulation.getOptions().getMotorConfigurationID(); String id = simulation.getOptions().getMotorConfigurationID();
Iterator<MotorMount> iterator = config.motorIterator();
while (iterator.hasNext()) { Configuration config = simulation.getConfiguration();
MotorMount m = iterator.next(); MotorInstanceConfiguration mic = new MotorInstanceConfiguration(config);
Collection<MotorInstance> activeMotors = config.getActiveMotors(mic );
for( MotorInstance curInstance : activeMotors ){
MotorMount m = curInstance.getMount();
if (m.getIgnitionConfiguration().getDefault().getIgnitionEvent() == IgnitionConfiguration.IgnitionEvent.LAUNCH) if (m.getIgnitionConfiguration().getDefault().getIgnitionEvent() == IgnitionConfiguration.IgnitionEvent.LAUNCH)
launchBurn = MathUtil.max(launchBurn, m.getMotor(id).getBurnTimeEstimate()); launchBurn = MathUtil.max(launchBurn, m.getMotor(id).getBurnTimeEstimate());
else else