folded BasicMassCalculator into MassCalculator

This commit is contained in:
Daniel_M_Williams 2015-09-05 11:54:29 -04:00
parent 7978771e1b
commit 85dff39fb9
11 changed files with 378 additions and 450 deletions

View File

@ -9,7 +9,6 @@ import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
import net.sf.openrocket.aerodynamics.WarningSet;
import net.sf.openrocket.formatting.RocketDescriptor;
import net.sf.openrocket.masscalc.BasicMassCalculator;
import net.sf.openrocket.masscalc.MassCalculator;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.motor.MotorInstanceConfiguration;
@ -93,7 +92,7 @@ public class Simulation implements ChangeSource, Cloneable {
private Class<? extends SimulationStepper> simulationStepperClass = RK4SimulationStepper.class;
private Class<? extends AerodynamicCalculator> aerodynamicCalculatorClass = BarrowmanCalculator.class;
@SuppressWarnings("unused")
private Class<? extends MassCalculator> massCalculatorClass = BasicMassCalculator.class;
private Class<? extends MassCalculator> massCalculatorClass = MassCalculator.class;
/** Listeners for this object */
private List<EventListener> listeners = new ArrayList<EventListener>();

View File

@ -13,11 +13,10 @@ import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.document.StorageOptions;
import net.sf.openrocket.file.RocketSaver;
import net.sf.openrocket.file.rocksim.RocksimCommonConstants;
import net.sf.openrocket.masscalc.BasicMassCalculator;
import net.sf.openrocket.masscalc.MassCalculator;
import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.rocketcomponent.Rocket;
import net.sf.openrocket.rocketcomponent.AxialStage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -93,7 +92,7 @@ public class RocksimSaver extends RocketSaver {
private RocketDesignDTO toRocketDesignDTO(Rocket rocket) {
RocketDesignDTO result = new RocketDesignDTO();
MassCalculator massCalc = new BasicMassCalculator();
MassCalculator massCalc = new MassCalculator();
final Configuration configuration = new Configuration(rocket);
final double cg = massCalc.getCG(configuration, MassCalculator.MassCalcType.NO_MOTORS).x *

View File

@ -1,403 +0,0 @@
package net.sf.openrocket.masscalc;
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;
import net.sf.openrocket.util.MathUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BasicMassCalculator implements MassCalculator {
private static final double MIN_MASS = 0.001 * MathUtil.EPSILON;
private static final Logger log = LoggerFactory.getLogger(MassCalculator.class);
private int rocketMassModID = -1;
private int rocketTreeModID = -1;
/*
* Cached data. All CG data is in absolute coordinates. All moments of inertia
* are relative to their respective CG.
*/
private Coordinate[] cgCache = null;
private double longitudinalInertiaCache[] = null;
private double rotationalInertiaCache[] = null;
////////////////// Mass property calculations ///////////////////
/**
* Return the CG of the rocket with the specified motor status (no motors,
* ignition, burnout).
*/
@Override
public Coordinate getCG(Configuration configuration, MassCalcType type) {
checkCache(configuration);
calculateStageCache(configuration);
Coordinate totalCG = null;
// Stage contribution
for (int stage : configuration.getActiveStages()) {
totalCG = cgCache[stage].average(totalCG);
}
if (totalCG == null)
totalCG = 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.getMotor(motorId);
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);
}
}
}
return totalCG;
}
/**
* Return the CG of the rocket with the provided motor configuration.
*/
@Override
public Coordinate getCG(Configuration configuration, MotorInstanceConfiguration motors) {
checkCache(configuration);
calculateStageCache(configuration);
Coordinate totalCG = getCG(configuration, MassCalcType.NO_MOTORS);
// 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);
}
}
}
return totalCG;
}
/**
* Return the longitudinal inertia of the rocket with the specified motor instance
* configuration.
*
* @param configuration the current motor instance configuration
* @return the longitudinal inertia of the rocket
*/
@Override
public double getLongitudinalInertia(Configuration configuration, MotorInstanceConfiguration motors) {
checkCache(configuration);
calculateStageCache(configuration);
final Coordinate totalCG = getCG(configuration, motors);
double totalInertia = 0;
// Stages
for (int stage : configuration.getActiveStages()) {
Coordinate stageCG = cgCache[stage];
totalInertia += (longitudinalInertiaCache[stage] +
stageCG.weight * MathUtil.pow2(stageCG.x - totalCG.x));
}
// Motors
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);
double inertia = motor.getLongitudinalInertia();
totalInertia += inertia + cg.weight * MathUtil.pow2(cg.x - totalCG.x);
}
}
}
return totalInertia;
}
/**
* Return the rotational inertia of the rocket with the specified motor instance
* configuration.
*
* @param configuration the current motor instance configuration
* @return the rotational inertia of the rocket
*/
@Override
public double getRotationalInertia(Configuration configuration, MotorInstanceConfiguration motors) {
checkCache(configuration);
calculateStageCache(configuration);
final Coordinate totalCG = getCG(configuration, motors);
double totalInertia = 0;
// Stages
for (int stage : configuration.getActiveStages()) {
Coordinate stageCG = cgCache[stage];
totalInertia += (rotationalInertiaCache[stage] +
stageCG.weight * (MathUtil.pow2(stageCG.y - totalCG.y) +
MathUtil.pow2(stageCG.z - totalCG.z)));
}
// Motors
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);
double inertia = motor.getRotationalInertia();
totalInertia += inertia + cg.weight * (MathUtil.pow2(cg.y - totalCG.y) +
MathUtil.pow2(cg.z - totalCG.z));
}
}
}
return totalInertia;
}
/**
* Return the total mass of the motors
*
* @param configuration the current motor instance configuration
* @return the total mass of all motors
*/
@Override
public double getPropellantMass(Configuration configuration, MotorInstanceConfiguration motors) {
double mass = 0;
// 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;
}
}
return mass;
}
@Override
public Map<RocketComponent, Coordinate> getCGAnalysis(Configuration configuration, MassCalcType type) {
checkCache(configuration);
calculateStageCache(configuration);
Map<RocketComponent, Coordinate> map = new HashMap<RocketComponent, Coordinate>();
for (RocketComponent c : configuration) {
Coordinate[] cgs = c.toAbsolute(c.getCG());
Coordinate totalCG = Coordinate.NUL;
for (Coordinate cg : cgs) {
totalCG = totalCG.average(cg);
}
map.put(c, totalCG);
}
map.put(configuration.getRocket(), getCG(configuration, type));
return map;
}
//////// Cache computations ////////
private void calculateStageCache(Configuration config) {
if (cgCache == null) {
ArrayList<AxialStage> stageList = config.getRocket().getStageList();
int stageCount = stageList.size();
cgCache = new Coordinate[stageCount];
longitudinalInertiaCache = new double[stageCount];
rotationalInertiaCache = new double[stageCount];
for (int i = 0; i < stageCount; i++) {
RocketComponent stage = stageList.get(i);
MassData data = calculateAssemblyMassData(stage);
cgCache[i] = stage.toAbsolute(data.getCG())[0];
longitudinalInertiaCache[i] = data.getLongitudinalInertia();
rotationalInertiaCache[i] = data.getRotationalInertia();
}
}
}
/**
* Returns the mass and inertia data for this component and all subcomponents.
* The inertia is returned relative to the CG, and the CG is in the coordinates
* of the specified component, not global coordinates.
*/
private MassData calculateAssemblyMassData(RocketComponent parent) {
Coordinate parentCG = Coordinate.ZERO;
double longitudinalInertia = 0.0;
double rotationalInertia = 0.0;
// Calculate data for this component
parentCG = parent.getComponentCG();
if (parentCG.weight < MIN_MASS)
parentCG = parentCG.setWeight(MIN_MASS);
// Override only this component's data
if (!parent.getOverrideSubcomponents()) {
if (parent.isMassOverridden())
parentCG = parentCG.setWeight(MathUtil.max(parent.getOverrideMass(), MIN_MASS));
if (parent.isCGOverridden())
parentCG = parentCG.setXYZ(parent.getOverrideCG());
}
longitudinalInertia = parent.getLongitudinalUnitInertia() * parentCG.weight;
rotationalInertia = parent.getRotationalUnitInertia() * parentCG.weight;
// Combine data for subcomponents
for (RocketComponent sibling : parent.getChildren()) {
Coordinate combinedCG;
double dx2, dr2;
// Compute data of sibling
MassData siblingData = calculateAssemblyMassData(sibling);
Coordinate[] siblingCGs = sibling.toRelative(siblingData.getCG(), parent);
for (Coordinate siblingCG : siblingCGs) {
// Compute CG of this + sibling
combinedCG = parentCG.average(siblingCG);
// Add effect of this CG change to parent inertia
dx2 = pow2(parentCG.x - combinedCG.x);
longitudinalInertia += parentCG.weight * dx2;
dr2 = pow2(parentCG.y - combinedCG.y) + pow2(parentCG.z - combinedCG.z);
rotationalInertia += parentCG.weight * dr2;
// Add inertia of sibling
longitudinalInertia += siblingData.getLongitudinalInertia();
rotationalInertia += siblingData.getRotationalInertia();
// Add effect of sibling CG change
dx2 = pow2(siblingData.getCG().x - combinedCG.x);
longitudinalInertia += siblingData.getCG().weight * dx2;
dr2 = pow2(siblingData.getCG().y - combinedCG.y) + pow2(siblingData.getCG().z - combinedCG.z);
rotationalInertia += siblingData.getCG().weight * dr2;
// Set combined CG
parentCG = combinedCG;
}
}
// Override total data
if (parent.getOverrideSubcomponents()) {
if (parent.isMassOverridden()) {
double oldMass = parentCG.weight;
double newMass = MathUtil.max(parent.getOverrideMass(), MIN_MASS);
longitudinalInertia = longitudinalInertia * newMass / oldMass;
rotationalInertia = rotationalInertia * newMass / oldMass;
parentCG = parentCG.setWeight(newMass);
}
if (parent.isCGOverridden()) {
double oldx = parentCG.x;
double newx = parent.getOverrideCGX();
longitudinalInertia += parentCG.weight * pow2(oldx - newx);
parentCG = parentCG.setX(newx);
}
}
MassData parentData = new MassData(parentCG, longitudinalInertia, rotationalInertia, 0);
return parentData;
}
/**
* Check the current cache consistency. This method must be called by all
* methods that may use any cached data before any other operations are
* performed. If the rocket has changed since the previous call to
* <code>checkCache()</code>, then {@link #voidMassCache()} is called.
* <p>
* This method performs the checking based on the rocket's modification IDs,
* so that these method may be called from listeners of the rocket itself.
*
* @param configuration the configuration of the current call
*/
protected final void checkCache(Configuration configuration) {
if (rocketMassModID != configuration.getRocket().getMassModID() ||
rocketTreeModID != configuration.getRocket().getTreeModID()) {
rocketMassModID = configuration.getRocket().getMassModID();
rocketTreeModID = configuration.getRocket().getTreeModID();
log.debug("Voiding the mass cache");
voidMassCache();
}
}
/**
* Void cached mass data. This method is called whenever a change occurs in
* the rocket structure that affects the mass of the rocket and when a new
* Rocket is used. This method must be overridden to void any cached data
* necessary. The method must call <code>super.voidMassCache()</code> during
* its execution.
*/
protected void voidMassCache() {
this.cgCache = null;
this.longitudinalInertiaCache = null;
this.rotationalInertiaCache = null;
}
@Override
public int getModID() {
return 0;
}
}

View File

@ -1,15 +1,29 @@
package net.sf.openrocket.masscalc;
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;
import net.sf.openrocket.util.MathUtil;
import net.sf.openrocket.util.Monitorable;
public interface MassCalculator extends Monitorable {
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MassCalculator implements Monitorable {
public static enum MassCalcType {
NO_MOTORS {
@ -34,41 +48,186 @@ public interface MassCalculator extends Monitorable {
public abstract Coordinate getCG(Motor motor);
}
private static final double MIN_MASS = 0.001 * MathUtil.EPSILON;
private static final Logger log = LoggerFactory.getLogger(MassCalculator.class);
private int rocketMassModID = -1;
private int rocketTreeModID = -1;
/*
* Cached data. All CG data is in absolute coordinates. All moments of inertia
* are relative to their respective CG.
*/
private Coordinate[] cgCache = null;
private double longitudinalInertiaCache[] = null;
private double rotationalInertiaCache[] = null;
////////////////// Mass property calculations ///////////////////
/**
* Compute the CG of the provided configuration.
* Return the CG of the rocket with the specified motor status (no motors,
* ignition, burnout).
*
* @param configuration the rocket configuration
* @param type the state of the motors (none, launch mass, burnout mass)
* @return the CG of the configuration
*/
public Coordinate getCG(Configuration configuration, MassCalcType type);
public Coordinate getCG(Configuration configuration, MassCalcType type) {
checkCache(configuration);
calculateStageCache(configuration);
Coordinate totalCG = null;
// Stage contribution
for (int stage : configuration.getActiveStages()) {
totalCG = cgCache[stage].average(totalCG);
}
if (totalCG == null)
totalCG = 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);
}
}
}
return totalCG;
}
/**
* Compute the CG of the provided configuration with specified motors.
* Compute the CG of the rocket with the provided motor configuration.
*
* @param configuration the rocket configuration
* @param motors the motor configuration
* @return the CG of the configuration
*/
public Coordinate getCG(Configuration configuration, MotorInstanceConfiguration motors);
public Coordinate getCG(Configuration configuration, MotorInstanceConfiguration motors) {
checkCache(configuration);
calculateStageCache(configuration);
Coordinate totalCG = getCG(configuration, MassCalcType.NO_MOTORS);
// 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);
}
}
}
return totalCG;
}
/**
* Compute the longitudinal inertia of the provided configuration with specified motors.
* Return the longitudinal inertia of the rocket with the specified motor instance
* configuration.
*
* @param configuration the rocket configuration
* @param configuration the current motor instance configuration
* @param motors the motor configuration
* @return the longitudinal inertia of the configuration
* @return the longitudinal inertia of the rocket
*/
public double getLongitudinalInertia(Configuration configuration, MotorInstanceConfiguration motors);
public double getLongitudinalInertia(Configuration configuration, MotorInstanceConfiguration motors) {
checkCache(configuration);
calculateStageCache(configuration);
final Coordinate totalCG = getCG(configuration, motors);
double totalInertia = 0;
// Stages
for (int stage : configuration.getActiveStages()) {
Coordinate stageCG = cgCache[stage];
totalInertia += (longitudinalInertiaCache[stage] +
stageCG.weight * MathUtil.pow2(stageCG.x - totalCG.x));
}
// Motors
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);
double inertia = motor.getLongitudinalInertia();
totalInertia += inertia + cg.weight * MathUtil.pow2(cg.x - totalCG.x);
}
}
}
return totalInertia;
}
/**
* Compute the rotational inertia of the provided configuration with specified motors.
*
* @param configuration the rocket configuration
* @param configuration the current motor instance configuration
* @param motors the motor configuration
* @return the rotational inertia of the configuration
*/
public double getRotationalInertia(Configuration configuration, MotorInstanceConfiguration motors);
public double getRotationalInertia(Configuration configuration, MotorInstanceConfiguration motors) {
checkCache(configuration);
calculateStageCache(configuration);
final Coordinate totalCG = getCG(configuration, motors);
double totalInertia = 0;
// Stages
for (int stage : configuration.getActiveStages()) {
Coordinate stageCG = cgCache[stage];
totalInertia += (rotationalInertiaCache[stage] +
stageCG.weight * (MathUtil.pow2(stageCG.y - totalCG.y) +
MathUtil.pow2(stageCG.z - totalCG.z)));
}
// Motors
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);
double inertia = motor.getRotationalInertia();
totalInertia += inertia + cg.weight * (MathUtil.pow2(cg.y - totalCG.y) +
MathUtil.pow2(cg.z - totalCG.z));
}
}
}
return totalInertia;
}
/**
* Return the total mass of the motors
@ -77,7 +236,18 @@ public interface MassCalculator extends Monitorable {
* @param configuration the current motor instance configuration
* @return the total mass of all motors
*/
public double getPropellantMass(Configuration configuration, MotorInstanceConfiguration motors);
public double getPropellantMass(Configuration configuration, MotorInstanceConfiguration motors) {
double mass = 0;
// 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;
}
}
return mass;
}
/**
* Compute an analysis of the per-component CG's of the provided configuration.
@ -90,7 +260,175 @@ public interface MassCalculator extends Monitorable {
* @param type the state of the motors (none, launch mass, burnout mass)
* @return a map from each rocket component to its corresponding CG.
*/
public Map<RocketComponent, Coordinate> getCGAnalysis(Configuration configuration, MassCalcType type);
public Map<RocketComponent, Coordinate> getCGAnalysis(Configuration configuration, MassCalcType type) {
checkCache(configuration);
calculateStageCache(configuration);
Map<RocketComponent, Coordinate> map = new HashMap<RocketComponent, Coordinate>();
for (RocketComponent c : configuration) {
Coordinate[] cgs = c.toAbsolute(c.getCG());
Coordinate totalCG = Coordinate.NUL;
for (Coordinate cg : cgs) {
totalCG = totalCG.average(cg);
}
map.put(c, totalCG);
}
map.put(configuration.getRocket(), getCG(configuration, type));
return map;
}
//////// Cache computations ////////
private void calculateStageCache(Configuration config) {
if (cgCache == null) {
ArrayList<AxialStage> stageList = config.getRocket().getStageList();
int stageCount = stageList.size();
cgCache = new Coordinate[stageCount];
longitudinalInertiaCache = new double[stageCount];
rotationalInertiaCache = new double[stageCount];
for (int i = 0; i < stageCount; i++) {
RocketComponent stage = stageList.get(i);
MassData data = calculateAssemblyMassData(stage);
cgCache[i] = stage.toAbsolute(data.getCG())[0];
longitudinalInertiaCache[i] = data.getLongitudinalInertia();
rotationalInertiaCache[i] = data.getRotationalInertia();
}
}
}
/**
* Returns the mass and inertia data for this component and all subcomponents.
* The inertia is returned relative to the CG, and the CG is in the coordinates
* of the specified component, not global coordinates.
*/
private MassData calculateAssemblyMassData(RocketComponent parent) {
Coordinate parentCG = Coordinate.ZERO;
double longitudinalInertia = 0.0;
double rotationalInertia = 0.0;
// Calculate data for this component
parentCG = parent.getComponentCG();
if (parentCG.weight < MIN_MASS)
parentCG = parentCG.setWeight(MIN_MASS);
// Override only this component's data
if (!parent.getOverrideSubcomponents()) {
if (parent.isMassOverridden())
parentCG = parentCG.setWeight(MathUtil.max(parent.getOverrideMass(), MIN_MASS));
if (parent.isCGOverridden())
parentCG = parentCG.setXYZ(parent.getOverrideCG());
}
longitudinalInertia = parent.getLongitudinalUnitInertia() * parentCG.weight;
rotationalInertia = parent.getRotationalUnitInertia() * parentCG.weight;
// Combine data for subcomponents
for (RocketComponent sibling : parent.getChildren()) {
Coordinate combinedCG;
double dx2, dr2;
// Compute data of sibling
MassData siblingData = calculateAssemblyMassData(sibling);
Coordinate[] siblingCGs = sibling.toRelative(siblingData.getCG(), parent);
for (Coordinate siblingCG : siblingCGs) {
// Compute CG of this + sibling
combinedCG = parentCG.average(siblingCG);
// Add effect of this CG change to parent inertia
dx2 = pow2(parentCG.x - combinedCG.x);
longitudinalInertia += parentCG.weight * dx2;
dr2 = pow2(parentCG.y - combinedCG.y) + pow2(parentCG.z - combinedCG.z);
rotationalInertia += parentCG.weight * dr2;
// Add inertia of sibling
longitudinalInertia += siblingData.getLongitudinalInertia();
rotationalInertia += siblingData.getRotationalInertia();
// Add effect of sibling CG change
dx2 = pow2(siblingData.getCG().x - combinedCG.x);
longitudinalInertia += siblingData.getCG().weight * dx2;
dr2 = pow2(siblingData.getCG().y - combinedCG.y) + pow2(siblingData.getCG().z - combinedCG.z);
rotationalInertia += siblingData.getCG().weight * dr2;
// Set combined CG
parentCG = combinedCG;
}
}
// Override total data
if (parent.getOverrideSubcomponents()) {
if (parent.isMassOverridden()) {
double oldMass = parentCG.weight;
double newMass = MathUtil.max(parent.getOverrideMass(), MIN_MASS);
longitudinalInertia = longitudinalInertia * newMass / oldMass;
rotationalInertia = rotationalInertia * newMass / oldMass;
parentCG = parentCG.setWeight(newMass);
}
if (parent.isCGOverridden()) {
double oldx = parentCG.x;
double newx = parent.getOverrideCGX();
longitudinalInertia += parentCG.weight * pow2(oldx - newx);
parentCG = parentCG.setX(newx);
}
}
MassData parentData = new MassData(parentCG, longitudinalInertia, rotationalInertia, 0);
return parentData;
}
/**
* Check the current cache consistency. This method must be called by all
* methods that may use any cached data before any other operations are
* performed. If the rocket has changed since the previous call to
* <code>checkCache()</code>, then {@link #voidMassCache()} is called.
* <p>
* This method performs the checking based on the rocket's modification IDs,
* so that these method may be called from listeners of the rocket itself.
*
* @param configuration the configuration of the current call
*/
protected final void checkCache(Configuration configuration) {
if (rocketMassModID != configuration.getRocket().getMassModID() ||
rocketTreeModID != configuration.getRocket().getTreeModID()) {
rocketMassModID = configuration.getRocket().getMassModID();
rocketTreeModID = configuration.getRocket().getTreeModID();
log.debug("Voiding the mass cache");
voidMassCache();
}
}
/**
* Void cached mass data. This method is called whenever a change occurs in
* the rocket structure that affects the mass of the rocket and when a new
* Rocket is used. This method must be overridden to void any cached data
* necessary. The method must call <code>super.voidMassCache()</code> during
* its execution.
*/
protected void voidMassCache() {
this.cgCache = null;
this.longitudinalInertiaCache = null;
this.rotationalInertiaCache = null;
}
@Override
public int getModID() {
return 0;
}
}

View File

@ -4,7 +4,6 @@ import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
import net.sf.openrocket.aerodynamics.FlightConditions;
import net.sf.openrocket.document.Simulation;
import net.sf.openrocket.masscalc.BasicMassCalculator;
import net.sf.openrocket.masscalc.MassCalculator;
import net.sf.openrocket.masscalc.MassCalculator.MassCalcType;
import net.sf.openrocket.optimization.rocketoptimization.SimulationDomain;
@ -50,8 +49,8 @@ public class StabilityDomain implements SimulationDomain {
}
@Override
public Pair<Double, Value> getDistanceToDomain(Simulation simulation) {
Coordinate cp, cg;
@ -64,9 +63,9 @@ public class StabilityDomain implements SimulationDomain {
* Caching would in any case be inefficient since the rocket changes all the time.
*/
AerodynamicCalculator aerodynamicCalculator = new BarrowmanCalculator();
MassCalculator massCalculator = new BasicMassCalculator();
MassCalculator massCalculator = new MassCalculator();
Configuration configuration = simulation.getConfiguration();
FlightConditions conditions = new FlightConditions(configuration);
conditions.setMach(Application.getPreferences().getDefaultMach());
@ -87,7 +86,7 @@ public class StabilityDomain implements SimulationDomain {
else
cgx = Double.NaN;
// Calculate the reference (absolute or relative)
absolute = cpx - cgx;
@ -101,7 +100,7 @@ public class StabilityDomain implements SimulationDomain {
}
relative = absolute / diameter;
Value desc;
if (minAbsolute && maxAbsolute) {
desc = new Value(absolute, UnitGroup.UNITS_LENGTH);

View File

@ -1,14 +1,10 @@
package net.sf.openrocket.optimization.rocketoptimization.parameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
import net.sf.openrocket.aerodynamics.FlightConditions;
import net.sf.openrocket.document.Simulation;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.masscalc.BasicMassCalculator;
import net.sf.openrocket.masscalc.MassCalculator;
import net.sf.openrocket.masscalc.MassCalculator.MassCalcType;
import net.sf.openrocket.optimization.general.OptimizationException;
@ -21,6 +17,9 @@ import net.sf.openrocket.unit.UnitGroup;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.MathUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An optimization parameter that computes either the absolute or relative stability of a rocket.
*
@ -31,7 +30,7 @@ public class StabilityParameter implements OptimizableParameter {
private static final Logger log = LoggerFactory.getLogger(StabilityParameter.class);
private static final Translator trans = Application.getTranslator();
private final boolean absolute;
public StabilityParameter(boolean absolute) {
@ -57,9 +56,9 @@ public class StabilityParameter implements OptimizableParameter {
* Caching would in any case be inefficient since the rocket changes all the time.
*/
AerodynamicCalculator aerodynamicCalculator = new BarrowmanCalculator();
MassCalculator massCalculator = new BasicMassCalculator();
MassCalculator massCalculator = new MassCalculator();
Configuration configuration = simulation.getConfiguration();
FlightConditions conditions = new FlightConditions(configuration);
conditions.setMach(Application.getPreferences().getDefaultMach());
@ -79,7 +78,7 @@ public class StabilityParameter implements OptimizableParameter {
else
cgx = Double.NaN;
// Calculate the reference (absolute or relative)
stability = cpx - cgx;

View File

@ -2,13 +2,12 @@ package net.sf.openrocket.rocketcomponent;
import java.util.Collection;
import net.sf.openrocket.masscalc.BasicMassCalculator;
import net.sf.openrocket.masscalc.MassCalculator;
import net.sf.openrocket.masscalc.MassCalculator.MassCalcType;
import net.sf.openrocket.util.Coordinate;
public abstract class RocketUtils {
public static double getLength(Rocket rocket) {
double length = 0;
Collection<Coordinate> bounds = rocket.getDefaultConfiguration().getBounds();
@ -24,9 +23,9 @@ public abstract class RocketUtils {
}
return length;
}
public static Coordinate getCG(Rocket rocket, MassCalcType calcType) {
MassCalculator massCalculator = new BasicMassCalculator();
MassCalculator massCalculator = new MassCalculator();
Coordinate cg = massCalculator.getCG(rocket.getDefaultConfiguration(), calcType);
return cg;
}

View File

@ -8,7 +8,7 @@ import java.util.Random;
import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
import net.sf.openrocket.formatting.MotorDescriptionSubstitutor;
import net.sf.openrocket.masscalc.BasicMassCalculator;
import net.sf.openrocket.masscalc.MassCalculator;
import net.sf.openrocket.models.atmosphere.AtmosphericModel;
import net.sf.openrocket.models.atmosphere.ExtendedISAModel;
import net.sf.openrocket.models.gravity.GravityModel;
@ -37,6 +37,7 @@ import org.slf4j.LoggerFactory;
*/
public class SimulationOptions implements ChangeSource, Cloneable {
@SuppressWarnings("unused")
private static final Logger log = LoggerFactory.getLogger(SimulationOptions.class);
public static final double MAX_LAUNCH_ROD_ANGLE = Math.PI / 3;
@ -638,7 +639,7 @@ public class SimulationOptions implements ChangeSource, Cloneable {
conditions.setGravityModel(gravityModel);
conditions.setAerodynamicCalculator(new BarrowmanCalculator());
conditions.setMassCalculator(new BasicMassCalculator());
conditions.setMassCalculator(new MassCalculator());
conditions.setTimeStep(getTimeStep());
conditions.setMaximumAngleStep(getMaximumStepAngle());

View File

@ -54,7 +54,6 @@ import net.sf.openrocket.gui.components.UnitSelector;
import net.sf.openrocket.gui.scalefigure.RocketPanel;
import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.masscalc.BasicMassCalculator;
import net.sf.openrocket.masscalc.MassCalculator;
import net.sf.openrocket.masscalc.MassCalculator.MassCalcType;
import net.sf.openrocket.rocketcomponent.Configuration;
@ -69,7 +68,7 @@ import net.sf.openrocket.util.MathUtil;
import net.sf.openrocket.util.StateChangeListener;
public class ComponentAnalysisDialog extends JDialog implements StateChangeListener {
private static final long serialVersionUID = 9131240570600307935L;
private static ComponentAnalysisDialog singletonDialog = null;
private static final Translator trans = Application.getTranslator();
@ -80,7 +79,7 @@ public class ComponentAnalysisDialog extends JDialog implements StateChangeListe
private final JToggleButton worstToggle;
private boolean fakeChange = false;
private AerodynamicCalculator aerodynamicCalculator;
private final MassCalculator massCalculator = new BasicMassCalculator();
private final MassCalculator massCalculator = new MassCalculator();
private final ColumnTableModel cpTableModel;
private final ColumnTableModel dragTableModel;

View File

@ -13,7 +13,6 @@ import net.sf.openrocket.formatting.RocketDescriptor;
import net.sf.openrocket.gui.figureelements.FigureElement;
import net.sf.openrocket.gui.figureelements.RocketInfo;
import net.sf.openrocket.gui.scalefigure.RocketPanel;
import net.sf.openrocket.masscalc.BasicMassCalculator;
import net.sf.openrocket.masscalc.MassCalculator;
import net.sf.openrocket.masscalc.MassCalculator.MassCalcType;
import net.sf.openrocket.motor.Motor;
@ -325,7 +324,7 @@ public class DesignReport {
DecimalFormat ttwFormat = new DecimalFormat("0.00");
MassCalculator massCalc = new BasicMassCalculator();
MassCalculator massCalc = new MassCalculator();
Configuration config = new Configuration(rocket);
config.setFlightConfigurationID(motorId);

View File

@ -54,7 +54,6 @@ import net.sf.openrocket.gui.main.componenttree.ComponentTreeModel;
import net.sf.openrocket.gui.simulation.SimulationWorker;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.masscalc.BasicMassCalculator;
import net.sf.openrocket.masscalc.MassCalculator;
import net.sf.openrocket.masscalc.MassCalculator.MassCalcType;
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
@ -184,7 +183,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
// TODO: FUTURE: calculator selection
aerodynamicCalculator = new BarrowmanCalculator();
massCalculator = new BasicMassCalculator();
massCalculator = new MassCalculator();
// Create figure and custom scroll pane
figure = new RocketFigure(configuration);