[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:
parent
85dff39fb9
commit
6c11fb2751
@ -74,11 +74,16 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
||||
new LinkedHashMap<RocketComponent, AerodynamicForces>();
|
||||
|
||||
// Add all components to the map
|
||||
for (RocketComponent c : configuration) {
|
||||
f = new AerodynamicForces();
|
||||
f.setComponent(c);
|
||||
for (RocketComponent component : configuration.getActiveComponents()) {
|
||||
|
||||
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)
|
||||
buildCalcMap(configuration);
|
||||
|
||||
for (RocketComponent component : configuration) {
|
||||
for (RocketComponent component : configuration.getActiveComponents()) {
|
||||
|
||||
// Skip non-aerodynamic components
|
||||
if (!component.isAerodynamic())
|
||||
@ -367,7 +372,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
||||
double[] roughnessLimited = new double[Finish.values().length];
|
||||
Arrays.fill(roughnessLimited, Double.NaN);
|
||||
|
||||
for (RocketComponent c : configuration) {
|
||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
||||
|
||||
// Consider only SymmetricComponents and FinSets:
|
||||
if (!(c instanceof SymmetricComponent) &&
|
||||
@ -469,7 +474,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
||||
base = calculateBaseCD(conditions.getMach());
|
||||
|
||||
total = 0;
|
||||
for (RocketComponent c : configuration) {
|
||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
||||
if (!c.isAerodynamic())
|
||||
continue;
|
||||
|
||||
@ -517,7 +522,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
||||
base = calculateBaseCD(conditions.getMach());
|
||||
total = 0;
|
||||
|
||||
for (RocketComponent c : configuration) {
|
||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
||||
if (!(c instanceof SymmetricComponent))
|
||||
continue;
|
||||
|
||||
@ -646,7 +651,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
||||
cacheLength = 0;
|
||||
cacheDiameter = 0;
|
||||
|
||||
for (RocketComponent c : configuration) {
|
||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
||||
if (c instanceof SymmetricComponent) {
|
||||
SymmetricComponent s = (SymmetricComponent) c;
|
||||
area += s.getComponentPlanformArea();
|
||||
@ -665,7 +670,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
||||
|
||||
// Fins
|
||||
// TODO: LOW: This could be optimized a lot...
|
||||
for (RocketComponent c : configuration) {
|
||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
||||
if (c instanceof FinSet) {
|
||||
FinSet f = (FinSet) c;
|
||||
mul += 0.6 * Math.min(f.getFinCount(), 4) * f.getFinArea() *
|
||||
|
@ -2,7 +2,6 @@ package net.sf.openrocket.document;
|
||||
|
||||
import java.util.EventListener;
|
||||
import java.util.EventObject;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
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.formatting.RocketDescriptor;
|
||||
import net.sf.openrocket.masscalc.MassCalculator;
|
||||
import net.sf.openrocket.motor.Motor;
|
||||
import net.sf.openrocket.motor.MotorInstanceConfiguration;
|
||||
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.RocketComponent;
|
||||
import net.sf.openrocket.simulation.BasicEventSimulationEngine;
|
||||
import net.sf.openrocket.simulation.DefaultSimulationOptionFactory;
|
||||
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.
|
||||
Configuration c = new Configuration(this.getRocket());
|
||||
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)
|
||||
if (0 == motors.getMotorCount()) {
|
||||
status = Status.CANT_RUN;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -4,16 +4,13 @@ import static net.sf.openrocket.util.MathUtil.pow2;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.openrocket.motor.Motor;
|
||||
import net.sf.openrocket.motor.MotorId;
|
||||
import net.sf.openrocket.motor.MotorInstance;
|
||||
import net.sf.openrocket.motor.MotorInstanceConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.AxialStage;
|
||||
import net.sf.openrocket.rocketcomponent.Configuration;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.simulation.MassData;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
@ -80,35 +77,21 @@ public class MassCalculator implements Monitorable {
|
||||
checkCache(configuration);
|
||||
calculateStageCache(configuration);
|
||||
|
||||
Coordinate totalCG = null;
|
||||
Coordinate dryCG = null;
|
||||
|
||||
// Stage contribution
|
||||
for (int stage : configuration.getActiveStages()) {
|
||||
totalCG = cgCache[stage].average(totalCG);
|
||||
for (AxialStage stage : configuration.getActiveStages()) {
|
||||
int stageNumber = stage.getStageNumber();
|
||||
dryCG = cgCache[stageNumber].average(dryCG);
|
||||
}
|
||||
|
||||
if (totalCG == null)
|
||||
totalCG = Coordinate.NUL;
|
||||
if (dryCG == null)
|
||||
dryCG = Coordinate.NUL;
|
||||
|
||||
// Add motor CGs
|
||||
String motorId = configuration.getFlightConfigurationID();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
MotorInstanceConfiguration motorConfig = new MotorInstanceConfiguration(configuration);
|
||||
Coordinate motorCG = getMotorCG(configuration, motorConfig, MassCalcType.LAUNCH_MASS);
|
||||
|
||||
Coordinate totalCG = dryCG.average(motorCG);
|
||||
return totalCG;
|
||||
}
|
||||
|
||||
@ -123,23 +106,27 @@ public class MassCalculator implements Monitorable {
|
||||
checkCache(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
|
||||
if (motors != null) {
|
||||
for (MotorId id : motors.getMotorIDs()) {
|
||||
int stage = ((RocketComponent) motors.getMotorMount(id)).getStageNumber();
|
||||
if (configuration.isStageActive(stage)) {
|
||||
|
||||
MotorInstance motor = motors.getMotorInstance(id);
|
||||
Coordinate position = motors.getMotorPosition(id);
|
||||
Coordinate cg = motor.getCG().add(position);
|
||||
totalCG = totalCG.average(cg);
|
||||
|
||||
for (MotorInstance inst : config.getActiveMotors(motors)) {
|
||||
int stage = ((RocketComponent) inst.getMount()).getStageNumber();
|
||||
if (config.isStageActive(stage)) {
|
||||
Coordinate position = inst.getPosition();
|
||||
Coordinate curCG = type.getCG(inst.getMotor()).add(position);
|
||||
motorCG = motorCG.average(curCG);
|
||||
}
|
||||
}
|
||||
}
|
||||
return totalCG;
|
||||
return motorCG;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -158,21 +145,21 @@ public class MassCalculator implements Monitorable {
|
||||
double totalInertia = 0;
|
||||
|
||||
// Stages
|
||||
for (int stage : configuration.getActiveStages()) {
|
||||
Coordinate stageCG = cgCache[stage];
|
||||
for (AxialStage stage : configuration.getActiveStages()) {
|
||||
int stageNumber = stage.getStageNumber();
|
||||
Coordinate stageCG = cgCache[stageNumber];
|
||||
|
||||
totalInertia += (longitudinalInertiaCache[stage] +
|
||||
totalInertia += (longitudinalInertiaCache[stageNumber] +
|
||||
stageCG.weight * MathUtil.pow2(stageCG.x - totalCG.x));
|
||||
}
|
||||
|
||||
|
||||
// Motors
|
||||
if (motors != null) {
|
||||
for (MotorId id : motors.getMotorIDs()) {
|
||||
int stage = ((RocketComponent) motors.getMotorMount(id)).getStageNumber();
|
||||
for (MotorInstance motor : configuration.getActiveMotors(motors)) {
|
||||
int stage = ((RocketComponent) motor.getMount()).getStageNumber();
|
||||
if (configuration.isStageActive(stage)) {
|
||||
MotorInstance motor = motors.getMotorInstance(id);
|
||||
Coordinate position = motors.getMotorPosition(id);
|
||||
Coordinate position = motor.getPosition();
|
||||
Coordinate cg = motor.getCG().add(position);
|
||||
|
||||
double inertia = motor.getLongitudinalInertia();
|
||||
@ -200,10 +187,11 @@ public class MassCalculator implements Monitorable {
|
||||
double totalInertia = 0;
|
||||
|
||||
// Stages
|
||||
for (int stage : configuration.getActiveStages()) {
|
||||
Coordinate stageCG = cgCache[stage];
|
||||
for (AxialStage stage : configuration.getActiveStages()) {
|
||||
int stageNumber = stage.getStageNumber();
|
||||
Coordinate stageCG = cgCache[stageNumber];
|
||||
|
||||
totalInertia += (rotationalInertiaCache[stage] +
|
||||
totalInertia += (rotationalInertiaCache[stageNumber] +
|
||||
stageCG.weight * (MathUtil.pow2(stageCG.y - totalCG.y) +
|
||||
MathUtil.pow2(stageCG.z - totalCG.z)));
|
||||
}
|
||||
@ -211,11 +199,10 @@ public class MassCalculator implements Monitorable {
|
||||
|
||||
// Motors
|
||||
if (motors != null) {
|
||||
for (MotorId id : motors.getMotorIDs()) {
|
||||
int stage = ((RocketComponent) motors.getMotorMount(id)).getStageNumber();
|
||||
for (MotorInstance motor : configuration.getActiveMotors(motors)) {
|
||||
int stage = ((RocketComponent) motor.getMount()).getStageNumber();
|
||||
if (configuration.isStageActive(stage)) {
|
||||
MotorInstance motor = motors.getMotorInstance(id);
|
||||
Coordinate position = motors.getMotorPosition(id);
|
||||
Coordinate position = motor.getPosition();
|
||||
Coordinate cg = motor.getCG().add(position);
|
||||
|
||||
double inertia = motor.getRotationalInertia();
|
||||
@ -241,9 +228,8 @@ public class MassCalculator implements Monitorable {
|
||||
|
||||
// add up the masses of all motors in the rocket
|
||||
if (motors != null) {
|
||||
for (MotorId id : motors.getMotorIDs()) {
|
||||
MotorInstance motor = motors.getMotorInstance(id);
|
||||
mass = mass + motor.getCG().weight - motor.getParentMotor().getEmptyCG().weight;
|
||||
for (MotorInstance motor : configuration.getActiveMotors(motors)) {
|
||||
mass = mass + motor.getCG().weight - motor.getMotor().getEmptyCG().weight;
|
||||
}
|
||||
}
|
||||
return mass;
|
||||
@ -266,13 +252,13 @@ public class MassCalculator implements Monitorable {
|
||||
|
||||
Map<RocketComponent, Coordinate> map = new HashMap<RocketComponent, Coordinate>();
|
||||
|
||||
for (RocketComponent c : configuration) {
|
||||
Coordinate[] cgs = c.toAbsolute(c.getCG());
|
||||
for (RocketComponent comp : configuration.getActiveComponents()) {
|
||||
Coordinate[] cgs = comp.toAbsolute(comp.getCG());
|
||||
Coordinate totalCG = Coordinate.NUL;
|
||||
for (Coordinate cg : cgs) {
|
||||
totalCG = totalCG.average(cg);
|
||||
}
|
||||
map.put(c, totalCG);
|
||||
map.put(comp, totalCG);
|
||||
}
|
||||
|
||||
map.put(configuration.getRocket(), getCG(configuration, type));
|
||||
@ -284,7 +270,8 @@ public class MassCalculator implements Monitorable {
|
||||
|
||||
private void calculateStageCache(Configuration config) {
|
||||
if (cgCache == null) {
|
||||
ArrayList<AxialStage> stageList = config.getRocket().getStageList();
|
||||
ArrayList<AxialStage> stageList = new ArrayList<AxialStage>();
|
||||
stageList.addAll(config.getRocket().getStageList());
|
||||
int stageCount = stageList.size();
|
||||
|
||||
cgCache = new Coordinate[stageCount];
|
||||
|
@ -8,10 +8,18 @@ package net.sf.openrocket.motor;
|
||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||
*/
|
||||
public final class MotorId {
|
||||
|
||||
|
||||
private final String componentId;
|
||||
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.
|
||||
@ -20,7 +28,6 @@ public final class MotorId {
|
||||
* @param number a positive motor doun5 number
|
||||
*/
|
||||
public MotorId(String componentId, int number) {
|
||||
super();
|
||||
|
||||
if (componentId == null) {
|
||||
throw new IllegalArgumentException("Component ID was null");
|
||||
@ -52,7 +59,7 @@ public final class MotorId {
|
||||
if (!(o instanceof MotorId))
|
||||
return false;
|
||||
|
||||
MotorId other = (MotorId)o;
|
||||
MotorId other = (MotorId) o;
|
||||
// Comparison with == ok since string is intern()'ed
|
||||
return this.componentId == other.componentId && this.number == other.number;
|
||||
}
|
||||
|
@ -1,11 +1,124 @@
|
||||
package net.sf.openrocket.motor;
|
||||
|
||||
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.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.
|
||||
*
|
||||
@ -13,51 +126,49 @@ public interface MotorInstance extends Cloneable, Monitorable {
|
||||
* @param acceleration the average acceleration 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 current step time.
|
||||
*/
|
||||
public double getTime();
|
||||
public abstract double getTime();
|
||||
|
||||
/**
|
||||
* Return the average thrust during the last step.
|
||||
*/
|
||||
public double getThrust();
|
||||
public abstract double getThrust();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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.
|
||||
* 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
|
||||
* 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
|
||||
* identical to this instance and can be used independently from this one.
|
||||
*/
|
||||
public MotorInstance clone();
|
||||
|
||||
|
||||
public Motor getParentMotor();
|
||||
@Override
|
||||
public abstract MotorInstance clone();
|
||||
|
||||
}
|
||||
|
@ -1,13 +1,16 @@
|
||||
package net.sf.openrocket.motor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
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.IgnitionEvent;
|
||||
import net.sf.openrocket.rocketcomponent.MotorConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.Monitorable;
|
||||
|
||||
@ -17,21 +20,55 @@ import net.sf.openrocket.util.Monitorable;
|
||||
*
|
||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||
*/
|
||||
public final class MotorInstanceConfiguration implements Monitorable, Cloneable {
|
||||
|
||||
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>();
|
||||
|
||||
public class MotorInstanceConfiguration implements Cloneable, Iterable<MotorInstance>, Monitorable {
|
||||
protected final HashMap<MotorId, MotorInstance> motors = new HashMap<MotorId, MotorInstance>();
|
||||
|
||||
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
|
||||
@ -45,89 +82,70 @@ public final class MotorInstanceConfiguration implements Monitorable, Cloneable
|
||||
* @param position the position of the motor in absolute coordinates.
|
||||
* @throws IllegalArgumentException if a motor with the specified ID already exists.
|
||||
*/
|
||||
public void addMotor(MotorId id, MotorInstance motor, double ejectionDelay, MotorMount mount,
|
||||
IgnitionEvent ignitionEvent, double ignitionDelay, Coordinate position) {
|
||||
if (this.ids.contains(id)) {
|
||||
// public void addMotor(MotorId _id, Motor _motor, double _ejectionDelay, MotorMount _mount,
|
||||
// IgnitionEvent _ignitionEvent, double _ignitionDelay, Coordinate _position) {
|
||||
//
|
||||
// MotorInstance instanceToAdd = new MotorInstance(_id, _motor, _mount, _ejectionDelay,
|
||||
// _ignitionEvent, _ignitionDelay, _position);
|
||||
//
|
||||
//
|
||||
// // this.ids.add(id);
|
||||
// // this.motors.add(motor);
|
||||
// // this.ejectionDelays.add(ejectionDelay);
|
||||
// // this.mounts.add(mount);
|
||||
// // this.ignitionEvents.add(ignitionEvent);
|
||||
// // this.ignitionDelays.add(ignitionDelay);
|
||||
// // this.positions.add(position);
|
||||
// // this.ignitionTimes.add(Double.POSITIVE_INFINITY);
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* Add a motor instance to this configuration.
|
||||
*
|
||||
* @param motor the motor instance.
|
||||
* @throws IllegalArgumentException if a motor with the specified ID already exists.
|
||||
*/
|
||||
public void addMotor(MotorInstance motor) {
|
||||
MotorId id = motor.getID();
|
||||
if (this.motors.containsKey(id)) {
|
||||
throw new IllegalArgumentException("MotorInstanceConfiguration already " +
|
||||
"contains a motor with id " + id);
|
||||
}
|
||||
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);
|
||||
this.motors.put(id, motor);
|
||||
|
||||
modID++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of all motor IDs in this configuration (not only ones in active stages).
|
||||
*/
|
||||
public List<MotorId> getMotorIDs() {
|
||||
return unmodifiableIds;
|
||||
public Collection<MotorInstance> getAllMotors() {
|
||||
return motors.values();
|
||||
}
|
||||
|
||||
public int getMotorCount() {
|
||||
return motors.size();
|
||||
}
|
||||
|
||||
public Set<MotorId> getMotorIDs() {
|
||||
return this.motors.keySet();
|
||||
}
|
||||
|
||||
public MotorInstance getMotorInstance(MotorId id) {
|
||||
return motors.get(indexOf(id));
|
||||
return motors.get(id);
|
||||
}
|
||||
|
||||
public double getEjectionDelay(MotorId id) {
|
||||
return ejectionDelays.get(indexOf(id));
|
||||
public boolean hasMotors() {
|
||||
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.
|
||||
* @param time the "global" time
|
||||
*/
|
||||
public void step(double time, double acceleration, AtmosphericConditions cond) {
|
||||
for (int i = 0; i < motors.size(); i++) {
|
||||
double t = time - ignitionTimes.get(i);
|
||||
for (MotorInstance inst : motors.values()) {
|
||||
double t = time - inst.getIgnitionTime();
|
||||
if (t >= 0) {
|
||||
motors.get(i).step(t, acceleration, cond);
|
||||
inst.step(t, acceleration, cond);
|
||||
}
|
||||
}
|
||||
modID++;
|
||||
@ -136,7 +154,7 @@ public final class MotorInstanceConfiguration implements Monitorable, Cloneable
|
||||
@Override
|
||||
public int getModID() {
|
||||
int id = modID;
|
||||
for (MotorInstance motor : motors) {
|
||||
for (MotorInstance motor : motors.values()) {
|
||||
id += motor.getModID();
|
||||
}
|
||||
return id;
|
||||
@ -149,18 +167,17 @@ public final class MotorInstanceConfiguration implements Monitorable, Cloneable
|
||||
@Override
|
||||
public MotorInstanceConfiguration clone() {
|
||||
MotorInstanceConfiguration clone = new MotorInstanceConfiguration();
|
||||
clone.ids.addAll(this.ids);
|
||||
clone.mounts.addAll(this.mounts);
|
||||
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());
|
||||
for (MotorInstance motor : this.motors.values()) {
|
||||
clone.motors.put(motor.id, motor.clone());
|
||||
}
|
||||
clone.modID = this.modID;
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<MotorInstance> iterator() {
|
||||
return this.motors.values().iterator();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -415,9 +415,9 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
|
||||
|
||||
|
||||
//////// Motor instance implementation ////////
|
||||
private class ThrustCurveMotorInstance implements MotorInstance {
|
||||
private class ThrustCurveMotorInstance extends MotorInstance {
|
||||
|
||||
private int position;
|
||||
private int timeIndex;
|
||||
|
||||
// Previous time step value
|
||||
private double prevTime;
|
||||
@ -434,13 +434,12 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
|
||||
|
||||
private final double unitRotationalInertia;
|
||||
private final double unitLongitudinalInertia;
|
||||
private final Motor parentMotor;
|
||||
|
||||
private int modID = 0;
|
||||
|
||||
public ThrustCurveMotorInstance() {
|
||||
log.debug("ThrustCurveMotor: Creating motor instance of " + ThrustCurveMotor.this);
|
||||
position = 0;
|
||||
timeIndex = 0;
|
||||
prevTime = 0;
|
||||
instThrust = 0;
|
||||
stepThrust = 0;
|
||||
@ -451,11 +450,6 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
|
||||
parentMotor = ThrustCurveMotor.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Motor getParentMotor() {
|
||||
return parentMotor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTime() {
|
||||
return prevTime;
|
||||
@ -500,7 +494,7 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
|
||||
|
||||
modID++;
|
||||
|
||||
if (position >= time.length - 1) {
|
||||
if (timeIndex >= time.length - 1) {
|
||||
// Thrust has ended
|
||||
prevTime = nextTime;
|
||||
stepThrust = 0;
|
||||
@ -511,33 +505,33 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
|
||||
|
||||
|
||||
// Compute average & instantaneous thrust
|
||||
if (nextTime < time[position + 1]) {
|
||||
if (nextTime < time[timeIndex + 1]) {
|
||||
|
||||
// Time step between time points
|
||||
double nextF = MathUtil.map(nextTime, time[position], time[position + 1],
|
||||
thrust[position], thrust[position + 1]);
|
||||
double nextF = MathUtil.map(nextTime, time[timeIndex], time[timeIndex + 1],
|
||||
thrust[timeIndex], thrust[timeIndex + 1]);
|
||||
stepThrust = (instThrust + nextF) / 2;
|
||||
instThrust = nextF;
|
||||
|
||||
} else {
|
||||
|
||||
// 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
|
||||
position++;
|
||||
while ((position < time.length - 1) && (nextTime >= time[position + 1])) {
|
||||
stepThrust += (thrust[position] + thrust[position + 1]) / 2 *
|
||||
(time[position + 1] - time[position]);
|
||||
position++;
|
||||
timeIndex++;
|
||||
while ((timeIndex < time.length - 1) && (nextTime >= time[timeIndex + 1])) {
|
||||
stepThrust += (thrust[timeIndex] + thrust[timeIndex + 1]) / 2 *
|
||||
(time[timeIndex + 1] - time[timeIndex]);
|
||||
timeIndex++;
|
||||
}
|
||||
|
||||
// End step
|
||||
if (position < time.length - 1) {
|
||||
instThrust = MathUtil.map(nextTime, time[position], time[position + 1],
|
||||
thrust[position], thrust[position + 1]);
|
||||
stepThrust += (thrust[position] + instThrust) / 2 *
|
||||
(nextTime - time[position]);
|
||||
if (timeIndex < time.length - 1) {
|
||||
instThrust = MathUtil.map(nextTime, time[timeIndex], time[timeIndex + 1],
|
||||
thrust[timeIndex], thrust[timeIndex + 1]);
|
||||
stepThrust += (thrust[timeIndex] + instThrust) / 2 *
|
||||
(nextTime - time[timeIndex]);
|
||||
} else {
|
||||
// Thrust ended during this step
|
||||
instThrust = 0;
|
||||
@ -549,9 +543,9 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
|
||||
|
||||
// Compute average and instantaneous CG (simple average between points)
|
||||
Coordinate nextCG;
|
||||
if (position < time.length - 1) {
|
||||
nextCG = MathUtil.map(nextTime, time[position], time[position + 1],
|
||||
cg[position], cg[position + 1]);
|
||||
if (timeIndex < time.length - 1) {
|
||||
nextCG = MathUtil.map(nextTime, time[timeIndex], time[timeIndex + 1],
|
||||
cg[timeIndex], cg[timeIndex + 1]);
|
||||
} else {
|
||||
nextCG = cg[cg.length - 1];
|
||||
}
|
||||
@ -564,11 +558,12 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
|
||||
|
||||
@Override
|
||||
public MotorInstance clone() {
|
||||
try {
|
||||
return (MotorInstance) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new BugException("CloneNotSupportedException", e);
|
||||
}
|
||||
throw new BugException("CloneNotSupportedException");
|
||||
//try {
|
||||
// return (MotorInstance) super.clone();
|
||||
//} catch (CloneNotSupportedException e) {
|
||||
// throw new BugException("CloneNotSupportedException", e);
|
||||
//}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -91,7 +91,7 @@ public class StabilityDomain implements SimulationDomain {
|
||||
absolute = cpx - cgx;
|
||||
|
||||
double diameter = 0;
|
||||
for (RocketComponent c : configuration) {
|
||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
||||
if (c instanceof SymmetricComponent) {
|
||||
double d1 = ((SymmetricComponent) c).getForeRadius() * 2;
|
||||
double d2 = ((SymmetricComponent) c).getAftRadius() * 2;
|
||||
|
@ -84,7 +84,7 @@ public class StabilityParameter implements OptimizableParameter {
|
||||
|
||||
if (!absolute) {
|
||||
double diameter = 0;
|
||||
for (RocketComponent c : configuration) {
|
||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
||||
if (c instanceof SymmetricComponent) {
|
||||
double d1 = ((SymmetricComponent) c).getForeRadius() * 2;
|
||||
double d2 = ((SymmetricComponent) c).getAftRadius() * 2;
|
||||
|
@ -15,13 +15,11 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
|
||||
private FlightConfigurationImpl<StageSeparationConfiguration> separationConfigurations;
|
||||
|
||||
protected int stageNumber;
|
||||
private static int stageCount;
|
||||
|
||||
public AxialStage() {
|
||||
this.separationConfigurations = new FlightConfigurationImpl<StageSeparationConfiguration>(this, ComponentChangeEvent.EVENT_CHANGE, new StageSeparationConfiguration());
|
||||
this.relativePosition = Position.AFTER;
|
||||
stageNumber = AxialStage.stageCount;
|
||||
AxialStage.stageCount++;
|
||||
this.stageNumber = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -35,10 +33,6 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
|
||||
return trans.get("Stage.Stage");
|
||||
}
|
||||
|
||||
public static int getStageCount() {
|
||||
return AxialStage.stageCount;
|
||||
}
|
||||
|
||||
public FlightConfiguration<StageSeparationConfiguration> getStageSeparationConfiguration() {
|
||||
return separationConfigurations;
|
||||
}
|
||||
@ -107,16 +101,10 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
|
||||
if (null == this.parent) {
|
||||
return -1;
|
||||
} 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
|
||||
@ -124,6 +112,10 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
|
||||
return this.stageNumber;
|
||||
}
|
||||
|
||||
public void setStageNumber(final int newStageNumber) {
|
||||
this.stageNumber = newStageNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coordinate[] shiftCoordinates(Coordinate[] c) {
|
||||
checkState();
|
||||
|
@ -130,32 +130,6 @@ public class BoosterSet extends AxialStage implements FlightConfigurableComponen
|
||||
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
|
||||
public Coordinate[] shiftCoordinates(Coordinate[] c) {
|
||||
checkState();
|
||||
|
@ -1,13 +1,13 @@
|
||||
package net.sf.openrocket.rocketcomponent;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.Collection;
|
||||
import java.util.EventListener;
|
||||
import java.util.EventObject;
|
||||
import java.util.Iterator;
|
||||
import java.util.HashMap;
|
||||
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.BugException;
|
||||
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.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>
|
||||
*/
|
||||
public class Configuration implements Cloneable, ChangeSource, ComponentChangeListener,
|
||||
Iterable<RocketComponent>, Monitorable {
|
||||
|
||||
private Rocket rocket;
|
||||
private BitSet stagesActive = new BitSet();
|
||||
|
||||
private String flightConfigurationId = null;
|
||||
public class Configuration implements Cloneable, ChangeSource, ComponentChangeListener, Monitorable {
|
||||
private static final Logger log = LoggerFactory.getLogger(Configuration.class);
|
||||
|
||||
protected Rocket rocket;
|
||||
protected String flightConfigurationId = null;
|
||||
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 */
|
||||
protected HashMap<Integer, StageFlags> stageMap = new HashMap<Integer, StageFlags>();
|
||||
|
||||
private int boundsModID = -1;
|
||||
private ArrayList<Coordinate> cachedBounds = new ArrayList<Coordinate>();
|
||||
private double cachedLength = -1;
|
||||
@ -43,7 +55,6 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
|
||||
private int refLengthModID = -1;
|
||||
private double cachedRefLength = -1;
|
||||
|
||||
|
||||
private int modID = 0;
|
||||
|
||||
|
||||
@ -55,98 +66,156 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
|
||||
*/
|
||||
public Configuration(Rocket rocket) {
|
||||
this.rocket = rocket;
|
||||
setAllStages();
|
||||
updateStageMap();
|
||||
rocket.addComponentChangeListener(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Rocket getRocket() {
|
||||
return rocket;
|
||||
}
|
||||
|
||||
|
||||
public void clearAllStages() {
|
||||
this.setAllStages(false);
|
||||
}
|
||||
|
||||
public void setAllStages() {
|
||||
stagesActive.clear();
|
||||
stagesActive.set(0, AxialStage.getStageCount());
|
||||
this.setAllStages(true);
|
||||
}
|
||||
|
||||
public void setAllStages(final boolean _value) {
|
||||
for (StageFlags cur : stageMap.values()) {
|
||||
cur.active = _value;
|
||||
}
|
||||
fireChangeEvent();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set all stages up to and including the given stage number. For example,
|
||||
* <code>setToStage(0)</code> will set only the first stage active.
|
||||
/**
|
||||
* This method flags a stage inactive. Other stages are unaffected.
|
||||
*
|
||||
* @param stage the stage number.
|
||||
* @param stageNumber stage number to inactivate
|
||||
*/
|
||||
public void setToStage(int stage) {
|
||||
stagesActive.clear();
|
||||
stagesActive.set(0, stage + 1, true);
|
||||
// stages.set(stage+1, rocket.getStageCount(), false);
|
||||
fireChangeEvent();
|
||||
public void clearOnlyStage(final int stageNumber) {
|
||||
setStage(stageNumber, false);
|
||||
}
|
||||
|
||||
public void setOnlyStage(int stage) {
|
||||
stagesActive.clear();
|
||||
stagesActive.set(stage, stage + 1, true);
|
||||
fireChangeEvent();
|
||||
/**
|
||||
* 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 up-most stage of the rocket is in this configuration.
|
||||
*
|
||||
* @return <code>true</code> if the first stage is active in this configuration.
|
||||
* Check whether the stage is active.
|
||||
*/
|
||||
public boolean isHead() {
|
||||
return isStageActive(0);
|
||||
public boolean isStageActive(final AxialStage stage) {
|
||||
return this.isStageActive(stage.getStageNumber());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the stage specified by the index is active.
|
||||
*/
|
||||
public boolean isStageActive(int stage) {
|
||||
if (stage >= AxialStage.getStageCount())
|
||||
public boolean isStageActive(int stageNumber) {
|
||||
if (stageNumber >= this.rocket.getStageCount()) {
|
||||
return false;
|
||||
return stagesActive.get(stage);
|
||||
}
|
||||
|
||||
public int getStageCount() {
|
||||
return AxialStage.getStageCount();
|
||||
}
|
||||
|
||||
public int getActiveStageCount() {
|
||||
int count = 0;
|
||||
int s = AxialStage.getStageCount();
|
||||
|
||||
for (int i = 0; i < s; i++) {
|
||||
if (stagesActive.get(i))
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
return stageMap.get(stageNumber).active;
|
||||
}
|
||||
|
||||
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);
|
||||
public List<RocketComponent> getActiveComponents() {
|
||||
ArrayList<RocketComponent> toReturn = new ArrayList<RocketComponent>();
|
||||
for (StageFlags curFlags : this.stageMap.values()) {
|
||||
if (curFlags.active) {
|
||||
toReturn.add(curFlags.stage);
|
||||
}
|
||||
}
|
||||
|
||||
ret = new int[active.size()];
|
||||
for (int i = 0; i < ret.length; i++) {
|
||||
ret[i] = active.get(i);
|
||||
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 ret;
|
||||
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() {
|
||||
int activeCount = 0;
|
||||
for (StageFlags cur : this.stageMap.values()) {
|
||||
if (cur.active) {
|
||||
activeCount++;
|
||||
}
|
||||
}
|
||||
return activeCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
public void componentChanged(ComponentChangeEvent e) {
|
||||
@ -232,26 +331,6 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
|
||||
|
||||
/////////////// 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.
|
||||
*/
|
||||
@ -272,7 +351,7 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
|
||||
cachedBounds.clear();
|
||||
|
||||
double minX = Double.POSITIVE_INFINITY, maxX = Double.NEGATIVE_INFINITY;
|
||||
for (RocketComponent component : this) {
|
||||
for (RocketComponent component : this.getActiveComponents()) {
|
||||
for (Coordinate coord : component.getComponentBounds()) {
|
||||
cachedBounds.add(coord);
|
||||
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
|
||||
* listeners are listening on the cloned object. The rocket instance remains the same.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Configuration clone() {
|
||||
try {
|
||||
Configuration config = (Configuration) super.clone();
|
||||
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.boundsModID = -1;
|
||||
config.refLengthModID = -1;
|
||||
@ -375,51 +414,5 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,9 +8,9 @@ public enum ReferenceType {
|
||||
NOSECONE {
|
||||
@Override
|
||||
public double getReferenceLength(Configuration config) {
|
||||
for (RocketComponent c: config) {
|
||||
for (RocketComponent c : config.getActiveComponents()) {
|
||||
if (c instanceof SymmetricComponent) {
|
||||
SymmetricComponent s = (SymmetricComponent)c;
|
||||
SymmetricComponent s = (SymmetricComponent) c;
|
||||
if (s.getForeRadius() >= 0.0005)
|
||||
return s.getForeRadius() * 2;
|
||||
if (s.getAftRadius() >= 0.0005)
|
||||
@ -25,9 +25,9 @@ public enum ReferenceType {
|
||||
@Override
|
||||
public double getReferenceLength(Configuration config) {
|
||||
double r = 0;
|
||||
for (RocketComponent c: config) {
|
||||
for (RocketComponent c : config.getActiveComponents()) {
|
||||
if (c instanceof SymmetricComponent) {
|
||||
SymmetricComponent s = (SymmetricComponent)c;
|
||||
SymmetricComponent s = (SymmetricComponent) c;
|
||||
r = Math.max(r, s.getForeRadius());
|
||||
r = Math.max(r, s.getAftRadius());
|
||||
}
|
||||
@ -37,8 +37,8 @@ public enum ReferenceType {
|
||||
r = Rocket.DEFAULT_REFERENCE_LENGTH;
|
||||
return r;
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
CUSTOM {
|
||||
@Override
|
||||
public double getReferenceLength(Configuration config) {
|
||||
|
@ -80,7 +80,7 @@ public class Rocket extends RocketComponent {
|
||||
// Does the rocket have a perfect finish (a notable amount of laminar flow)
|
||||
private boolean perfectFinish = false;
|
||||
|
||||
|
||||
private final HashMap<Integer, AxialStage> stageMap = new HashMap<Integer, AxialStage>();
|
||||
|
||||
///////////// Constructor /////////////
|
||||
|
||||
@ -93,7 +93,6 @@ public class Rocket extends RocketComponent {
|
||||
functionalModID = modID;
|
||||
defaultConfiguration = new Configuration(this);
|
||||
|
||||
AxialStage.resetStageCount();
|
||||
}
|
||||
|
||||
|
||||
@ -130,7 +129,7 @@ public class Rocket extends RocketComponent {
|
||||
*/
|
||||
public int getStageCount() {
|
||||
checkState();
|
||||
return AxialStage.getStageCount();
|
||||
return this.stageMap.size();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -195,29 +194,34 @@ public class Rocket extends RocketComponent {
|
||||
return functionalModID;
|
||||
}
|
||||
|
||||
public ArrayList<AxialStage> getStageList() {
|
||||
ArrayList<AxialStage> toReturn = new ArrayList<AxialStage>();
|
||||
|
||||
toReturn = Rocket.getStages(toReturn, this);
|
||||
|
||||
return toReturn;
|
||||
public Collection<AxialStage> getStageList() {
|
||||
return this.stageMap.values();
|
||||
}
|
||||
|
||||
private static ArrayList<AxialStage> getStages(ArrayList<AxialStage> accumulator, final RocketComponent parent) {
|
||||
if ((null == accumulator) || (null == parent)) {
|
||||
return new ArrayList<AxialStage>();
|
||||
private int getNewStageNumber() {
|
||||
int guess = 0;
|
||||
while (stageMap.containsKey(guess)) {
|
||||
guess++;
|
||||
}
|
||||
|
||||
for (RocketComponent curChild : parent.getChildren()) {
|
||||
if (curChild instanceof AxialStage) {
|
||||
AxialStage curStage = (AxialStage) curChild;
|
||||
accumulator.add(curStage);
|
||||
}
|
||||
getStages(accumulator, curChild);
|
||||
}
|
||||
return accumulator;
|
||||
return guess;
|
||||
}
|
||||
|
||||
public void trackStage(final AxialStage newStage) {
|
||||
int stageNumber = newStage.getStageNumber();
|
||||
AxialStage value = stageMap.get(stageNumber);
|
||||
|
||||
if (newStage.equals(value)) {
|
||||
// stage is already added. skip.
|
||||
} else {
|
||||
stageNumber = getNewStageNumber();
|
||||
newStage.setStageNumber(stageNumber);
|
||||
this.stageMap.put(stageNumber, newStage);
|
||||
}
|
||||
}
|
||||
|
||||
public void forgetStage(final AxialStage oldStage) {
|
||||
this.stageMap.remove(oldStage.getStageNumber());
|
||||
}
|
||||
|
||||
public ReferenceType getReferenceType() {
|
||||
checkState();
|
||||
|
@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
public abstract class RocketComponent implements ChangeSource, Cloneable, Iterable<RocketComponent> {
|
||||
@SuppressWarnings("unused")
|
||||
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)
|
||||
@ -985,8 +986,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
* it should override this with a public method that simply calls this
|
||||
* 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.
|
||||
*/
|
||||
public void setPositionValue(double value) {
|
||||
@ -1346,6 +1346,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
children.add(index, component);
|
||||
component.parent = this;
|
||||
|
||||
if (component instanceof AxialStage) {
|
||||
AxialStage nStage = (AxialStage) component;
|
||||
this.getRocket().trackStage(nStage);
|
||||
}
|
||||
|
||||
this.checkComponentStructure();
|
||||
component.checkComponentStructure();
|
||||
|
||||
@ -1363,6 +1368,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
RocketComponent component = children.remove(n);
|
||||
component.parent = null;
|
||||
|
||||
if (component instanceof AxialStage) {
|
||||
AxialStage nStage = (AxialStage) component;
|
||||
this.getRocket().forgetStage(nStage);
|
||||
}
|
||||
|
||||
this.checkComponentStructure();
|
||||
component.checkComponentStructure();
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
package net.sf.openrocket.simulation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.sf.openrocket.masscalc.MassCalculator;
|
||||
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
|
||||
import net.sf.openrocket.motor.MotorId;
|
||||
import net.sf.openrocket.motor.MotorInstance;
|
||||
import net.sf.openrocket.motor.MotorInstanceConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.Configuration;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||
import net.sf.openrocket.simulation.listeners.SimulationListenerHelper;
|
||||
import net.sf.openrocket.util.BugException;
|
||||
@ -45,7 +45,7 @@ public abstract class AbstractSimulationStepper implements SimulationStepper {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Compute the wind to use, allowing listeners to override.
|
||||
*
|
||||
@ -75,7 +75,7 @@ public abstract class AbstractSimulationStepper implements SimulationStepper {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Compute the gravity to use, allowing listeners to override.
|
||||
*
|
||||
@ -104,7 +104,7 @@ public abstract class AbstractSimulationStepper implements SimulationStepper {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Compute the mass data to use, allowing listeners to override.
|
||||
*
|
||||
@ -142,9 +142,9 @@ public abstract class AbstractSimulationStepper implements SimulationStepper {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the average thrust produced by the motors in the current configuration, allowing
|
||||
* listeners to override. The average is taken between <code>status.time</code> and
|
||||
@ -171,19 +171,18 @@ public abstract class AbstractSimulationStepper implements SimulationStepper {
|
||||
}
|
||||
|
||||
Configuration configuration = status.getConfiguration();
|
||||
MotorInstanceConfiguration mic = status.getMotorConfiguration();
|
||||
|
||||
// Iterate over the motors and calculate combined thrust
|
||||
MotorInstanceConfiguration mic = status.getMotorConfiguration();
|
||||
if (!stepMotors) {
|
||||
mic = mic.clone();
|
||||
}
|
||||
mic.step(status.getSimulationTime() + timestep, acceleration, atmosphericConditions);
|
||||
thrust = 0;
|
||||
for (MotorId id : mic.getMotorIDs()) {
|
||||
if (configuration.isComponentActive((RocketComponent) mic.getMotorMount(id))) {
|
||||
MotorInstance motor = mic.getMotorInstance(id);
|
||||
thrust += motor.getThrust();
|
||||
}
|
||||
|
||||
List<MotorInstance> activeMotors = configuration.getActiveMotors(mic);
|
||||
for (MotorInstance currentMotorInstance : activeMotors) {
|
||||
thrust += currentMotorInstance.getThrust();
|
||||
}
|
||||
|
||||
// Post-listeners
|
||||
|
@ -1,6 +1,6 @@
|
||||
package net.sf.openrocket.simulation;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import net.sf.openrocket.aerodynamics.Warning;
|
||||
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.MotorInstance;
|
||||
import net.sf.openrocket.motor.MotorInstanceConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.AxialStage;
|
||||
import net.sf.openrocket.rocketcomponent.Configuration;
|
||||
import net.sf.openrocket.rocketcomponent.DeploymentConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.IgnitionConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.MotorConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.rocketcomponent.AxialStage;
|
||||
import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration;
|
||||
import net.sf.openrocket.simulation.exception.MotorIgnitionException;
|
||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||
@ -68,7 +67,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
// Set up rocket configuration
|
||||
Configuration configuration = setupConfiguration(simulationConditions);
|
||||
flightConfigurationId = configuration.getFlightConfigurationID();
|
||||
MotorInstanceConfiguration motorConfiguration = setupMotorConfiguration(configuration);
|
||||
MotorInstanceConfiguration motorConfiguration = new MotorInstanceConfiguration(configuration);
|
||||
if (motorConfiguration.getMotorIDs().isEmpty()) {
|
||||
throw new MotorIgnitionException(trans.get("BasicEventSimulationEngine.error.noMotorsDefined"));
|
||||
}
|
||||
@ -199,7 +198,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
MotorInstance motor = status.getMotorConfiguration().getMotorInstance(motorId);
|
||||
if (!motor.isActive() && status.addBurntOutMotor(motorId)) {
|
||||
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) {
|
||||
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();
|
||||
if (tooMuchThrust) {
|
||||
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.
|
||||
* 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
|
||||
for (MotorId id : status.getMotorConfiguration().getMotorIDs()) {
|
||||
IgnitionConfiguration.IgnitionEvent ignitionEvent = status.getMotorConfiguration().getMotorIgnitionEvent(id);
|
||||
MotorMount mount = status.getMotorConfiguration().getMotorMount(id);
|
||||
MotorInstance inst = status.getMotorConfiguration().getMotorInstance(id);
|
||||
IgnitionConfiguration.IgnitionEvent ignitionEvent = inst.getIgnitionEvent();
|
||||
MotorMount mount = inst.getMount();
|
||||
RocketComponent component = (RocketComponent) mount;
|
||||
|
||||
if (ignitionEvent.isActivationEvent(event, component)) {
|
||||
double ignitionDelay = status.getMotorConfiguration().getMotorIgnitionDelay(id);
|
||||
double ignitionDelay = inst.getIgnitionDelay();
|
||||
addEvent(new FlightEvent(FlightEvent.Type.IGNITION,
|
||||
status.getSimulationTime() + ignitionDelay,
|
||||
component, id));
|
||||
@ -354,11 +323,12 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
|
||||
|
||||
// Check for stage separation event
|
||||
for (int stageNo : status.getConfiguration().getActiveStages()) {
|
||||
|
||||
for (AxialStage stage : status.getConfiguration().getActiveStages()) {
|
||||
int stageNo = stage.getStageNumber();
|
||||
if (stageNo == 0)
|
||||
continue;
|
||||
|
||||
AxialStage stage = (AxialStage) status.getConfiguration().getRocket().getChild(stageNo);
|
||||
StageSeparationConfiguration separationConfig = stage.getStageSeparationConfiguration().get(flightConfigurationId);
|
||||
if (separationConfig.getSeparationEvent().isSeparationEvent(event, stage)) {
|
||||
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
|
||||
Iterator<RocketComponent> rci = status.getConfiguration().iterator();
|
||||
while (rci.hasNext()) {
|
||||
RocketComponent c = rci.next();
|
||||
for (RocketComponent c : status.getConfiguration().getActiveComponents()) {
|
||||
if (!(c instanceof RecoveryDevice))
|
||||
continue;
|
||||
DeploymentConfiguration deployConfig = ((RecoveryDevice) c).getDeploymentConfiguration().get(flightConfigurationId);
|
||||
@ -393,8 +361,10 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
case IGNITION: {
|
||||
// Ignite the motor
|
||||
MotorId motorId = (MotorId) event.getData();
|
||||
MotorInstanceConfiguration config = status.getMotorConfiguration();
|
||||
config.setMotorIgnitionTime(motorId, event.getTime());
|
||||
MotorInstanceConfiguration motorConfig = status.getMotorConfiguration();
|
||||
MotorInstance inst = motorConfig.getMotorInstance(motorId);
|
||||
inst.setIgnitionTime(event.getTime());
|
||||
|
||||
status.setMotorIgnited(true);
|
||||
status.getFlightData().addEvent(event);
|
||||
|
||||
@ -422,7 +392,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
}
|
||||
// Add ejection charge event
|
||||
MotorId motorId = (MotorId) event.getData();
|
||||
double delay = status.getMotorConfiguration().getEjectionDelay(motorId);
|
||||
double delay = status.getMotorConfiguration().getMotorInstance(motorId).getEjectionDelay();
|
||||
if (delay != Motor.PLUGGED) {
|
||||
addEvent(new FlightEvent(FlightEvent.Type.EJECTION_CHARGE, status.getSimulationTime() + delay,
|
||||
event.getSource(), event.getData()));
|
||||
@ -450,7 +420,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
stages.add(boosterStatus);
|
||||
|
||||
// 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.
|
||||
boosterStatus.getConfiguration().setOnlyStage(n);
|
||||
@ -476,12 +446,14 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
// TODO: HIGH: Check stage activeness for other events as well?
|
||||
|
||||
// Check whether any motor in the active stages is active anymore
|
||||
for (MotorId motorId : status.getMotorConfiguration().getMotorIDs()) {
|
||||
int stage = ((RocketComponent) status.getMotorConfiguration().
|
||||
getMotorMount(motorId)).getStageNumber();
|
||||
List<MotorInstance> activeMotors = status.getConfiguration().getActiveMotors(status.getMotorConfiguration());
|
||||
for (MotorInstance curInstance : activeMotors) {
|
||||
MotorId curID = curInstance.getID();
|
||||
RocketComponent comp = ((RocketComponent) curInstance.getMount());
|
||||
int stage = comp.getStageNumber();
|
||||
if (!status.getConfiguration().isStageActive(stage))
|
||||
continue;
|
||||
if (!status.getMotorConfiguration().getMotorInstance(motorId).isActive())
|
||||
if (!status.getMotorConfiguration().getMotorInstance(curID).isActive())
|
||||
continue;
|
||||
status.getWarnings().add(Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING);
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ public class SimulationStatus implements Monitorable {
|
||||
*/
|
||||
double length = this.simulationConditions.getLaunchRodLength();
|
||||
double lugPosition = Double.NaN;
|
||||
for (RocketComponent c : this.configuration) {
|
||||
for (RocketComponent c : this.configuration.getActiveComponents()) {
|
||||
if (c instanceof LaunchLug) {
|
||||
double pos = c.toAbsolute(new Coordinate(c.getLength()))[0].x;
|
||||
if (Double.isNaN(lugPosition) || pos > lugPosition) {
|
||||
|
@ -6,8 +6,9 @@ import java.util.Map;
|
||||
import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
|
||||
import net.sf.openrocket.aerodynamics.AerodynamicForces;
|
||||
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.rocketcomponent.Configuration;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.simulation.FlightDataBranch;
|
||||
import net.sf.openrocket.simulation.FlightDataType;
|
||||
@ -20,7 +21,9 @@ import net.sf.openrocket.util.Coordinate;
|
||||
public class DampingMoment extends AbstractSimulationListener {
|
||||
|
||||
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
|
||||
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.
|
||||
double nozzleDistance = 0;
|
||||
for (MotorId id : status.getMotorConfiguration().getMotorIDs()) {
|
||||
MotorInstanceConfiguration config = status.getMotorConfiguration();
|
||||
Coordinate position = config.getMotorPosition(id);
|
||||
Configuration config = status.getConfiguration();
|
||||
MotorInstanceConfiguration motorConfig = status.getMotorConfiguration();
|
||||
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) {
|
||||
nozzleDistance = x;
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ public class RollControlListener extends AbstractSimulationListener {
|
||||
// Maximum control fin angle (rad)
|
||||
private static final double MAX_ANGLE = 15 * Math.PI / 180;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* PID parameters
|
||||
*
|
||||
@ -47,9 +47,9 @@ public class RollControlListener extends AbstractSimulationListener {
|
||||
private static final double KP = 0.007;
|
||||
private static final double KI = 0.2;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private double rollrate;
|
||||
|
||||
private double prevTime = 0;
|
||||
@ -58,7 +58,7 @@ public class RollControlListener extends AbstractSimulationListener {
|
||||
private double finPosition = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public FlightConditions postFlightConditions(SimulationStatus status, FlightConditions flightConditions) {
|
||||
// Store the current roll rate for later use
|
||||
@ -78,7 +78,7 @@ public class RollControlListener extends AbstractSimulationListener {
|
||||
|
||||
// Find the fin set named CONTROL
|
||||
FinSet finset = null;
|
||||
for (RocketComponent c : status.getConfiguration()) {
|
||||
for (RocketComponent c : status.getConfiguration().getActiveComponents()) {
|
||||
if ((c instanceof FinSet) && (c.getName().equals(CONTROL_FIN_NAME))) {
|
||||
finset = (FinSet) c;
|
||||
break;
|
||||
@ -88,12 +88,12 @@ public class RollControlListener extends AbstractSimulationListener {
|
||||
throw new SimulationException("A fin set with name '" + CONTROL_FIN_NAME + "' was not found");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Determine time step
|
||||
double deltaT = status.getSimulationTime() - prevTime;
|
||||
prevTime = status.getSimulationTime();
|
||||
|
||||
|
||||
|
||||
// PID controller
|
||||
double error = SETPOINT - rollrate;
|
||||
|
||||
@ -103,7 +103,7 @@ public class RollControlListener extends AbstractSimulationListener {
|
||||
|
||||
double value = p + i;
|
||||
|
||||
|
||||
|
||||
// Clamp the fin angle between -MAX_ANGLE and MAX_ANGLE
|
||||
if (Math.abs(value) > MAX_ANGLE) {
|
||||
System.err.printf("Attempting to set angle %.1f at t=%.3f, clamping.\n",
|
||||
@ -111,7 +111,7 @@ public class RollControlListener extends AbstractSimulationListener {
|
||||
value = MathUtil.clamp(value, -MAX_ANGLE, MAX_ANGLE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Limit the fin turn rate
|
||||
if (finPosition < value) {
|
||||
finPosition = Math.min(finPosition + TURNRATE * deltaT, value);
|
||||
|
@ -23,8 +23,8 @@ public class CaliberUnit extends GeneralUnit {
|
||||
private double caliber = -1;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public CaliberUnit(Configuration configuration) {
|
||||
super(1.0, "cal");
|
||||
this.configuration = configuration;
|
||||
@ -69,7 +69,7 @@ public class CaliberUnit extends GeneralUnit {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void checkCaliber() {
|
||||
if (configuration != null && configuration.getModID() != configurationModId) {
|
||||
caliber = -1;
|
||||
@ -98,7 +98,7 @@ public class CaliberUnit extends GeneralUnit {
|
||||
* @return the caliber of the rocket, or the default caliber.
|
||||
*/
|
||||
public static double calculateCaliber(Configuration config) {
|
||||
return calculateCaliber(config.iterator());
|
||||
return calculateCaliber(config.getActiveComponents().iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -112,7 +112,7 @@ public class CaliberUnit extends GeneralUnit {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static double calculateCaliber(Iterator<RocketComponent> iterator) {
|
||||
double cal = 0;
|
||||
|
||||
|
@ -647,7 +647,6 @@ public class BoosterSetTest extends BaseTestCase {
|
||||
assertEquals(" init order error: " + treeDump + " Booster B: resultant positions: ", expectedOffset, resultantOffsetB, EPSILON);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testStageNumbering() {
|
||||
Rocket rocket = createTestRocket();
|
||||
@ -679,9 +678,30 @@ public class BoosterSetTest extends BaseTestCase {
|
||||
actualStageNumber = boosterB.getStageNumber();
|
||||
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
|
||||
public void testToAbsolute() {
|
||||
Rocket rocket = createTestRocket();
|
||||
|
@ -1,11 +1,12 @@
|
||||
package net.sf.openrocket.rocketcomponent;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.EventObject;
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent.Position;
|
||||
import net.sf.openrocket.util.StateChangeListener;
|
||||
@ -72,20 +73,9 @@ public class ConfigurationTest extends BaseTestCase {
|
||||
Configuration config = r1.getDefaultConfiguration();
|
||||
|
||||
/* Test */
|
||||
|
||||
// Test rocket component iterator
|
||||
// TODO: validate iterator iterates correctly
|
||||
for (Iterator<RocketComponent> i = config.iterator(); i.hasNext();) {
|
||||
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"));
|
||||
}
|
||||
// the component iterator is no longer a custom iterator....
|
||||
// use the standard iterator over the Collection<> returned by config.getActiveComponents()
|
||||
|
||||
// Test motor iterator
|
||||
/* 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
|
||||
try {
|
||||
Iterator<MotorMount> motorIterator = config.motorIterator();
|
||||
motorIterator.remove();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
assertTrue(e.getMessage().equals("remove unsupported"));
|
||||
}
|
||||
|
||||
// // Motor iterator remove method is unsupported, should throw exception
|
||||
// try {
|
||||
// Iterator<MotorMount> motorIterator = config.motorIterator();
|
||||
// motorIterator.remove();
|
||||
// } catch (UnsupportedOperationException e) {
|
||||
// assertTrue(e.getMessage().equals("remove unsupported"));
|
||||
// }
|
||||
//
|
||||
/* Cleanup */
|
||||
config.release();
|
||||
|
||||
@ -119,7 +109,7 @@ public class ConfigurationTest extends BaseTestCase {
|
||||
|
||||
Configuration configClone = config.clone(); // TODO validate clone worked
|
||||
assertFalse(config.getRocket() == null);
|
||||
assertFalse(config.hasMotors());
|
||||
// assertFalse(config.hasMotors());
|
||||
|
||||
config.release();
|
||||
}
|
||||
@ -211,31 +201,34 @@ public class ConfigurationTest extends BaseTestCase {
|
||||
Rocket r1 = makeSingleStageTestRocket();
|
||||
Configuration config = r1.getDefaultConfiguration();
|
||||
|
||||
BitSet activeStageFlags = new BitSet();
|
||||
activeStageFlags.set(0, false); // first stage
|
||||
|
||||
/* Test */
|
||||
|
||||
// test cloning of single stage rocket
|
||||
Configuration configClone = config.clone(); // TODO validate clone worked
|
||||
configClone.release();
|
||||
|
||||
// test explicitly setting only first stage active
|
||||
config.clearAllStages();
|
||||
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
|
||||
config.setToStage(0);
|
||||
activeStageFlags.clear();
|
||||
activeStageFlags.set(0, true);
|
||||
validateStages(config, 1, activeStageFlags);
|
||||
config.setOnlyStage(0);
|
||||
|
||||
// test explicitly setting all stages active
|
||||
config.setAllStages();
|
||||
activeStageFlags.clear();
|
||||
activeStageFlags.set(0, true);
|
||||
validateStages(config, 1, activeStageFlags);
|
||||
|
||||
// Cleanup
|
||||
config.release();
|
||||
@ -252,43 +245,57 @@ public class ConfigurationTest extends BaseTestCase {
|
||||
Rocket r1 = makeTwoStageTestRocket();
|
||||
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
|
||||
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
|
||||
config.setOnlyStage(0);
|
||||
activeStageFlags.clear();
|
||||
activeStageFlags.set(0, true);
|
||||
validateStages(config, 2, activeStageFlags);
|
||||
|
||||
// test explicitly setting all stages up to first stage active
|
||||
config.setToStage(0);
|
||||
activeStageFlags.clear();
|
||||
activeStageFlags.set(0, true);
|
||||
validateStages(config, 2, activeStageFlags);
|
||||
expectedStageCount = 1;
|
||||
stageCount = config.getActiveStageCount();
|
||||
assertThat("active stage count doesn't match", stageCount, equalTo(expectedStageCount));
|
||||
|
||||
assertThat(" setting single stage active: ", config.isStageActive(0), equalTo(true));
|
||||
|
||||
// test explicitly setting all stages up to second stage active
|
||||
config.setToStage(1);
|
||||
activeStageFlags.clear();
|
||||
activeStageFlags.set(0, 2, true);
|
||||
validateStages(config, 2, activeStageFlags);
|
||||
config.setOnlyStage(1);
|
||||
assertThat(config.toDebug() + "Setting single stage active: ", config.isStageActive(1), equalTo(true));
|
||||
|
||||
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
|
||||
config.setAllStages();
|
||||
activeStageFlags.clear();
|
||||
activeStageFlags.set(0, 2, true);
|
||||
validateStages(config, 2, activeStageFlags);
|
||||
assertThat(" activate all stages: check #0: ", config.isStageActive(0), equalTo(true));
|
||||
assertThat(" activate all stages: check #1: ", config.isStageActive(1), equalTo(true));
|
||||
|
||||
// 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
|
||||
config.release();
|
||||
|
||||
|
||||
}
|
||||
|
||||
///////////////////// Helper Methods ////////////////////////////
|
||||
@ -307,43 +314,45 @@ public class ConfigurationTest extends BaseTestCase {
|
||||
}
|
||||
}
|
||||
assertTrue(config.getActiveStageCount() == expectedActiveStageCount);
|
||||
int[] stages = config.getActiveStages();
|
||||
assertTrue(stages.length == expectedActiveStageCount);
|
||||
|
||||
// test if isHead() detects first stage being active or inactive
|
||||
if (activeStageFlags.get(0)) {
|
||||
assertTrue(config.isHead());
|
||||
} else {
|
||||
assertFalse(config.isHead());
|
||||
}
|
||||
|
||||
// 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));
|
||||
} else {
|
||||
assertFalse(config.isStageActive(i));
|
||||
}
|
||||
}
|
||||
|
||||
// test boundary conditions
|
||||
|
||||
// stage -1 should not exist, and isStageActive() should throw exception
|
||||
boolean IndexOutOfBoundsExceptionFlag = false;
|
||||
try {
|
||||
assertFalse(config.isStageActive(-1));
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
IndexOutOfBoundsExceptionFlag = true;
|
||||
}
|
||||
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));
|
||||
assertTrue("this test is not yet written.", false);
|
||||
// int[] stages = config.getActiveStages();
|
||||
//
|
||||
// assertTrue(stages.length == expectedActiveStageCount);
|
||||
//
|
||||
// // test if isHead() detects first stage being active or inactive
|
||||
// if (activeStageFlags.get(0)) {
|
||||
// assertTrue(config.isHead());
|
||||
// } else {
|
||||
// assertFalse(config.isHead());
|
||||
// }
|
||||
//
|
||||
// // 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));
|
||||
// } else {
|
||||
// assertFalse(config.isStageActive(i));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // test boundary conditions
|
||||
//
|
||||
// // stage -1 should not exist, and isStageActive() should throw exception
|
||||
// boolean IndexOutOfBoundsExceptionFlag = false;
|
||||
// try {
|
||||
// assertFalse(config.isStageActive(-1));
|
||||
// } catch (IndexOutOfBoundsException e) {
|
||||
// IndexOutOfBoundsExceptionFlag = true;
|
||||
// }
|
||||
// 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 /////////////////////////
|
||||
|
||||
public static Rocket makeEmptyRocket() {
|
||||
|
@ -11,12 +11,15 @@ import javax.swing.JToggleButton;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.rocketcomponent.AxialStage;
|
||||
import net.sf.openrocket.rocketcomponent.Configuration;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.util.StateChangeListener;
|
||||
|
||||
|
||||
public class StageSelector extends JPanel implements StateChangeListener {
|
||||
private static final long serialVersionUID = -2898763402479628711L;
|
||||
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
|
||||
private final Configuration configuration;
|
||||
@ -40,13 +43,11 @@ public class StageSelector extends JPanel implements StateChangeListener {
|
||||
if (buttons.size() == stages)
|
||||
return;
|
||||
|
||||
while (buttons.size() > stages) {
|
||||
JToggleButton button = buttons.remove(buttons.size() - 1);
|
||||
this.remove(button);
|
||||
}
|
||||
|
||||
while (buttons.size() < stages) {
|
||||
JToggleButton button = new JToggleButton(new StageAction(buttons.size()));
|
||||
buttons.clear();
|
||||
this.removeAll();
|
||||
for(AxialStage stage : configuration.getRocket().getStageList()){
|
||||
int stageNum = stage.getStageNumber();
|
||||
JToggleButton button = new JToggleButton(new StageAction(stageNum));
|
||||
this.add(button);
|
||||
buttons.add(button);
|
||||
}
|
||||
@ -55,8 +56,6 @@ public class StageSelector extends JPanel implements StateChangeListener {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void stateChanged(EventObject e) {
|
||||
updateButtons();
|
||||
@ -64,10 +63,11 @@ public class StageSelector extends JPanel 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) {
|
||||
this.stage = stage;
|
||||
this.stageNumber = stage;
|
||||
configuration.addChangeListener(this);
|
||||
stateChanged(null);
|
||||
}
|
||||
@ -75,37 +75,20 @@ public class StageSelector extends JPanel implements StateChangeListener {
|
||||
@Override
|
||||
public Object getValue(String key) {
|
||||
if (key.equals(NAME)) {
|
||||
//// Stage
|
||||
return trans.get("StageAction.Stage") + " " + (stage + 1);
|
||||
// Stage
|
||||
return trans.get("StageAction.Stage") + " " + (stageNumber );
|
||||
}
|
||||
return super.getValue(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
configuration.setToStage(stage);
|
||||
|
||||
// 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);
|
||||
configuration.toggleStage(stageNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateChanged(EventObject e) {
|
||||
this.putValue(SELECTED_KEY, configuration.isStageActive(stage));
|
||||
this.putValue(SELECTED_KEY, configuration.isStageActive(stageNumber));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -513,7 +513,7 @@ public class ComponentAnalysisDialog extends JDialog implements StateChangeListe
|
||||
cgData.clear();
|
||||
dragData.clear();
|
||||
rollData.clear();
|
||||
for (RocketComponent c : configuration) {
|
||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
||||
forces = aeroData.get(c);
|
||||
Coordinate cg = massData.get(c);
|
||||
|
||||
|
@ -2,7 +2,6 @@ package net.sf.openrocket.gui.figure3d;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
@ -62,7 +61,7 @@ public abstract class RocketRenderer {
|
||||
// Store a vector of pickable parts.
|
||||
final Vector<RocketComponent> pickParts = new Vector<RocketComponent>();
|
||||
|
||||
for (RocketComponent c : configuration) {
|
||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
||||
if (ignore != null && ignore.contains(c))
|
||||
continue;
|
||||
|
||||
@ -116,7 +115,7 @@ public abstract class RocketRenderer {
|
||||
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_SPECULAR, colorBlack, 0);
|
||||
gl.glLineWidth(5.0f);
|
||||
|
||||
for (RocketComponent c : configuration) {
|
||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
||||
if (selection.contains(c)) {
|
||||
// Draw as lines, set Z to nearest
|
||||
gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_LINE);
|
||||
@ -141,7 +140,7 @@ public abstract class RocketRenderer {
|
||||
gl.glCullFace(GL.GL_BACK);
|
||||
|
||||
// Draw all inner components
|
||||
for (RocketComponent c : configuration) {
|
||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
||||
if (isDrawn(c)) {
|
||||
if (!isDrawnTransparent(c)) {
|
||||
renderComponent(gl, c, 1.0f);
|
||||
@ -153,7 +152,7 @@ public abstract class RocketRenderer {
|
||||
|
||||
// Draw T&T front faces blended, without depth test
|
||||
gl.glEnable(GL.GL_BLEND);
|
||||
for (RocketComponent c : configuration) {
|
||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
||||
if (isDrawn(c)) {
|
||||
if (isDrawnTransparent(c)) {
|
||||
renderComponent(gl, c, 0.2f);
|
||||
@ -166,20 +165,23 @@ public abstract class RocketRenderer {
|
||||
|
||||
private void renderMotors(GL2 gl, Configuration configuration) {
|
||||
String motorID = configuration.getFlightConfigurationID();
|
||||
Iterator<MotorMount> iterator = configuration.motorIterator();
|
||||
while (iterator.hasNext()) {
|
||||
MotorMount mount = iterator.next();
|
||||
Motor motor = mount.getMotorConfiguration().get(motorID).getMotor();
|
||||
double length = motor.getLength();
|
||||
|
||||
for( RocketComponent comp : configuration.getActiveComponents()){
|
||||
if( comp instanceof MotorMount){
|
||||
|
||||
Coordinate[] position = ((RocketComponent) mount).toAbsolute(new Coordinate(((RocketComponent) mount)
|
||||
.getLength() + mount.getMotorOverhang() - length));
|
||||
MotorMount mount = (MotorMount) comp;
|
||||
Motor motor = mount.getMotorConfiguration().get(motorID).getMotor();
|
||||
double length = motor.getLength();
|
||||
|
||||
for (int i = 0; i < position.length; i++) {
|
||||
gl.glPushMatrix();
|
||||
gl.glTranslated(position[i].x, position[i].y, position[i].z);
|
||||
renderMotor(gl, motor);
|
||||
gl.glPopMatrix();
|
||||
Coordinate[] position = ((RocketComponent) mount).toAbsolute(new Coordinate(((RocketComponent) mount)
|
||||
.getLength() + mount.getMotorOverhang() - length));
|
||||
|
||||
for (int i = 0; i < position.length; i++) {
|
||||
gl.glPushMatrix();
|
||||
gl.glTranslated(position[i].x, position[i].y, position[i].z);
|
||||
renderMotor(gl, motor);
|
||||
gl.glPopMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,6 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.media.opengl.DebugGL2;
|
||||
import javax.media.opengl.GL;
|
||||
import javax.media.opengl.GL2;
|
||||
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.MotorMount;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.rocketcomponent.AxialStage;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.startup.Preferences;
|
||||
import net.sf.openrocket.util.Color;
|
||||
@ -416,37 +414,40 @@ public class PhotoPanel extends JPanel implements GLEventListener {
|
||||
rr.render(drawable, configuration, new HashSet<RocketComponent>());
|
||||
|
||||
//Figure out the lowest stage shown
|
||||
final int currentStageNumber = configuration.getActiveStages()[configuration.getActiveStages().length-1];
|
||||
final AxialStage currentStage = (AxialStage)configuration.getRocket().getChild(currentStageNumber);
|
||||
final int bottomStageNumber = configuration.getBottomStage().getStageNumber();
|
||||
//final int currentStageNumber = configuration.getActiveStages()[configuration.getActiveStages().length-1];
|
||||
//final AxialStage currentStage = (AxialStage)configuration.getRocket().getChild( bottomStageNumber);
|
||||
|
||||
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.
|
||||
RocketComponent parent = ((RocketComponent)mount);
|
||||
while ( null != (parent = parent.getParent()) ){
|
||||
if ( parent instanceof AxialStage ){
|
||||
if ( parent != currentStage )
|
||||
continue motor;
|
||||
break;
|
||||
//If this mount is not in currentStage continue on to the next one.
|
||||
if( curStageNumber != bottomStageNumber ){
|
||||
continue;
|
||||
}
|
||||
|
||||
final Motor motor = mount.getMotorConfiguration().get(motorID).getMotor();
|
||||
final double length = motor.getLength();
|
||||
|
||||
Coordinate[] position = ((RocketComponent) mount)
|
||||
.toAbsolute(new Coordinate(((RocketComponent) mount)
|
||||
.getLength() + mount.getMotorOverhang() - length));
|
||||
|
||||
for (int i = 0; i < position.length; i++) {
|
||||
gl.glPushMatrix();
|
||||
gl.glTranslated(position[i].x + motor.getLength(),
|
||||
position[i].y, position[i].z);
|
||||
FlameRenderer.drawExhaust(gl, p, motor);
|
||||
gl.glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
final Motor motor = mount.getMotorConfiguration().get(motorID).getMotor();
|
||||
final double length = motor.getLength();
|
||||
|
||||
Coordinate[] position = ((RocketComponent) mount)
|
||||
.toAbsolute(new Coordinate(((RocketComponent) mount)
|
||||
.getLength() + mount.getMotorOverhang() - length));
|
||||
|
||||
for (int i = 0; i < position.length; i++) {
|
||||
gl.glPushMatrix();
|
||||
gl.glTranslated(position[i].x + motor.getLength(),
|
||||
position[i].y, position[i].z);
|
||||
FlameRenderer.drawExhaust(gl, p, motor);
|
||||
gl.glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ import java.awt.geom.Rectangle2D;
|
||||
import net.sf.openrocket.aerodynamics.Warning;
|
||||
import net.sf.openrocket.aerodynamics.WarningSet;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.motor.MotorInstanceConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.Configuration;
|
||||
import net.sf.openrocket.simulation.FlightData;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
@ -47,7 +48,9 @@ public class RocketInfo implements FigureElement {
|
||||
private double cg = 0, cp = 0;
|
||||
private double length = 0, diameter = 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;
|
||||
|
||||
@ -151,7 +154,8 @@ public class RocketInfo implements FigureElement {
|
||||
UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(diameter));
|
||||
|
||||
String massText;
|
||||
if (configuration.hasMotors())
|
||||
MotorInstanceConfiguration mic = new MotorInstanceConfiguration(configuration);
|
||||
if (mic.hasMotors())
|
||||
//// Mass with motors
|
||||
massText = trans.get("RocketInfo.massText1") +" ";
|
||||
else
|
||||
|
@ -16,6 +16,7 @@ import net.sf.openrocket.gui.scalefigure.RocketPanel;
|
||||
import net.sf.openrocket.masscalc.MassCalculator;
|
||||
import net.sf.openrocket.masscalc.MassCalculator.MassCalcType;
|
||||
import net.sf.openrocket.motor.Motor;
|
||||
import net.sf.openrocket.motor.MotorInstanceConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.Configuration;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||
@ -192,7 +193,9 @@ public class DesignReport {
|
||||
canvas.showText("" + rocket.getStageCount());
|
||||
|
||||
|
||||
if (configuration.hasMotors()) {
|
||||
|
||||
MotorInstanceConfiguration mic = new MotorInstanceConfiguration(configuration);
|
||||
if (mic.hasMotors()){
|
||||
if (configuration.getStageCount() > 1) {
|
||||
canvas.newlineShowText(MASS_WITH_MOTORS);
|
||||
} else {
|
||||
@ -341,7 +344,8 @@ public class DesignReport {
|
||||
for (RocketComponent c : rocket) {
|
||||
|
||||
if (c instanceof AxialStage) {
|
||||
config.setToStage(stage);
|
||||
config.clearAllStages();
|
||||
config.setOnlyStage(stage);
|
||||
stage++;
|
||||
stageMass = massCalc.getCG(config, MassCalcType.LAUNCH_MASS).weight;
|
||||
// Calculate total thrust-to-weight from only lowest stage motors
|
||||
|
@ -23,6 +23,8 @@ import net.sf.openrocket.gui.figureelements.FigureElement;
|
||||
import net.sf.openrocket.gui.util.ColorConversion;
|
||||
import net.sf.openrocket.gui.util.SwingPreferences;
|
||||
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.Configuration;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
@ -339,13 +341,13 @@ public class RocketFigure extends AbstractScaleFigure {
|
||||
RenderingHints.VALUE_STROKE_NORMALIZE);
|
||||
|
||||
// Draw motors
|
||||
String motorID = configuration.getFlightConfigurationID();
|
||||
Color fillColor = ((SwingPreferences)Application.getPreferences()).getMotorFillColor();
|
||||
Color borderColor = ((SwingPreferences)Application.getPreferences()).getMotorBorderColor();
|
||||
Iterator<MotorMount> iterator = configuration.motorIterator();
|
||||
while (iterator.hasNext()) {
|
||||
MotorMount mount = iterator.next();
|
||||
Motor motor = mount.getMotor(motorID);
|
||||
|
||||
MotorInstanceConfiguration mic = new MotorInstanceConfiguration(configuration);
|
||||
for( MotorInstance curInstance : configuration.getActiveMotors(mic)){
|
||||
MotorMount mount = curInstance.getMount();
|
||||
Motor motor = curInstance.getMotor();
|
||||
double motorLength = motor.getLength();
|
||||
double motorRadius = motor.getDiameter() / 2;
|
||||
|
||||
|
@ -56,6 +56,7 @@ import net.sf.openrocket.gui.util.SwingPreferences;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.masscalc.MassCalculator;
|
||||
import net.sf.openrocket.masscalc.MassCalculator.MassCalcType;
|
||||
import net.sf.openrocket.motor.MotorInstanceConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
|
||||
import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
|
||||
import net.sf.openrocket.rocketcomponent.Configuration;
|
||||
@ -640,7 +641,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
|
||||
length = maxX - minX;
|
||||
}
|
||||
|
||||
for (RocketComponent c : configuration) {
|
||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
||||
if (c instanceof SymmetricComponent) {
|
||||
double d1 = ((SymmetricComponent) c).getForeRadius() * 2;
|
||||
double d2 = ((SymmetricComponent) c).getAftRadius() * 2;
|
||||
@ -692,8 +693,10 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
|
||||
// Stop previous computation (if any)
|
||||
stopBackgroundSimulation();
|
||||
|
||||
MotorInstanceConfiguration mic = new MotorInstanceConfiguration( configuration);
|
||||
|
||||
// Check that configuration has motors
|
||||
if (!configuration.hasMotors()) {
|
||||
if (!mic.hasMotors()){
|
||||
extraText.setFlightData(FlightData.NaN_DATA);
|
||||
extraText.setCalculatingData(false);
|
||||
return;
|
||||
|
@ -8,6 +8,7 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
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.SwingPreferences;
|
||||
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.IgnitionConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
@ -306,11 +309,13 @@ public class SimulationRunDialog extends JDialog {
|
||||
// Calculate estimate of motor burn time
|
||||
double launchBurn = 0;
|
||||
double otherBurn = 0;
|
||||
Configuration config = simulation.getConfiguration();
|
||||
String id = simulation.getOptions().getMotorConfigurationID();
|
||||
Iterator<MotorMount> iterator = config.motorIterator();
|
||||
while (iterator.hasNext()) {
|
||||
MotorMount m = iterator.next();
|
||||
|
||||
Configuration config = simulation.getConfiguration();
|
||||
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)
|
||||
launchBurn = MathUtil.max(launchBurn, m.getMotor(id).getBurnTimeEstimate());
|
||||
else
|
||||
|
Loading…
x
Reference in New Issue
Block a user