Merge pull request #676 from teyrana/509-fix-component-analysis
[fixes #509] Fix Component Analysis Dialog
This commit is contained in:
commit
8c129dcc10
@ -700,9 +700,10 @@ componentanalysisdlg.lbl.machnumber = Mach number:
|
|||||||
componentanalysisdlg.lbl.rollrate = Roll rate:
|
componentanalysisdlg.lbl.rollrate = Roll rate:
|
||||||
componentanalysisdlg.lbl.activestages = Active stages:
|
componentanalysisdlg.lbl.activestages = Active stages:
|
||||||
componentanalysisdlg.lbl.motorconf = Motor configuration:
|
componentanalysisdlg.lbl.motorconf = Motor configuration:
|
||||||
componentanalysisdlg.TabStability.Col = Component
|
componentanalysisdlg.TabStability.Col = Component Name
|
||||||
componentanalysisdlg.TabStability.Col.CG = CG
|
componentanalysisdlg.TabStability.Col.EachMass = Instance Mass
|
||||||
componentanalysisdlg.TabStability.Col.Mass = Mass
|
componentanalysisdlg.TabStability.Col.AllMass = Aggregate Mass
|
||||||
|
componentanalysisdlg.TabStability.Col.CG = Aggregate CG Location
|
||||||
componentanalysisdlg.TabStability.Col.CP = CP
|
componentanalysisdlg.TabStability.Col.CP = CP
|
||||||
componentanalysisdlg.TabStability = Stability
|
componentanalysisdlg.TabStability = Stability
|
||||||
componentanalysisdlg.TabStability.ttip = Stability information
|
componentanalysisdlg.TabStability.ttip = Stability information
|
||||||
|
@ -2,14 +2,7 @@ package net.sf.openrocket.aerodynamics;
|
|||||||
|
|
||||||
import static net.sf.openrocket.util.MathUtil.pow2;
|
import static net.sf.openrocket.util.MathUtil.pow2;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Queue;
|
|
||||||
|
|
||||||
import net.sf.openrocket.aerodynamics.barrowman.FinSetCalc;
|
import net.sf.openrocket.aerodynamics.barrowman.FinSetCalc;
|
||||||
import net.sf.openrocket.aerodynamics.barrowman.RocketComponentCalc;
|
import net.sf.openrocket.aerodynamics.barrowman.RocketComponentCalc;
|
||||||
@ -27,7 +20,7 @@ import net.sf.openrocket.util.Coordinate;
|
|||||||
import net.sf.openrocket.util.MathUtil;
|
import net.sf.openrocket.util.MathUtil;
|
||||||
import net.sf.openrocket.util.PolyInterpolator;
|
import net.sf.openrocket.util.PolyInterpolator;
|
||||||
import net.sf.openrocket.util.Reflection;
|
import net.sf.openrocket.util.Reflection;
|
||||||
import net.sf.openrocket.util.Transformation;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An aerodynamic calculator that uses the extended Barrowman method to
|
* An aerodynamic calculator that uses the extended Barrowman method to
|
||||||
@ -64,7 +57,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
public Coordinate getCP(FlightConfiguration configuration, FlightConditions conditions,
|
public Coordinate getCP(FlightConfiguration configuration, FlightConditions conditions,
|
||||||
WarningSet warnings) {
|
WarningSet warnings) {
|
||||||
checkCache(configuration);
|
checkCache(configuration);
|
||||||
AerodynamicForces forces = calculateNonAxialForces(configuration, conditions, null, warnings);
|
AerodynamicForces forces = calculateNonAxialForces(configuration, conditions, warnings);
|
||||||
return forces.getCP();
|
return forces.getCP();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,60 +65,102 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<RocketComponent, AerodynamicForces> getForceAnalysis(FlightConfiguration configuration,
|
public Map<RocketComponent, AerodynamicForces> getForceAnalysis(FlightConfiguration configuration,
|
||||||
FlightConditions conditions, WarningSet warnings) {
|
FlightConditions conditions,
|
||||||
checkCache(configuration);
|
WarningSet warnings) {
|
||||||
|
if (calcMap == null){
|
||||||
AerodynamicForces f;
|
buildCalcMap(configuration);
|
||||||
Map<RocketComponent, AerodynamicForces> map =
|
|
||||||
new LinkedHashMap<RocketComponent, AerodynamicForces>();
|
|
||||||
|
|
||||||
// Add all components to the map
|
|
||||||
for (RocketComponent component : configuration.getActiveComponents()) {
|
|
||||||
|
|
||||||
// Skip non-aerodynamic components
|
|
||||||
if (!component.isAerodynamic())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
f = new AerodynamicForces();
|
|
||||||
f.setComponent(component);
|
|
||||||
|
|
||||||
map.put(component, f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InstanceMap instMap = configuration.getActiveInstances();
|
||||||
|
Map<RocketComponent, AerodynamicForces> eachMap = new LinkedHashMap<>();
|
||||||
|
Map<RocketComponent, AerodynamicForces> assemblyMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
// Calculate non-axial force data
|
// Calculate non-axial force data
|
||||||
AerodynamicForces total = calculateNonAxialForces(configuration, conditions, map, warnings);
|
calculateForceAnalysis(conditions, configuration.getRocket(), instMap, eachMap, assemblyMap, warnings);
|
||||||
|
|
||||||
|
|
||||||
// Calculate friction data
|
// Calculate friction data
|
||||||
total.setFrictionCD(calculateFrictionDrag(configuration, conditions, map, warnings));
|
AerodynamicForces rocketForces = assemblyMap.get(configuration.getRocket());
|
||||||
total.setPressureCD(calculatePressureDrag(configuration, conditions, map, warnings));
|
rocketForces.setFrictionCD(calculateFrictionDrag(configuration, conditions, eachMap, warnings));
|
||||||
total.setBaseCD(calculateBaseDrag(configuration, conditions, map, warnings));
|
rocketForces.setPressureCD(calculatePressureDrag(configuration, conditions, eachMap, warnings));
|
||||||
|
rocketForces.setBaseCD(calculateBaseDrag(configuration, conditions, eachMap, warnings));
|
||||||
total.setComponent(configuration.getRocket());
|
|
||||||
map.put(total.getComponent(), total);
|
Map<RocketComponent, AerodynamicForces> finalMap = new LinkedHashMap<>();
|
||||||
|
for(final RocketComponent comp : instMap.keySet()){
|
||||||
|
|
||||||
for (RocketComponent c : map.keySet()) {
|
AerodynamicForces f;
|
||||||
f = map.get(c);
|
if(comp instanceof ComponentAssembly) {
|
||||||
if (Double.isNaN(f.getBaseCD()) && Double.isNaN(f.getPressureCD()) &&
|
f = assemblyMap.get(comp);
|
||||||
Double.isNaN(f.getFrictionCD()))
|
} else if(comp.isAerodynamic()){
|
||||||
|
f = eachMap.get(comp);
|
||||||
|
}else{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Double.isNaN(f.getCNa())){
|
||||||
|
f.setCNa(0.0);
|
||||||
|
}
|
||||||
|
if (f.getCP().isNaN()) {
|
||||||
|
f.setCP(Coordinate.ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
if (Double.isNaN(f.getBaseCD()))
|
if (Double.isNaN(f.getBaseCD()))
|
||||||
f.setBaseCD(0);
|
f.setBaseCD(0);
|
||||||
|
|
||||||
if (Double.isNaN(f.getPressureCD()))
|
if (Double.isNaN(f.getPressureCD()))
|
||||||
f.setPressureCD(0);
|
f.setPressureCD(0);
|
||||||
|
|
||||||
if (Double.isNaN(f.getFrictionCD()))
|
if (Double.isNaN(f.getFrictionCD()))
|
||||||
f.setFrictionCD(0);
|
f.setFrictionCD(0);
|
||||||
|
|
||||||
f.setCD(f.getBaseCD() + f.getPressureCD() + f.getFrictionCD());
|
f.setCD(f.getBaseCD() + f.getPressureCD() + f.getFrictionCD());
|
||||||
f.setCaxial(calculateAxialDrag(conditions, f.getCD()));
|
f.setCaxial(calculateAxialDrag(conditions, f.getCD()));
|
||||||
|
|
||||||
|
finalMap.put(comp, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
return finalMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AerodynamicForces calculateForceAnalysis( FlightConditions conds,
|
||||||
|
RocketComponent comp,
|
||||||
|
InstanceMap instances,
|
||||||
|
Map<RocketComponent, AerodynamicForces> eachForces,
|
||||||
|
Map<RocketComponent, AerodynamicForces> assemblyForces,
|
||||||
|
WarningSet warnings)
|
||||||
|
{
|
||||||
|
// forces for this component, and all forces below it, in the rocket-tree
|
||||||
|
// => regardless `if(comp isinstance ComponentAssembly)`, or not.
|
||||||
|
AerodynamicForces aggregateForces = new AerodynamicForces().zero();
|
||||||
|
aggregateForces.setComponent(comp);
|
||||||
|
|
||||||
|
// forces for this component, _only_
|
||||||
|
if(comp.isAerodynamic()) {
|
||||||
|
RocketComponentCalc calcObj = calcMap.get(comp);
|
||||||
|
if (null == calcObj) {
|
||||||
|
throw new NullPointerException("Could not find a CalculationObject for aerodynamic Component!: " + comp.getComponentName());
|
||||||
|
} else {
|
||||||
|
List<InstanceContext> contextList = instances.get(comp);
|
||||||
|
// across every instance of this component:
|
||||||
|
AerodynamicForces compForces = calculateComponentNonAxialForces(conds, comp, calcObj, contextList, warnings);
|
||||||
|
eachForces.put(comp, compForces);
|
||||||
|
aggregateForces.merge(compForces);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for( RocketComponent child : comp.getChildren()) {
|
||||||
|
// forces particular to each component
|
||||||
|
AerodynamicForces childForces = calculateForceAnalysis(conds, child, instances, eachForces, assemblyForces, warnings);
|
||||||
|
|
||||||
|
if(null != childForces) {
|
||||||
|
aggregateForces.merge(childForces);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assemblyForces.put(comp, aggregateForces);
|
||||||
|
|
||||||
|
return eachForces.get(comp);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AerodynamicForces getAerodynamicForces(FlightConfiguration configuration,
|
public AerodynamicForces getAerodynamicForces(FlightConfiguration configuration,
|
||||||
FlightConditions conditions, WarningSet warnings) {
|
FlightConditions conditions, WarningSet warnings) {
|
||||||
@ -135,7 +170,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
warnings = ignoreWarningSet;
|
warnings = ignoreWarningSet;
|
||||||
|
|
||||||
// Calculate non-axial force data
|
// Calculate non-axial force data
|
||||||
AerodynamicForces total = calculateNonAxialForces(configuration, conditions, null, warnings);
|
AerodynamicForces total = calculateNonAxialForces(configuration, conditions, warnings);
|
||||||
|
|
||||||
// Calculate friction data
|
// Calculate friction data
|
||||||
total.setFrictionCD(calculateFrictionDrag(configuration, conditions, null, warnings));
|
total.setFrictionCD(calculateFrictionDrag(configuration, conditions, null, warnings));
|
||||||
@ -150,77 +185,79 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
calculateDampingMoments(configuration, conditions, total);
|
calculateDampingMoments(configuration, conditions, total);
|
||||||
total.setCm(total.getCm() - total.getPitchDampingMoment());
|
total.setCm(total.getCm() - total.getPitchDampingMoment());
|
||||||
total.setCyaw(total.getCyaw() - total.getYawDampingMoment());
|
total.setCyaw(total.getCyaw() - total.getYawDampingMoment());
|
||||||
|
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private AerodynamicForces calculateComponentNonAxialForces( FlightConditions conditions,
|
||||||
|
RocketComponent comp,
|
||||||
|
RocketComponentCalc calcObj,
|
||||||
|
List<InstanceContext> contextList,
|
||||||
|
WarningSet warnings)
|
||||||
|
{
|
||||||
|
// across every instance of this component:
|
||||||
|
final AerodynamicForces componentForces = new AerodynamicForces().zero();
|
||||||
|
|
||||||
|
// iterate across component instances
|
||||||
|
for(InstanceContext context: contextList ) {
|
||||||
|
// specific to this _instance_ of this component:
|
||||||
|
AerodynamicForces instanceForces = new AerodynamicForces().zero();
|
||||||
|
calcObj.calculateNonaxialForces(conditions, context.transform, instanceForces, warnings);
|
||||||
|
|
||||||
|
Coordinate cp_inst = instanceForces.getCP();
|
||||||
|
Coordinate cp_abs = context.transform.transform(cp_inst);
|
||||||
|
cp_abs = cp_abs.setY(0.0).setZ(0.0);
|
||||||
|
|
||||||
|
instanceForces.setCP(cp_abs);
|
||||||
|
double CN_instanced = instanceForces.getCN();
|
||||||
|
instanceForces.setCm(CN_instanced * instanceForces.getCP().x / conditions.getRefLength());
|
||||||
|
|
||||||
|
componentForces.merge(instanceForces);
|
||||||
|
}
|
||||||
|
componentForces.setComponent(comp);
|
||||||
|
|
||||||
|
return componentForces;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform the actual CP calculation.
|
* Perform the actual CP calculation.
|
||||||
*/
|
*/
|
||||||
private AerodynamicForces calculateNonAxialForces(FlightConfiguration configuration, FlightConditions conditions,
|
private AerodynamicForces calculateNonAxialForces(FlightConfiguration configuration, FlightConditions conditions, WarningSet warnings) {
|
||||||
Map<RocketComponent, AerodynamicForces> calculators, WarningSet warnings) {
|
|
||||||
|
|
||||||
checkCache(configuration);
|
checkCache(configuration);
|
||||||
|
|
||||||
if (warnings == null)
|
if (warnings == null)
|
||||||
warnings = ignoreWarningSet;
|
warnings = ignoreWarningSet;
|
||||||
|
|
||||||
if (conditions.getAOA() > 17.5 * Math.PI / 180)
|
if (conditions.getAOA() > 17.5 * Math.PI / 180)
|
||||||
warnings.add(new Warning.LargeAOA(conditions.getAOA()));
|
warnings.add(new Warning.LargeAOA(conditions.getAOA()));
|
||||||
|
|
||||||
if (calcMap == null)
|
if (calcMap == null)
|
||||||
buildCalcMap(configuration);
|
buildCalcMap(configuration);
|
||||||
|
|
||||||
|
|
||||||
if( ! isContinuous( configuration.getRocket() ) ){
|
if( ! isContinuous( configuration.getRocket() ) ){
|
||||||
warnings.add( Warning.DIAMETER_DISCONTINUITY);
|
warnings.add( Warning.DIAMETER_DISCONTINUITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
final InstanceMap imap = configuration.getActiveInstances();
|
final InstanceMap imap = configuration.getActiveInstances();
|
||||||
|
|
||||||
|
// across the _entire_ assembly -- like a rocket, or a stage
|
||||||
final AerodynamicForces assemblyForces= new AerodynamicForces().zero();
|
final AerodynamicForces assemblyForces= new AerodynamicForces().zero();
|
||||||
|
|
||||||
// System.err.println("======================================");
|
for(Map.Entry<RocketComponent, ArrayList<InstanceContext>> mapEntry: imap.entrySet() ) {
|
||||||
// System.err.println("==== Iterating through components ====");
|
final RocketComponent comp = mapEntry.getKey();
|
||||||
// iterate through all components
|
final List<InstanceContext> contextList = mapEntry.getValue();
|
||||||
for(Map.Entry<RocketComponent, ArrayList<InstanceContext>> entry: imap.entrySet() ) {
|
|
||||||
final RocketComponent comp = entry.getKey();
|
|
||||||
RocketComponentCalc calcObj = calcMap.get(comp);
|
RocketComponentCalc calcObj = calcMap.get(comp);
|
||||||
|
|
||||||
// System.err.println("comp=" + comp);
|
|
||||||
if (null != calcObj) {
|
if (null != calcObj) {
|
||||||
// iterate across component instances
|
// calculated across all component instances
|
||||||
final ArrayList<InstanceContext> contextList = entry.getValue();
|
final AerodynamicForces componentForces = calculateComponentNonAxialForces(conditions, comp, calcObj, contextList, warnings);
|
||||||
|
|
||||||
for(InstanceContext context: contextList ) {
|
assemblyForces.merge(componentForces);
|
||||||
AerodynamicForces instanceForces = new AerodynamicForces().zero();
|
|
||||||
// System.err.println(String.format("@ [%s]:[%d/%d]", comp.getName(), context.instanceNumber + 1, comp.getInstanceCount()));
|
|
||||||
// System.err.println("_________ inst/ctxt: xrotation: " + context.transform.getXrotation());
|
|
||||||
|
|
||||||
calcObj.calculateNonaxialForces(conditions, context.transform, instanceForces, warnings);
|
|
||||||
|
|
||||||
Coordinate cp_inst = instanceForces.getCP();
|
|
||||||
Coordinate cp_abs = context.transform.transform(cp_inst);
|
|
||||||
cp_abs = cp_abs.setY(0.0).setZ(0.0);
|
|
||||||
|
|
||||||
// if( 1e-6 < cp_inst.weight) {
|
|
||||||
// System.err.println("_________ cp:inst: (rel): " + cp_inst.toString());
|
|
||||||
// System.err.println("_________ cp:inst: (abs): " + cp_abs.toString());
|
|
||||||
// }
|
|
||||||
|
|
||||||
instanceForces.setCP(cp_abs);
|
|
||||||
double CN_instanced = instanceForces.getCN();
|
|
||||||
instanceForces.setCm(CN_instanced * instanceForces.getCP().x / conditions.getRefLength());
|
|
||||||
assemblyForces.merge(instanceForces);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// System.err.println("____ cp:asbly: " + assemblyForces.getCP().toString());
|
|
||||||
return assemblyForces;
|
return assemblyForces;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +267,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean testIsContinuous( final RocketComponent treeRoot ){
|
private boolean testIsContinuous( final RocketComponent treeRoot ){
|
||||||
Queue<RocketComponent> queue = new LinkedList<RocketComponent>();
|
Queue<RocketComponent> queue = new LinkedList<>();
|
||||||
queue.addAll(treeRoot.getChildren());
|
queue.addAll(treeRoot.getChildren());
|
||||||
|
|
||||||
boolean isContinuous = true;
|
boolean isContinuous = true;
|
||||||
@ -279,7 +316,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
* @param conditions Flight conditions taken into account
|
* @param conditions Flight conditions taken into account
|
||||||
* @param map ?
|
* @param map ?
|
||||||
* @param set Set to handle
|
* @param set Set to handle
|
||||||
* @return
|
* @return friction drag for entire rocket
|
||||||
*/
|
*/
|
||||||
private double calculateFrictionDrag(FlightConfiguration configuration, FlightConditions conditions,
|
private double calculateFrictionDrag(FlightConfiguration configuration, FlightConditions conditions,
|
||||||
Map<RocketComponent, AerodynamicForces> map, WarningSet set) {
|
Map<RocketComponent, AerodynamicForces> map, WarningSet set) {
|
||||||
@ -510,12 +547,12 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
*
|
*
|
||||||
* @param configuration Rocket configuration
|
* @param configuration Rocket configuration
|
||||||
* @param conditions Flight conditions taken into account
|
* @param conditions Flight conditions taken into account
|
||||||
* @param map ?
|
* @param forceMap
|
||||||
* @param set Set to handle
|
* @param warningSet all current warnings
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private double calculatePressureDrag(FlightConfiguration configuration, FlightConditions conditions,
|
private double calculatePressureDrag(FlightConfiguration configuration, FlightConditions conditions,
|
||||||
Map<RocketComponent, AerodynamicForces> map, WarningSet warnings) {
|
Map<RocketComponent, AerodynamicForces> forceMap, WarningSet warningSet) {
|
||||||
|
|
||||||
double stagnation, base, total;
|
double stagnation, base, total;
|
||||||
|
|
||||||
@ -538,11 +575,11 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
|
|
||||||
// Pressure fore drag
|
// Pressure fore drag
|
||||||
double cd = calcMap.get(c).calculatePressureDragForce(conditions, stagnation, base,
|
double cd = calcMap.get(c).calculatePressureDragForce(conditions, stagnation, base,
|
||||||
warnings);
|
warningSet);
|
||||||
total += cd;
|
total += cd;
|
||||||
|
|
||||||
if (map != null) {
|
if (forceMap != null) {
|
||||||
map.get(c).setPressureCD(cd);
|
forceMap.get(c).setPressureCD(cd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(c.isCDOverridden())
|
if(c.isCDOverridden())
|
||||||
@ -562,8 +599,8 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
cd = stagnation * area / conditions.getRefArea();
|
cd = stagnation * area / conditions.getRefArea();
|
||||||
total += cd;
|
total += cd;
|
||||||
|
|
||||||
if (map != null) {
|
if (forceMap != null) {
|
||||||
map.get(c).setPressureCD(map.get(c).getPressureCD() + cd);
|
forceMap.get(c).setPressureCD(forceMap.get(c).getPressureCD() + cd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -580,7 +617,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
* @param configuration Rocket configuration
|
* @param configuration Rocket configuration
|
||||||
* @param conditions Flight conditions taken into account
|
* @param conditions Flight conditions taken into account
|
||||||
* @param map ?
|
* @param map ?
|
||||||
* @param set Set to handle
|
* @param warnings all current warnings
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private double calculateBaseDrag(FlightConfiguration configuration, FlightConditions conditions,
|
private double calculateBaseDrag(FlightConfiguration configuration, FlightConditions conditions,
|
||||||
@ -752,10 +789,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
total.setPitchDampingMoment(MathUtil.sign(pitchRate) * pitchDampingMomentMagnitude);
|
total.setPitchDampingMoment(MathUtil.sign(pitchRate) * pitchDampingMomentMagnitude);
|
||||||
total.setYawDampingMoment(MathUtil.sign(yawRate) * yawDampingMomentMagnitude);
|
total.setYawDampingMoment(MathUtil.sign(yawRate) * yawDampingMomentMagnitude);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: MEDIUM: Are the rotation etc. being added correctly? sin/cos theta?
|
|
||||||
|
|
||||||
|
|
||||||
private double getDampingMultiplier(FlightConfiguration configuration, FlightConditions conditions,
|
private double getDampingMultiplier(FlightConfiguration configuration, FlightConditions conditions,
|
||||||
double cgx) {
|
double cgx) {
|
||||||
if (cacheDiameter < 0) {
|
if (cacheDiameter < 0) {
|
||||||
@ -811,18 +845,15 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
|
|
||||||
|
|
||||||
private void buildCalcMap(FlightConfiguration configuration) {
|
private void buildCalcMap(FlightConfiguration configuration) {
|
||||||
Iterator<RocketComponent> iterator;
|
calcMap = new HashMap<>();
|
||||||
|
|
||||||
calcMap = new HashMap<RocketComponent, RocketComponentCalc>();
|
|
||||||
|
|
||||||
|
// because this is not a per-instance iteration... this usage of 'getActiveComponents' is probably fine.
|
||||||
for (RocketComponent comp: configuration.getActiveComponents()) {
|
for (RocketComponent comp: configuration.getActiveComponents()) {
|
||||||
if (!comp.isAerodynamic())
|
if (!comp.isAerodynamic())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
RocketComponentCalc calcObj = (RocketComponentCalc) Reflection.construct(BARROWMAN_PACKAGE, comp, BARROWMAN_SUFFIX, comp);
|
RocketComponentCalc calcObj = (RocketComponentCalc) Reflection.construct(BARROWMAN_PACKAGE, comp, BARROWMAN_SUFFIX, comp);
|
||||||
//String isNull = (null==calcObj?"null":"valid");
|
|
||||||
//System.err.println(" >> At component: "+c.getName() +"=="+c.getID()+". CalcObj is "+isNull);
|
|
||||||
|
|
||||||
calcMap.put(comp, calcObj );
|
calcMap.put(comp, calcObj );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
40
core/src/net/sf/openrocket/masscalc/CMAnalysisEntry.java
Normal file
40
core/src/net/sf/openrocket/masscalc/CMAnalysisEntry.java
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package net.sf.openrocket.masscalc;
|
||||||
|
|
||||||
|
import net.sf.openrocket.motor.Motor;
|
||||||
|
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||||
|
import net.sf.openrocket.util.Coordinate;
|
||||||
|
|
||||||
|
public class CMAnalysisEntry {
|
||||||
|
|
||||||
|
public CMAnalysisEntry(final Object _src) {
|
||||||
|
source = _src;
|
||||||
|
if (source instanceof RocketComponent){
|
||||||
|
name = ((RocketComponent)source).getName();
|
||||||
|
}else if( source instanceof Motor ){
|
||||||
|
name = ((Motor) source).getDesignation();
|
||||||
|
}else {
|
||||||
|
name = null;
|
||||||
|
}
|
||||||
|
eachMass = Double.NaN;
|
||||||
|
totalCM = Coordinate.NaN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name;
|
||||||
|
public Object source;
|
||||||
|
public double eachMass;
|
||||||
|
public Coordinate totalCM;
|
||||||
|
|
||||||
|
public void updateEachMass(final double newMass) {
|
||||||
|
if (Double.isNaN(eachMass)) {
|
||||||
|
eachMass = newMass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateAverageCM(final Coordinate newCM) {
|
||||||
|
if (this.totalCM.isNaN()) {
|
||||||
|
this.totalCM = newCM;
|
||||||
|
} else {
|
||||||
|
this.totalCM = totalCM.average(newCM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,11 @@
|
|||||||
package net.sf.openrocket.masscalc;
|
package net.sf.openrocket.masscalc;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import net.sf.openrocket.motor.Motor;
|
import net.sf.openrocket.motor.Motor;
|
||||||
import net.sf.openrocket.motor.MotorConfiguration;
|
import net.sf.openrocket.motor.MotorConfiguration;
|
||||||
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
import net.sf.openrocket.rocketcomponent.*;
|
||||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
|
||||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
|
||||||
import net.sf.openrocket.util.Coordinate;
|
import net.sf.openrocket.util.Coordinate;
|
||||||
import net.sf.openrocket.util.MathUtil;
|
import net.sf.openrocket.util.MathUtil;
|
||||||
import net.sf.openrocket.util.Transformation;
|
import net.sf.openrocket.util.Transformation;
|
||||||
@ -73,8 +72,8 @@ public class MassCalculation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MassCalculation copy( final RocketComponent _root, final Transformation _transform ){
|
public MassCalculation copy( final RocketComponent _root, final Transformation _transform){
|
||||||
return new MassCalculation( this.type, this.config, this.simulationTime, _root, _transform );
|
return new MassCalculation( this.type, this.config, this.simulationTime, _root, _transform, this.analysisMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Coordinate getCM() {
|
public Coordinate getCM() {
|
||||||
@ -110,13 +109,17 @@ public class MassCalculation {
|
|||||||
return (int) (this.centerOfMass.hashCode());
|
return (int) (this.centerOfMass.hashCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
public MassCalculation( final Type _type, final FlightConfiguration _config, final double _time, final RocketComponent _root, final Transformation _transform) {
|
public MassCalculation( final Type _type, final FlightConfiguration _config, final double _time,
|
||||||
|
final RocketComponent _root, final Transformation _transform,
|
||||||
|
Map<Integer, CMAnalysisEntry> _map)
|
||||||
|
{
|
||||||
type = _type;
|
type = _type;
|
||||||
config = _config;
|
config = _config;
|
||||||
simulationTime = _time;
|
simulationTime = _time;
|
||||||
root = _root;
|
root = _root;
|
||||||
transform = _transform;
|
transform = _transform;
|
||||||
|
analysisMap = _map;
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,8 +170,10 @@ public class MassCalculation {
|
|||||||
|
|
||||||
// center-of-mass AND moment-of-inertia data.
|
// center-of-mass AND moment-of-inertia data.
|
||||||
final ArrayList<RigidBody> bodies = new ArrayList<RigidBody>();
|
final ArrayList<RigidBody> bodies = new ArrayList<RigidBody>();
|
||||||
|
|
||||||
String prefix = "";
|
String prefix = "";
|
||||||
|
|
||||||
|
Map<Integer, CMAnalysisEntry> analysisMap;
|
||||||
|
|
||||||
// =========== Private Instance Functions ========================
|
// =========== Private Instance Functions ========================
|
||||||
|
|
||||||
@ -183,8 +188,8 @@ public class MassCalculation {
|
|||||||
if( motorConfig.isEmpty() ){
|
if( motorConfig.isEmpty() ){
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
final double mountXPosition = root.getPosition().x;
|
final double mountXPosition = root.getPosition().x;
|
||||||
|
|
||||||
final int instanceCount = root.getInstanceCount();
|
final int instanceCount = root.getInstanceCount();
|
||||||
@ -210,10 +215,10 @@ public class MassCalculation {
|
|||||||
eachMass = eachMotorMass - eachCasingMass;
|
eachMass = eachMotorMass - eachCasingMass;
|
||||||
eachCMx = (eachMotorCMx*eachMotorMass - eachCasingCMx*eachCasingMass)/eachMass;
|
eachCMx = (eachMotorCMx*eachMotorMass - eachCasingCMx*eachCasingMass)/eachMass;
|
||||||
}
|
}
|
||||||
|
|
||||||
// System.err.println(String.format("%-40s|Motor: %s.... Mass @%f = %.6f", prefix, motorConfig.toDescription(), simulationTime, eachMass ));
|
// System.err.println(String.format("%-40s|Motor: %s.... Mass @%f = %.6f", prefix, motorConfig.toDescription(), simulationTime, eachMass ));
|
||||||
|
|
||||||
|
|
||||||
// coordinates in rocket frame; Ir, It about CoM.
|
// coordinates in rocket frame; Ir, It about CoM.
|
||||||
final Coordinate clusterLocalCM = new Coordinate( mountXPosition + motorXPosition + eachCMx, 0, 0, eachMass*instanceCount);
|
final Coordinate clusterLocalCM = new Coordinate( mountXPosition + motorXPosition + eachCMx, 0, 0, eachMass*instanceCount);
|
||||||
|
|
||||||
@ -232,7 +237,17 @@ public class MassCalculation {
|
|||||||
|
|
||||||
final Coordinate clusterCM = transform.transform( clusterLocalCM );
|
final Coordinate clusterCM = transform.transform( clusterLocalCM );
|
||||||
addMass( clusterCM );
|
addMass( clusterCM );
|
||||||
|
|
||||||
|
if(null != this.analysisMap) {
|
||||||
|
CMAnalysisEntry entry = analysisMap.get(motor.getDesignation());
|
||||||
|
if (null == entry){
|
||||||
|
entry = new CMAnalysisEntry(motor);
|
||||||
|
analysisMap.put(motor.getDesignation().hashCode(), entry);
|
||||||
|
}
|
||||||
|
entry.updateEachMass(eachMass);
|
||||||
|
entry.updateAverageCM(clusterCM);
|
||||||
|
}
|
||||||
|
|
||||||
RigidBody clusterMOI = new RigidBody( clusterCM, clusterIr, clusterIt, clusterIt );
|
RigidBody clusterMOI = new RigidBody( clusterCM, clusterIr, clusterIt, clusterIt );
|
||||||
addInertia( clusterMOI );
|
addInertia( clusterMOI );
|
||||||
|
|
||||||
@ -273,7 +288,14 @@ public class MassCalculation {
|
|||||||
// if( this.config.isComponentActive(component) ){
|
// if( this.config.isComponentActive(component) ){
|
||||||
// System.err.println(String.format( "%s>>[%s]....", prefix, component.getName()));
|
// System.err.println(String.format( "%s>>[%s]....", prefix, component.getName()));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
if(null != analysisMap) {
|
||||||
|
if (this.config.isComponentActive(component) && (! analysisMap.containsKey(component.hashCode()))){
|
||||||
|
CMAnalysisEntry entry = new CMAnalysisEntry(component);
|
||||||
|
analysisMap.put(component.hashCode(), entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// iterate over the aggregated instances for the whole tree.
|
// iterate over the aggregated instances for the whole tree.
|
||||||
MassCalculation children = this.copy(component, parentTransform );
|
MassCalculation children = this.copy(component, parentTransform );
|
||||||
for( int currentInstanceNumber = 0; currentInstanceNumber < instanceCount; ++currentInstanceNumber) {
|
for( int currentInstanceNumber = 0; currentInstanceNumber < instanceCount; ++currentInstanceNumber) {
|
||||||
@ -288,14 +310,14 @@ public class MassCalculation {
|
|||||||
|
|
||||||
for (RocketComponent child : component.getChildren()) {
|
for (RocketComponent child : component.getChildren()) {
|
||||||
// child data, relative to rocket reference frame
|
// child data, relative to rocket reference frame
|
||||||
MassCalculation eachChild = copy( child, currentTransform);
|
MassCalculation eachChild = copy(child, currentTransform);
|
||||||
|
|
||||||
eachChild.prefix = prefix + "....";
|
eachChild.prefix = prefix + "....";
|
||||||
eachChild.calculateStructure();
|
eachChild.calculateStructure();
|
||||||
|
|
||||||
// accumulate children's data
|
// accumulate children's data
|
||||||
children.merge( eachChild );
|
children.merge( eachChild );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( MIN_MASS < children.getMass() ) {
|
if( MIN_MASS < children.getMass() ) {
|
||||||
@ -320,6 +342,20 @@ public class MassCalculation {
|
|||||||
// mass data for *this component only* in the rocket-frame
|
// mass data for *this component only* in the rocket-frame
|
||||||
compCM = parentTransform.transform( compCM.add(component.getPosition()) );
|
compCM = parentTransform.transform( compCM.add(component.getPosition()) );
|
||||||
this.addMass( compCM );
|
this.addMass( compCM );
|
||||||
|
|
||||||
|
if(null != analysisMap){
|
||||||
|
if( component instanceof ComponentAssembly) {
|
||||||
|
// For ComponentAssemblies, record the _assembly_ information
|
||||||
|
CMAnalysisEntry entry = analysisMap.get(component.hashCode());
|
||||||
|
entry.updateEachMass(children.getMass() / component.getInstanceCount());
|
||||||
|
entry.updateAverageCM(this.centerOfMass);
|
||||||
|
}else{
|
||||||
|
// For actual components, record the mass of the component, and disregard children
|
||||||
|
CMAnalysisEntry entry = analysisMap.get(component.hashCode());
|
||||||
|
entry.updateEachMass(compCM.weight);
|
||||||
|
entry.updateAverageCM(compCM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
double compIx = component.getRotationalUnitInertia() * compCM.weight;
|
double compIx = component.getRotationalUnitInertia() * compCM.weight;
|
||||||
double compIt = component.getLongitudinalUnitInertia() * compCM.weight;
|
double compIt = component.getLongitudinalUnitInertia() * compCM.weight;
|
||||||
@ -331,7 +367,7 @@ public class MassCalculation {
|
|||||||
// System.err.println(String.format( "%s....componentData: %s", prefix, compCM.toPreciseString() ));
|
// System.err.println(String.format( "%s....componentData: %s", prefix, compCM.toPreciseString() ));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (component.getOverrideSubcomponents()) {
|
if (component.getOverrideSubcomponents()) {
|
||||||
if (component.isMassOverridden()) {
|
if (component.isMassOverridden()) {
|
||||||
double newMass = MathUtil.max(component.getOverrideMass(), MIN_MASS);
|
double newMass = MathUtil.max(component.getOverrideMass(), MIN_MASS);
|
||||||
Coordinate newCM = this.getCM().setWeight( newMass );
|
Coordinate newCM = this.getCM().setWeight( newMass );
|
||||||
@ -355,29 +391,29 @@ public class MassCalculation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MassCalculation calculateMotors() {
|
MassCalculation calculateMotors() {
|
||||||
|
|
||||||
final RocketComponent component = this.root;
|
final RocketComponent component = this.root;
|
||||||
final Transformation parentTransform = this.transform;
|
final Transformation parentTransform = this.transform;
|
||||||
|
|
||||||
final int instanceCount = component.getInstanceCount();
|
final int instanceCount = component.getInstanceCount();
|
||||||
Coordinate[] instanceLocations = component.getInstanceLocations();
|
Coordinate[] instanceLocations = component.getInstanceLocations();
|
||||||
|
|
||||||
// // vvv DEBUG
|
// // vvv DEBUG
|
||||||
// if( this.config.isComponentActive(component) ){
|
// if( this.config.isComponentActive(component) ){
|
||||||
// System.err.println(String.format( "%s[%s]....", prefix, component.getName()));
|
// System.err.println(String.format( "%s[%s]....", prefix, component.getName()));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (component.isMotorMount()) {
|
if (component.isMotorMount()) {
|
||||||
MassCalculation propellant = this.copy(component, parentTransform);
|
MassCalculation propellant = this.copy(component, parentTransform);
|
||||||
|
|
||||||
propellant.calculateMountData();
|
propellant.calculateMountData();
|
||||||
|
|
||||||
this.merge( propellant );
|
this.merge( propellant );
|
||||||
|
|
||||||
// // vvv DEBUG
|
// // vvv DEBUG
|
||||||
// if( 0 < propellant.getMass() ) {
|
// if( 0 < propellant.getMass() ) {
|
||||||
// System.err.println(String.format( "%s........++ propellantData: %s", prefix, propellant.toCMDebug()));
|
// System.err.println(String.format( "%s........++ propellantData: %s", prefix, propellant.toCMDebug()));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate over the aggregated instances for the whole tree.
|
// iterate over the aggregated instances for the whole tree.
|
||||||
@ -395,7 +431,7 @@ public class MassCalculation {
|
|||||||
|
|
||||||
// accumulate children's data
|
// accumulate children's data
|
||||||
children.merge( eachChild );
|
children.merge( eachChild );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( MIN_MASS < children.getMass() ) {
|
if( MIN_MASS < children.getMass() ) {
|
||||||
@ -407,7 +443,7 @@ public class MassCalculation {
|
|||||||
// if( this.config.isComponentActive(component) && 0 < this.getMass() ) {
|
// if( this.config.isComponentActive(component) && 0 < this.getMass() ) {
|
||||||
// System.err.println(String.format( "%s....<< return assemblyData: %s (tree @%s)", prefix, this.toCMDebug(), component.getName() ));
|
// System.err.println(String.format( "%s....<< return assemblyData: %s (tree @%s)", prefix, this.toCMDebug(), component.getName() ));
|
||||||
// }
|
// }
|
||||||
// ^^^ DEBUG
|
// // ^^^ DEBUG
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -427,9 +463,8 @@ public class MassCalculation {
|
|||||||
It += eachGlobal.Iyy;
|
It += eachGlobal.Iyy;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RigidBody( centerOfMass, Ir, It, It );
|
return new RigidBody( centerOfMass, Ir, It, It );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,10 +7,7 @@ import net.sf.openrocket.motor.Motor;
|
|||||||
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
||||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||||
import net.sf.openrocket.simulation.SimulationStatus;
|
import net.sf.openrocket.simulation.SimulationStatus;
|
||||||
import net.sf.openrocket.util.Coordinate;
|
import net.sf.openrocket.util.*;
|
||||||
import net.sf.openrocket.util.MathUtil;
|
|
||||||
import net.sf.openrocket.util.Monitorable;
|
|
||||||
import net.sf.openrocket.util.Transformation;
|
|
||||||
|
|
||||||
public class MassCalculator implements Monitorable {
|
public class MassCalculator implements Monitorable {
|
||||||
|
|
||||||
@ -104,7 +101,7 @@ public class MassCalculator implements Monitorable {
|
|||||||
public static RigidBody calculate( final MassCalculation.Type _type, final SimulationStatus status ){
|
public static RigidBody calculate( final MassCalculation.Type _type, final SimulationStatus status ){
|
||||||
final FlightConfiguration config = status.getConfiguration();
|
final FlightConfiguration config = status.getConfiguration();
|
||||||
final double time = status.getSimulationTime();
|
final double time = status.getSimulationTime();
|
||||||
MassCalculation calculation= new MassCalculation( _type, config, time, config.getRocket(), Transformation.IDENTITY);
|
MassCalculation calculation= new MassCalculation( _type, config, time, config.getRocket(), Transformation.IDENTITY, null);
|
||||||
|
|
||||||
calculation.calculateAssembly();
|
calculation.calculateAssembly();
|
||||||
RigidBody result = calculation.calculateMomentOfInertia();
|
RigidBody result = calculation.calculateMomentOfInertia();
|
||||||
@ -112,55 +109,51 @@ public class MassCalculator implements Monitorable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// convenience wrapper -- use this to implicitly create a plain MassCalculation object with common parameters
|
// convenience wrapper -- use this to implicitly create a plain MassCalculation object with common parameters
|
||||||
public static RigidBody calculate( final MassCalculation.Type _type, final FlightConfiguration _config, double _time ){
|
public static RigidBody calculate( final MassCalculation.Type _type, final FlightConfiguration _config, double _time){
|
||||||
MassCalculation calculation = new MassCalculation( _type, _config, _time, _config.getRocket(), Transformation.IDENTITY);
|
MassCalculation calculation = new MassCalculation( _type, _config, _time, _config.getRocket(), Transformation.IDENTITY, null);
|
||||||
calculation.calculateAssembly();
|
calculation.calculateAssembly();
|
||||||
return calculation.calculateMomentOfInertia();
|
return calculation.calculateMomentOfInertia();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute an analysis of the per-component CG's of the provided configuration.
|
* Compute an analysis of the per-component CG's of the provided configuration.
|
||||||
* The returned map will contain an entry for each physical rocket component (not stages)
|
* The returned map will contain an entry for each physical rocket component (not stages)
|
||||||
* with its corresponding (best-effort) CG. Overriding of subcomponents is ignored.
|
* with its corresponding (best-effort) CG. Overriding of subcomponents is ignored.
|
||||||
* The CG of the entire configuration with motors is stored in the entry with the corresponding
|
* The CG of the entire configuration with motors is stored in the entry with the corresponding
|
||||||
* Rocket as the key.
|
* Rocket as the key.
|
||||||
*
|
*
|
||||||
* Deprecated:
|
* Deprecated:
|
||||||
* This function is fundamentally broken, because it asks for a calculation which ignores instancing.
|
* This function is fundamentally broken, because it asks for a calculation which ignores instancing.
|
||||||
* This function will work with simple rockets, but will be misleading or downright wrong for others.
|
* This function will work with simple rockets, but will be misleading or downright wrong for others.
|
||||||
*
|
*
|
||||||
* This is a problem with using a single-typed map:
|
* This is a problem with using a single-typed map:
|
||||||
* [1] multiple instances of components are not allowed, and must be merged.
|
* [1] multiple instances of components are not allowed, and must be merged.
|
||||||
* [2] propellant / motor data does not have a corresponding RocketComponent.
|
* [2] propellant / motor data does not have a corresponding RocketComponent.
|
||||||
* ( or mount-data collides with motor-data )
|
* ( or mount-data collides with motor-data )
|
||||||
*
|
*
|
||||||
* @param configuration the rocket configuration
|
* @return a list of CG coordinates for every instance of this component
|
||||||
* @return a map from each rocket component to its corresponding CG.
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
public static Map<Integer,CMAnalysisEntry> getCMAnalysis(FlightConfiguration config) {
|
||||||
public Map<RocketComponent, Coordinate> getCGAnalysis(FlightConfiguration configuration) {
|
|
||||||
// revalidateCache(configuration);
|
|
||||||
|
|
||||||
Map<RocketComponent, Coordinate> map = new HashMap<RocketComponent, Coordinate>();
|
|
||||||
|
|
||||||
Coordinate rocketCG = Coordinate.ZERO;
|
|
||||||
for (RocketComponent comp : configuration.getActiveComponents()) {
|
|
||||||
Coordinate[] cgs = comp.toAbsolute(comp.getCG());
|
|
||||||
Coordinate stageCG = Coordinate.NUL;
|
|
||||||
for (Coordinate cg : cgs) {
|
|
||||||
stageCG = stageCG.average(cg);
|
|
||||||
}
|
|
||||||
map.put(comp, stageCG);
|
|
||||||
|
|
||||||
rocketCG.average( stageCG);
|
|
||||||
}
|
|
||||||
|
|
||||||
map.put(configuration.getRocket(), rocketCG );
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Map<Integer,CMAnalysisEntry> analysisMap = new HashMap<>();
|
||||||
|
|
||||||
|
MassCalculation calculation = new MassCalculation(
|
||||||
|
MassCalculation.Type.LAUNCH,
|
||||||
|
config,
|
||||||
|
Motor.PSEUDO_TIME_LAUNCH,
|
||||||
|
config.getRocket(),
|
||||||
|
Transformation.IDENTITY,
|
||||||
|
analysisMap);
|
||||||
|
|
||||||
|
calculation.calculateAssembly();
|
||||||
|
|
||||||
|
CMAnalysisEntry totals = new CMAnalysisEntry(config.getRocket());
|
||||||
|
totals.totalCM = calculation.centerOfMass;
|
||||||
|
totals.eachMass = calculation.centerOfMass.weight;
|
||||||
|
analysisMap.put(config.getRocket().hashCode(), totals);
|
||||||
|
|
||||||
|
return analysisMap;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////// Mass property calculations ///////////////////
|
////////////////// Mass property calculations ///////////////////
|
||||||
@Override
|
@Override
|
||||||
|
@ -202,23 +202,16 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Collection<RocketComponent> getAllComponents() {
|
public Collection<RocketComponent> getAllComponents() {
|
||||||
Queue<RocketComponent> toProcess = new ArrayDeque<RocketComponent>();
|
List<RocketComponent> traversalOrder = new ArrayList<RocketComponent>();
|
||||||
toProcess.offer(this.rocket);
|
recurseAllComponentsDepthFirst(this.rocket,traversalOrder);
|
||||||
|
return traversalOrder;
|
||||||
ArrayList<RocketComponent> toReturn = new ArrayList<>();
|
}
|
||||||
|
|
||||||
while (!toProcess.isEmpty()) {
|
private void recurseAllComponentsDepthFirst(RocketComponent comp, List<RocketComponent> traversalOrder){
|
||||||
RocketComponent comp = toProcess.poll();
|
traversalOrder.add(comp);
|
||||||
|
for( RocketComponent child : comp.getChildren()){
|
||||||
toReturn.add(comp);
|
recurseAllComponentsDepthFirst(child, traversalOrder);
|
||||||
for (RocketComponent child : comp.getChildren()) {
|
|
||||||
if (!(child instanceof AxialStage)) {
|
|
||||||
toProcess.offer(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return toReturn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns all the components on core stages (i.e. centerline)
|
/** Returns all the components on core stages (i.e. centerline)
|
||||||
@ -401,10 +394,10 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateStages() {
|
private void updateStages() {
|
||||||
if (this.rocket.getStageCount() == this.stages.size()) {
|
if (this.rocket.getStageCount() == this.stages.size()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.stages.clear();
|
this.stages.clear();
|
||||||
for (AxialStage curStage : this.rocket.getStageList()) {
|
for (AxialStage curStage : this.rocket.getStageList()) {
|
||||||
|
|
||||||
|
@ -341,12 +341,9 @@ public class BarrowmanCalculatorTest {
|
|||||||
|
|
||||||
final Coordinate cpNoPods = calcNoPods.getCP(configNoPods, conditionsNoPods, warningsNoPods);
|
final Coordinate cpNoPods = calcNoPods.getCP(configNoPods, conditionsNoPods, warningsNoPods);
|
||||||
final Coordinate cpPods = calcPods.getCP(configPods, conditionsPods, warningsPods);
|
final Coordinate cpPods = calcPods.getCP(configPods, conditionsPods, warningsPods);
|
||||||
System.out.printf("with pods %s\n", cpPods.toString());
|
|
||||||
System.out.printf("without pods %s\n", cpNoPods.toString());
|
|
||||||
assertEquals(" Alpha III With Pods rocket cp x value is incorrect:", cpNoPods.x - 0.002788761352, cpPods.x, EPSILON);
|
assertEquals(" Alpha III With Pods rocket cp x value is incorrect:", cpNoPods.x - 0.002788761352, cpPods.x, EPSILON);
|
||||||
assertEquals(" Alpha III With Pods rocket cp y value is incorrect:", cpNoPods.y, cpPods.y, EPSILON);
|
assertEquals(" Alpha III With Pods rocket cp y value is incorrect:", cpNoPods.y, cpPods.y, EPSILON);
|
||||||
assertEquals(" Alpha III With Pods rocket cp z value is incorrect:", cpNoPods.z, cpPods.z, EPSILON);
|
assertEquals(" Alpha III With Pods rocket cp z value is incorrect:", cpNoPods.z, cpPods.z, EPSILON);
|
||||||
assertEquals(" Alpha III With Pods rocket CNa value is incorrect:", cpPods.weight, cpNoPods.weight - 3.91572, EPSILON);
|
assertEquals(" Alpha III With Pods rocket CNa value is incorrect:", cpPods.weight, cpNoPods.weight - 3.91572, EPSILON);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ import java.util.Vector;
|
|||||||
|
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JComboBox;
|
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
@ -54,21 +53,22 @@ import net.sf.openrocket.gui.components.UnitSelector;
|
|||||||
import net.sf.openrocket.gui.scalefigure.RocketPanel;
|
import net.sf.openrocket.gui.scalefigure.RocketPanel;
|
||||||
import net.sf.openrocket.gui.util.GUIUtil;
|
import net.sf.openrocket.gui.util.GUIUtil;
|
||||||
import net.sf.openrocket.l10n.Translator;
|
import net.sf.openrocket.l10n.Translator;
|
||||||
|
import net.sf.openrocket.masscalc.CMAnalysisEntry;
|
||||||
import net.sf.openrocket.masscalc.MassCalculator;
|
import net.sf.openrocket.masscalc.MassCalculator;
|
||||||
import net.sf.openrocket.motor.MotorConfiguration;
|
import net.sf.openrocket.motor.MotorConfiguration;
|
||||||
import net.sf.openrocket.rocketcomponent.AxialStage;
|
import net.sf.openrocket.rocketcomponent.*;
|
||||||
import net.sf.openrocket.rocketcomponent.FinSet;
|
|
||||||
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
|
||||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
|
||||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
|
||||||
import net.sf.openrocket.startup.Application;
|
import net.sf.openrocket.startup.Application;
|
||||||
import net.sf.openrocket.unit.Unit;
|
import net.sf.openrocket.unit.Unit;
|
||||||
import net.sf.openrocket.unit.UnitGroup;
|
import net.sf.openrocket.unit.UnitGroup;
|
||||||
import net.sf.openrocket.util.Coordinate;
|
import net.sf.openrocket.util.Coordinate;
|
||||||
import net.sf.openrocket.util.MathUtil;
|
import net.sf.openrocket.util.MathUtil;
|
||||||
import net.sf.openrocket.util.StateChangeListener;
|
import net.sf.openrocket.util.StateChangeListener;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class ComponentAnalysisDialog extends JDialog implements StateChangeListener {
|
public class ComponentAnalysisDialog extends JDialog implements StateChangeListener {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ComponentAnalysisDialog.class);
|
||||||
|
|
||||||
private static final long serialVersionUID = 9131240570600307935L;
|
private static final long serialVersionUID = 9131240570600307935L;
|
||||||
private static ComponentAnalysisDialog singletonDialog = null;
|
private static ComponentAnalysisDialog singletonDialog = null;
|
||||||
private static final Translator trans = Application.getTranslator();
|
private static final Translator trans = Application.getTranslator();
|
||||||
@ -80,18 +80,16 @@ public class ComponentAnalysisDialog extends JDialog implements StateChangeListe
|
|||||||
private final JToggleButton worstToggle;
|
private final JToggleButton worstToggle;
|
||||||
private boolean fakeChange = false;
|
private boolean fakeChange = false;
|
||||||
private AerodynamicCalculator aerodynamicCalculator;
|
private AerodynamicCalculator aerodynamicCalculator;
|
||||||
private final MassCalculator massCalculator = new MassCalculator();
|
|
||||||
|
|
||||||
private final ColumnTableModel cpTableModel;
|
private final ColumnTableModel longitudeStabilityTableModel;
|
||||||
private final ColumnTableModel dragTableModel;
|
private final ColumnTableModel dragTableModel;
|
||||||
private final ColumnTableModel rollTableModel;
|
private final ColumnTableModel rollTableModel;
|
||||||
|
|
||||||
private final JList<Object> warningList;
|
private final JList<Object> warningList;
|
||||||
|
|
||||||
|
|
||||||
private final List<Object[]> cgData = new ArrayList<Object[]>();
|
private final List<LongitudinalStabilityRow> stabData = new ArrayList<>();
|
||||||
private final List<AerodynamicForces> dragData = new ArrayList<AerodynamicForces>();
|
private final List<AerodynamicForces> dragData = new ArrayList<AerodynamicForces>();
|
||||||
private double totalCD = 0;
|
|
||||||
private final List<AerodynamicForces> rollData = new ArrayList<AerodynamicForces>();
|
private final List<AerodynamicForces> rollData = new ArrayList<AerodynamicForces>();
|
||||||
|
|
||||||
|
|
||||||
@ -186,69 +184,59 @@ public class ComponentAnalysisDialog extends JDialog implements StateChangeListe
|
|||||||
panel.add(tabbedPane, "spanx, growx, growy");
|
panel.add(tabbedPane, "spanx, growx, growy");
|
||||||
|
|
||||||
|
|
||||||
// Create the CP data table
|
// Create the Longitudinal Stability (CM vs CP) data table
|
||||||
cpTableModel = new ColumnTableModel(
|
longitudeStabilityTableModel = new ColumnTableModel(
|
||||||
|
|
||||||
//// Component
|
//// Component
|
||||||
new Column(trans.get("componentanalysisdlg.TabStability.Col.Component")) {
|
new Column(trans.get("componentanalysisdlg.TabStability.Col.Component")) {
|
||||||
@Override
|
@Override
|
||||||
public Object getValueAt(int row) {
|
public Object getValueAt(int row) {
|
||||||
Object c = cgData.get(row)[0];
|
Object c = stabData.get(row).name;
|
||||||
if (c instanceof Rocket) {
|
|
||||||
return trans.get("componentanalysisdlg.TOTAL");
|
|
||||||
}
|
|
||||||
return c.toString();
|
return c.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getDefaultWidth() {
|
public int getDefaultWidth() {
|
||||||
return 200;
|
return 200;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Column(trans.get("componentanalysisdlg.TabStability.Col.CG") + " / " + UnitGroup.UNITS_LENGTH.getDefaultUnit().getUnit()) {
|
// would be per-instance mass
|
||||||
private Unit unit = UnitGroup.UNITS_LENGTH.getDefaultUnit();
|
new Column(trans.get("componentanalysisdlg.TabStability.Col.EachMass") + " (" + UnitGroup.UNITS_MASS.getDefaultUnit().getUnit() + ")") {
|
||||||
|
final private Unit unit = UnitGroup.UNITS_MASS.getDefaultUnit();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getValueAt(int row) {
|
public Object getValueAt(int row) {
|
||||||
Coordinate cg = (Coordinate) cgData.get(row)[1];
|
return unit.toString(stabData.get(row).eachMass);
|
||||||
if ( cg == null ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return unit.toString(cg.x);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Column(trans.get("componentanalysisdlg.TabStability.Col.Mass") + " / " + UnitGroup.UNITS_MASS.getDefaultUnit().getUnit()) {
|
new Column(trans.get("componentanalysisdlg.TabStability.Col.AllMass") + " (" + UnitGroup.UNITS_MASS.getDefaultUnit().getUnit() + ")") {
|
||||||
private Unit unit = UnitGroup.UNITS_MASS.getDefaultUnit();
|
final private Unit unit = UnitGroup.UNITS_MASS.getDefaultUnit();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getValueAt(int row) {
|
public Object getValueAt(int row) {
|
||||||
Coordinate cg = (Coordinate) cgData.get(row)[1];
|
return unit.toString(stabData.get(row).cm.weight);
|
||||||
if ( cg == null ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return unit.toString(cg.weight);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Column(trans.get("componentanalysisdlg.TabStability.Col.CP") + " / " + UnitGroup.UNITS_LENGTH.getDefaultUnit().getUnit()) {
|
new Column(trans.get("componentanalysisdlg.TabStability.Col.CG") + " (" + UnitGroup.UNITS_LENGTH.getDefaultUnit().getUnit() + ")") {
|
||||||
private Unit unit = UnitGroup.UNITS_LENGTH.getDefaultUnit();
|
final private Unit unit = UnitGroup.UNITS_LENGTH.getDefaultUnit();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getValueAt(int row) {
|
public Object getValueAt(int row) {
|
||||||
AerodynamicForces forces = (AerodynamicForces) cgData.get(row)[2];
|
return unit.toString(stabData.get(row).cm.x);
|
||||||
if ( forces == null ) {
|
}
|
||||||
return null;
|
},
|
||||||
}
|
new Column(trans.get("componentanalysisdlg.TabStability.Col.CP") + " (" + UnitGroup.UNITS_LENGTH.getDefaultUnit().getUnit() + ")") {
|
||||||
return unit.toString(forces.getCP().x);
|
final private Unit unit = UnitGroup.UNITS_LENGTH.getDefaultUnit();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValueAt(int row) {
|
||||||
|
return NOUNIT.toString(stabData.get(row).cpx);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Column("<html>C<sub>N<sub>" + ALPHA + "</sub></sub>") {
|
new Column("<html>C<sub>N<sub>" + ALPHA + "</sub></sub>") {
|
||||||
@Override
|
@Override
|
||||||
public Object getValueAt(int row) {
|
public Object getValueAt(int row) {
|
||||||
AerodynamicForces forces = (AerodynamicForces) cgData.get(row)[2];
|
return NOUNIT.toString(stabData.get(row).cna);
|
||||||
if ( forces == null ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return NOUNIT.toString(forces.getCP().weight);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,15 +249,15 @@ public class ComponentAnalysisDialog extends JDialog implements StateChangeListe
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRowCount() {
|
public int getRowCount() {
|
||||||
return cgData.size();
|
return stabData.size();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
table = new ColumnTable(cpTableModel);
|
table = new ColumnTable(longitudeStabilityTableModel);
|
||||||
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||||
table.setSelectionBackground(Color.LIGHT_GRAY);
|
table.setSelectionBackground(Color.LIGHT_GRAY);
|
||||||
table.setSelectionForeground(Color.BLACK);
|
table.setSelectionForeground(Color.BLACK);
|
||||||
cpTableModel.setColumnWidths(table.getColumnModel());
|
longitudeStabilityTableModel.setColumnWidths(table.getColumnModel());
|
||||||
|
|
||||||
table.setDefaultRenderer(Object.class, new CustomCellRenderer());
|
table.setDefaultRenderer(Object.class, new CustomCellRenderer());
|
||||||
// table.setShowHorizontalLines(false);
|
// table.setShowHorizontalLines(false);
|
||||||
@ -425,8 +413,6 @@ public class ComponentAnalysisDialog extends JDialog implements StateChangeListe
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Add the data updater to listen to changes in aoa and theta
|
// Add the data updater to listen to changes in aoa and theta
|
||||||
mach.addChangeListener(this);
|
mach.addChangeListener(this);
|
||||||
theta.addChangeListener(this);
|
theta.addChangeListener(this);
|
||||||
@ -534,80 +520,97 @@ public class ComponentAnalysisDialog extends JDialog implements StateChangeListe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<RocketComponent, AerodynamicForces> aeroData =
|
// key is the comp.hashCode() or motor.getDesignation().hashCode()
|
||||||
aerodynamicCalculator.getForceAnalysis(configuration, conditions, set);
|
Map<Integer, CMAnalysisEntry> cmMap= MassCalculator.getCMAnalysis(configuration);
|
||||||
Map<RocketComponent, Coordinate> massData =
|
|
||||||
massCalculator.getCGAnalysis(configuration);
|
|
||||||
|
|
||||||
|
Map<RocketComponent, AerodynamicForces> aeroData = aerodynamicCalculator.getForceAnalysis(configuration, conditions, set);
|
||||||
|
|
||||||
cgData.clear();
|
stabData.clear();
|
||||||
dragData.clear();
|
dragData.clear();
|
||||||
rollData.clear();
|
rollData.clear();
|
||||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
|
||||||
if ( c instanceof AxialStage ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Object[] data = new Object[3];
|
|
||||||
cgData.add(data);
|
|
||||||
data[0] = c;
|
|
||||||
|
|
||||||
Coordinate cg = massData.get(c);
|
for(final RocketComponent comp: configuration.getAllComponents()) {
|
||||||
data[1] = cg;
|
// // this is actually redundant, because the analysis will not contain inactive stages.
|
||||||
|
// if (!configuration.isComponentActive(comp)) {
|
||||||
forces = aeroData.get(c);
|
// continue;
|
||||||
if (forces == null) {
|
// }
|
||||||
|
|
||||||
|
CMAnalysisEntry cmEntry = cmMap.get(comp.hashCode());
|
||||||
|
if (null == cmEntry) {
|
||||||
|
log.warn("Could not find massData entry for component: " + comp.getName());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (forces.getCP() != null) {
|
|
||||||
data[2] = forces;
|
if ((comp instanceof ComponentAssembly) && !(comp instanceof Rocket)){
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LongitudinalStabilityRow row = new LongitudinalStabilityRow(cmEntry.name, cmEntry.source);
|
||||||
|
stabData.add(row);
|
||||||
|
|
||||||
|
row.source = cmEntry.source;
|
||||||
|
row.eachMass = cmEntry.eachMass;
|
||||||
|
row.cm = cmEntry.totalCM;
|
||||||
|
|
||||||
|
forces = aeroData.get(comp);
|
||||||
|
if (forces == null) {
|
||||||
|
// DEBUG / trace level
|
||||||
|
System.err.println("Could not find aeroData entry for component: " + comp.getName());
|
||||||
|
row.cpx = 0.0;
|
||||||
|
row.cna = 0.0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// System.err.println(String.format(" .CP = %s", forces.getCP()));
|
||||||
|
if (forces.getCP() != null) {
|
||||||
|
row.cpx = forces.getCP().x;
|
||||||
|
row.cna = forces.getCNa();
|
||||||
|
}
|
||||||
|
|
||||||
|
// System.err.println(String.format(" .CD = %s", forces.getCD()));
|
||||||
if (!Double.isNaN(forces.getCD())) {
|
if (!Double.isNaN(forces.getCD())) {
|
||||||
dragData.add(forces);
|
dragData.add(forces);
|
||||||
}
|
}
|
||||||
if (c instanceof FinSet) {
|
|
||||||
|
if (comp instanceof FinSet) {
|
||||||
rollData.add(forces);
|
rollData.add(forces);
|
||||||
}
|
}
|
||||||
|
// // We _would_ check this, except TubeFinSet doesn't implement cant angles... so they can't impart any roll torque
|
||||||
|
// // If this is ever implemented, uncomment this block:
|
||||||
|
// else if(comp instanceof TubeFinSet){
|
||||||
|
// rollData.add(forces)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( MotorConfiguration motorConfig : configuration.getActiveMotors()) {
|
for(final MotorConfiguration config: configuration.getActiveMotors()) {
|
||||||
|
CMAnalysisEntry cmEntry = cmMap.get(config.getMotor().getDesignation());
|
||||||
Object [] data = new Object[3];
|
if (null == cmEntry) {
|
||||||
cgData.add(data);
|
continue;
|
||||||
|
}
|
||||||
data[0] = motorConfig.getMotor().getDesignation();
|
|
||||||
data[1] = motorConfig.getMotor().getLaunchMass();
|
LongitudinalStabilityRow row = new LongitudinalStabilityRow(cmEntry.name, cmEntry.source);
|
||||||
}
|
stabData.add(row);
|
||||||
|
|
||||||
forces = aeroData.get(rkt);
|
row.source = cmEntry.source;
|
||||||
if (forces != null) {
|
row.eachMass = cmEntry.eachMass;
|
||||||
Object[] data = new Object[3];
|
row.cm = cmEntry.totalCM;
|
||||||
cgData.add(data);
|
row.cpx = 0.0;
|
||||||
data[0] = rkt;
|
row.cna = 0.0;
|
||||||
data[1] = massData.get(rkt);
|
|
||||||
data[2] = forces;
|
|
||||||
dragData.add(forces);
|
|
||||||
rollData.add(forces);
|
|
||||||
totalCD = forces.getCD();
|
|
||||||
} else {
|
|
||||||
totalCD = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set warnings
|
// Set warnings
|
||||||
if (set.isEmpty()) {
|
if (set.isEmpty()) {
|
||||||
warningList.setListData(new String[] {
|
warningList.setListData(new String[] {trans.get("componentanalysisdlg.noWarnings")
|
||||||
trans.get("componentanalysisdlg.noWarnings")
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
warningList.setListData(new Vector<Warning>(set));
|
warningList.setListData(new Vector<Warning>(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
cpTableModel.fireTableDataChanged();
|
longitudeStabilityTableModel.fireTableDataChanged();
|
||||||
dragTableModel.fireTableDataChanged();
|
dragTableModel.fireTableDataChanged();
|
||||||
rollTableModel.fireTableDataChanged();
|
rollTableModel.fireTableDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class CustomCellRenderer extends JLabel implements TableCellRenderer {
|
private class CustomCellRenderer extends JLabel implements TableCellRenderer {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -628,10 +631,10 @@ public class ComponentAnalysisDialog extends JDialog implements StateChangeListe
|
|||||||
|
|
||||||
this.setText(value == null ? null : value.toString());
|
this.setText(value == null ? null : value.toString());
|
||||||
|
|
||||||
if ((row < 0) || (row >= cgData.size()))
|
if ((row < 0) || (row >= stabData.size()))
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
if (cgData.get(row)[0] instanceof Rocket) {
|
if ( 0 == row ) {
|
||||||
this.setFont(boldFont);
|
this.setFont(boldFont);
|
||||||
} else {
|
} else {
|
||||||
this.setFont(normalFont);
|
this.setFont(normalFont);
|
||||||
@ -662,6 +665,7 @@ public class ComponentAnalysisDialog extends JDialog implements StateChangeListe
|
|||||||
boolean isSelected, boolean hasFocus, int row, int column) {
|
boolean isSelected, boolean hasFocus, int row, int column) {
|
||||||
|
|
||||||
if (value instanceof Double) {
|
if (value instanceof Double) {
|
||||||
|
final double totalCD = dragData.get(0).getCD();
|
||||||
|
|
||||||
// A drag coefficient
|
// A drag coefficient
|
||||||
double cd = (Double) value;
|
double cd = (Double) value;
|
||||||
@ -698,6 +702,25 @@ public class ComponentAnalysisDialog extends JDialog implements StateChangeListe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class LongitudinalStabilityRow {
|
||||||
|
|
||||||
|
public String name;
|
||||||
|
public Object source;
|
||||||
|
public double eachMass;
|
||||||
|
public Coordinate cm;
|
||||||
|
public double cpx;
|
||||||
|
public double cna;
|
||||||
|
|
||||||
|
public LongitudinalStabilityRow(final String _name, final Object _source){
|
||||||
|
name = _name;
|
||||||
|
source = _source;
|
||||||
|
eachMass = Double.NaN;
|
||||||
|
cm = Coordinate.NaN;
|
||||||
|
cpx = Double.NaN;
|
||||||
|
cna = Double.NaN;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
///////// Singleton implementation
|
///////// Singleton implementation
|
||||||
|
|
||||||
|
@ -682,19 +682,18 @@ public class BasicFrame extends JFrame {
|
|||||||
menubar.add(menu);
|
menubar.add(menu);
|
||||||
|
|
||||||
|
|
||||||
// TODO: reimplement this
|
//// Component analysis
|
||||||
// //// Component analysis
|
item = new JMenuItem(trans.get("main.menu.analyze.componentAnalysis"), KeyEvent.VK_C);
|
||||||
// item = new JMenuItem(trans.get("main.menu.analyze.componentAnalysis"), KeyEvent.VK_C);
|
//// Analyze the rocket components separately
|
||||||
// //// Analyze the rocket components separately
|
item.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.analyze.componentAnalysis.desc"));
|
||||||
// item.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.analyze.componentAnalysis.desc"));
|
item.addActionListener(new ActionListener() {
|
||||||
// item.addActionListener(new ActionListener() {
|
@Override
|
||||||
// @Override
|
public void actionPerformed(ActionEvent e) {
|
||||||
// public void actionPerformed(ActionEvent e) {
|
log.info(Markers.USER_MARKER, "Component analysis selected");
|
||||||
// log.info(Markers.USER_MARKER, "Component analysis selected");
|
ComponentAnalysisDialog.showDialog(rocketpanel);
|
||||||
// ComponentAnalysisDialog.showDialog(rocketpanel);
|
}
|
||||||
// }
|
});
|
||||||
// });
|
menu.add(item);
|
||||||
// menu.add(item);
|
|
||||||
|
|
||||||
// TODO: reimplement this dialog
|
// TODO: reimplement this dialog
|
||||||
// //// Optimize
|
// //// Optimize
|
||||||
|
Loading…
x
Reference in New Issue
Block a user