[#2048] Support inline, flush assemblies in prev/next sym comp
This commit is contained in:
parent
09918a3d22
commit
074fee3663
@ -1296,6 +1296,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
mutex.verify();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public double getRadiusOffset(RadiusMethod method) {
|
||||
double radius = getRadiusMethod().getRadius(parent, this, getRadiusOffset());
|
||||
return method.getAsOffset(parent, this, radius);
|
||||
}
|
||||
|
||||
public RadiusMethod getRadiusMethod() {
|
||||
return RadiusMethod.COAXIAL;
|
||||
@ -2059,20 +2064,37 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the component assemblies that are a child of this component
|
||||
* @return list of ComponentAssembly components that are a child of this component
|
||||
* Return all the component assemblies that are a direct/indirect child of this component
|
||||
* @return list of ComponentAssembly components that are a direct/indirect child of this component
|
||||
*/
|
||||
public final List<RocketComponent> getChildAssemblies() {
|
||||
public final List<ComponentAssembly> getAllChildAssemblies() {
|
||||
checkState();
|
||||
|
||||
Iterator<RocketComponent> children = iterator(false);
|
||||
|
||||
List<RocketComponent> result = new ArrayList<>();
|
||||
List<ComponentAssembly> result = new ArrayList<>();
|
||||
|
||||
while (children.hasNext()) {
|
||||
RocketComponent child = children.next();
|
||||
if (child instanceof ComponentAssembly) {
|
||||
result.add(child);
|
||||
result.add((ComponentAssembly) child);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the component assemblies that are a direct child of this component
|
||||
* @return list of ComponentAssembly components that are a direct child of this component
|
||||
*/
|
||||
public final List<ComponentAssembly> getDirectChildAssemblies() {
|
||||
checkState();
|
||||
|
||||
List<ComponentAssembly> result = new ArrayList<>();
|
||||
|
||||
for (RocketComponent child : this.getChildren()) {
|
||||
if (child instanceof ComponentAssembly) {
|
||||
result.add((ComponentAssembly) child);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -7,10 +7,10 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import net.sf.openrocket.preset.ComponentPreset;
|
||||
import net.sf.openrocket.rocketcomponent.position.AxialMethod;
|
||||
import net.sf.openrocket.util.BoundingBox;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
import net.sf.openrocket.rocketcomponent.position.RadiusMethod;
|
||||
|
||||
/**
|
||||
* Class for an axially symmetric rocket component generated by rotating
|
||||
@ -622,7 +622,8 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou
|
||||
while (0 <= searchSiblingIndex) {
|
||||
final RocketComponent searchSibling = searchParent.getChild(searchSiblingIndex);
|
||||
if ((searchSibling instanceof SymmetricComponent) && inline(searchSibling)) {
|
||||
return (SymmetricComponent) searchSibling;
|
||||
return getPreviousSymmetricComponentFromComponentAssembly((SymmetricComponent) searchSibling,
|
||||
(SymmetricComponent) searchSibling, 0);
|
||||
}
|
||||
--searchSiblingIndex;
|
||||
}
|
||||
@ -636,14 +637,81 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou
|
||||
}
|
||||
}
|
||||
|
||||
// one last thing -- I could be the child of a PodSet, and in line with
|
||||
// one last thing -- I could be the child of a ComponentAssembly, and in line with
|
||||
// the SymmetricComponent that is my grandParent
|
||||
if ((grandParent instanceof SymmetricComponent) && inline(grandParent)) {
|
||||
return (SymmetricComponent) grandParent;
|
||||
// If the grandparent is actually before me, then this is the previous component
|
||||
if ((parent.getAxialOffset(AxialMethod.TOP) + getAxialOffset(AxialMethod.TOP)) > 0) {
|
||||
return (SymmetricComponent) grandParent;
|
||||
}
|
||||
// If not, then search for the component before the grandparent
|
||||
else {
|
||||
// NOTE: will be incorrect if the ComponentAssembly is even further to the front than the
|
||||
// previous component of the grandparent. But that would be really bad rocket design...
|
||||
return ((SymmetricComponent) grandParent).getPreviousSymmetricComponent();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if parent has component assemblies that have potential previous components.
|
||||
* A child symmetric component of a component assembly is a potential previous component if:
|
||||
* - it is inline with the parent
|
||||
* - it is flush with the end of the parent
|
||||
* - it is larger in aft radius than the parent
|
||||
* @param parent parent component to check for child component assemblies
|
||||
* @param previous the current previous component candidate
|
||||
* @param flushOffset an extra offset to be added to check for flushness. This is used when recursively running this
|
||||
* method to check children of children of the original parent are flush with the end of the
|
||||
* original parent.
|
||||
* @return the previous component if it is found
|
||||
*/
|
||||
private SymmetricComponent getPreviousSymmetricComponentFromComponentAssembly(SymmetricComponent parent,
|
||||
SymmetricComponent previous, double flushOffset) {
|
||||
if (previous == null) {
|
||||
return parent;
|
||||
}
|
||||
if (parent == null) {
|
||||
return previous;
|
||||
}
|
||||
|
||||
double maxRadius = previous.isAftRadiusAutomatic() ? 0 : previous.getAftRadius();
|
||||
SymmetricComponent previousComponent = previous;
|
||||
for (ComponentAssembly assembly : parent.getDirectChildAssemblies()) {
|
||||
if (assembly.getChildCount() == 0) {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Check if the component assembly's last child is a symmetric component that is:
|
||||
* - inline with the parent
|
||||
* - flush with the end of the parent
|
||||
* - larger in aft radius than the parent
|
||||
* in that case, this component assembly is the new previousComponent.
|
||||
*/
|
||||
RocketComponent lastChild = assembly.getChild(assembly.getChildCount() - 1);
|
||||
if (!( (lastChild instanceof SymmetricComponent) && parent.inline(lastChild) )) {
|
||||
continue;
|
||||
}
|
||||
SymmetricComponent lastSymmetricChild = (SymmetricComponent) lastChild;
|
||||
double flushDeviation = flushOffset + assembly.getAxialOffset(AxialMethod.BOTTOM); // How much the last child is flush with the parent
|
||||
|
||||
// If the last symmetric child from the assembly if flush with the end of the parent and larger than the
|
||||
// current previous component, then this is the new previous component
|
||||
if (MathUtil.equals(flushDeviation, 0) && !lastSymmetricChild.isAftRadiusAutomatic() &&
|
||||
lastSymmetricChild.getAftRadius() > maxRadius) {
|
||||
previousComponent = lastSymmetricChild;
|
||||
maxRadius = previousComponent.getAftRadius();
|
||||
}
|
||||
// It could be that there is a child component assembly that is flush with the end of the parent or larger
|
||||
// Recursively check assembly's children
|
||||
previousComponent = getPreviousSymmetricComponentFromComponentAssembly(lastSymmetricChild, previousComponent, flushDeviation);
|
||||
maxRadius = previousComponent != null ? previousComponent.getAftRadius() : maxRadius;
|
||||
}
|
||||
|
||||
return previousComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next symmetric component, or null if none exists.
|
||||
@ -670,7 +738,8 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou
|
||||
while (searchSiblingIndex < searchParent.getChildCount()) {
|
||||
final RocketComponent searchSibling = searchParent.getChild(searchSiblingIndex);
|
||||
if ((searchSibling instanceof SymmetricComponent) && inline(searchSibling)) {
|
||||
return (SymmetricComponent) searchSibling;
|
||||
return getNextSymmetricComponentFromComponentAssembly((SymmetricComponent) searchSibling,
|
||||
(SymmetricComponent) searchSibling, 0);
|
||||
}
|
||||
++searchSiblingIndex;
|
||||
}
|
||||
@ -681,13 +750,22 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou
|
||||
searchSiblingIndex = 0;
|
||||
}
|
||||
|
||||
// One last thing -- I could have a child that is a PodSet that is in line
|
||||
// One last thing -- I could have a child that is a ComponentAssembly that is in line
|
||||
// with me
|
||||
for (RocketComponent child : getChildren()) {
|
||||
if (child instanceof PodSet) {
|
||||
if (child instanceof ComponentAssembly) {
|
||||
for (RocketComponent grandchild : child.getChildren()) {
|
||||
if ((grandchild instanceof SymmetricComponent) && inline(grandchild)) {
|
||||
return (SymmetricComponent) grandchild;
|
||||
// If the grandparent is actually after me, then this is the next component
|
||||
if ((parent.getAxialOffset(AxialMethod.BOTTOM) + getAxialOffset(AxialMethod.BOTTOM)) < 0) {
|
||||
return (SymmetricComponent) grandchild;
|
||||
}
|
||||
// If not, then search for the component after the grandparent
|
||||
else {
|
||||
// NOTE: will be incorrect if the ComponentAssembly is even further to the back than the
|
||||
// next component of the grandparent. But that would be really bad rocket design...
|
||||
return ((SymmetricComponent) grandchild).getNextSymmetricComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -696,6 +774,64 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if parent has component assemblies that have potential next components.
|
||||
* A child symmetric component of a component assembly is a potential next component if:
|
||||
* - it is inline with the parent
|
||||
* - it is flush with the front of the parent
|
||||
* - it is larger in fore radius than the parent
|
||||
* @param parent parent component to check for child component assemblies
|
||||
* @param next the next previous component candidate
|
||||
* @param flushOffset an extra offset to be added to check for flushness. This is used when recursively running this
|
||||
* method to check children of children of the original parent are flush with the front of the
|
||||
* original parent.
|
||||
* @return the next component if it is found
|
||||
*/
|
||||
private SymmetricComponent getNextSymmetricComponentFromComponentAssembly(SymmetricComponent parent,
|
||||
SymmetricComponent next, double flushOffset) {
|
||||
if (next == null) {
|
||||
return parent;
|
||||
}
|
||||
if (parent == null) {
|
||||
return next;
|
||||
}
|
||||
|
||||
double maxRadius = next.isForeRadiusAutomatic() ? 0 : next.getForeRadius();
|
||||
SymmetricComponent nextComponent = next;
|
||||
for (ComponentAssembly assembly : parent.getDirectChildAssemblies()) {
|
||||
if (assembly.getChildCount() == 0) {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Check if the component assembly's last child is a symmetric component that is:
|
||||
* - inline with the parent
|
||||
* - flush with the front of the parent
|
||||
* - larger in fore radius than the parent
|
||||
* in that case, this component assembly is the new nextComponent.
|
||||
*/
|
||||
RocketComponent firstChild = assembly.getChild(0);
|
||||
if (!( (firstChild instanceof SymmetricComponent) && parent.inline(firstChild) )) {
|
||||
continue;
|
||||
}
|
||||
SymmetricComponent firstSymmetricChild = (SymmetricComponent) firstChild;
|
||||
double flushDeviation = flushOffset + assembly.getAxialOffset(AxialMethod.TOP); // How much the last child is flush with the parent
|
||||
|
||||
// If the first symmetric child from the assembly if flush with the front of the parent and larger than the
|
||||
// current next component, then this is the new next component
|
||||
if (MathUtil.equals(flushDeviation, 0) && !firstSymmetricChild.isForeRadiusAutomatic() &&
|
||||
firstSymmetricChild.getForeRadius() > maxRadius) {
|
||||
nextComponent = firstSymmetricChild;
|
||||
maxRadius = nextComponent.getForeRadius();
|
||||
}
|
||||
// It could be that there is a child component assembly that is flush with the front of the parent or larger
|
||||
// Recursively check assembly's children
|
||||
nextComponent = getNextSymmetricComponentFromComponentAssembly(firstSymmetricChild, nextComponent, flushDeviation);
|
||||
maxRadius = nextComponent != null ? nextComponent.getForeRadius() : maxRadius;
|
||||
}
|
||||
|
||||
return nextComponent;
|
||||
}
|
||||
|
||||
/***
|
||||
* Determine whether a candidate symmetric component is in line with us
|
||||
*
|
||||
|
@ -469,7 +469,6 @@ public class BarrowmanCalculatorTest {
|
||||
final FlightConfiguration testConfig = testRocket.getSelectedConfiguration();
|
||||
final FlightConditions testConditions = new FlightConditions(testConfig);
|
||||
|
||||
TestRockets.dumpRocket(testRocket, "/home/joseph/rockets/openrocket/git/openrocket/work/testrocket.ork");
|
||||
final BarrowmanCalculator testCalc = new BarrowmanCalculator();
|
||||
double testCP = testCalc.getCP(testConfig, testConditions, warnings).x;
|
||||
final AerodynamicForces testForces = testCalc.getAerodynamicForces(testConfig, testConditions, warnings);
|
||||
@ -487,8 +486,15 @@ public class BarrowmanCalculatorTest {
|
||||
|
||||
// move the pod forward.
|
||||
warnings.clear();
|
||||
pod.setAxialOffset(pod.getAxialOffset() - 0.2);
|
||||
testCP = testCalc.getCP(testConfig, testConditions, warnings).x;
|
||||
pod.setAxialOffset(pod.getAxialOffset() - 0.3);
|
||||
testCP = testCalc.getCP(testConfig, testConditions, warnings).x;
|
||||
assertFalse("should be warning from airframe overlap", warnings.isEmpty());
|
||||
|
||||
// move the pod back.
|
||||
warnings.clear();
|
||||
pod.setAxialOffset(pod.getAxialOffset() + 0.1);
|
||||
TestRockets.dumpRocket(testRocket, "/Users/SiboVanGool/Downloads/sfs/test.ork");
|
||||
testCP = testCalc.getCP(testConfig, testConditions, warnings).x;
|
||||
assertFalse("should be warning from airframe overlap", warnings.isEmpty());
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,511 @@
|
||||
package net.sf.openrocket.rocketcomponent;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import net.sf.openrocket.material.Material;
|
||||
import net.sf.openrocket.rocketcomponent.position.AxialMethod;
|
||||
import net.sf.openrocket.rocketcomponent.position.RadiusMethod;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
|
||||
|
||||
import net.sf.openrocket.util.TestRockets;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SymmetricComponentTest extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void testPreviousSymmetricComponent() {
|
||||
Rocket rocket = TestRockets.makeFalcon9Heavy();
|
||||
AxialStage payloadStage = rocket.getStage(0);
|
||||
NoseCone payloadFairingNoseCone = (NoseCone) payloadStage.getChild(0);
|
||||
BodyTube payloadBody = (BodyTube) payloadStage.getChild(1);
|
||||
Transition payloadFairingTail = (Transition) payloadStage.getChild(2);
|
||||
BodyTube upperStageBody = (BodyTube) payloadStage.getChild(3);
|
||||
BodyTube interstageBody = (BodyTube) payloadStage.getChild(4);
|
||||
|
||||
assertNull(payloadFairingNoseCone.getPreviousSymmetricComponent());
|
||||
assertEquals(payloadFairingNoseCone, payloadBody.getPreviousSymmetricComponent());
|
||||
assertEquals(payloadBody, payloadFairingTail.getPreviousSymmetricComponent());
|
||||
assertEquals(payloadFairingTail, upperStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(upperStageBody, interstageBody.getPreviousSymmetricComponent());
|
||||
|
||||
AxialStage coreStage = rocket.getStage(1);
|
||||
BodyTube coreBody = (BodyTube) coreStage.getChild(0);
|
||||
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
ParallelStage boosterStage = (ParallelStage) rocket.getStage(2);
|
||||
NoseCone boosterCone = (NoseCone) boosterStage.getChild(0);
|
||||
BodyTube boosterBody = (BodyTube) boosterStage.getChild(1);
|
||||
|
||||
assertNull(boosterCone.getPreviousSymmetricComponent());
|
||||
assertEquals(boosterCone, boosterBody.getPreviousSymmetricComponent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreviousSymmetricComponentInlineComponentAssembly() {
|
||||
Rocket rocket = TestRockets.makeFalcon9Heavy();
|
||||
|
||||
// Stage 0
|
||||
AxialStage payloadStage = rocket.getStage(0);
|
||||
NoseCone payloadFairingNoseCone = (NoseCone) payloadStage.getChild(0);
|
||||
BodyTube payloadBody = (BodyTube) payloadStage.getChild(1);
|
||||
Transition payloadFairingTail = (Transition) payloadStage.getChild(2);
|
||||
BodyTube upperStageBody = (BodyTube) payloadStage.getChild(3);
|
||||
BodyTube interstageBody = (BodyTube) payloadStage.getChild(4);
|
||||
|
||||
// Stage 1
|
||||
AxialStage coreStage = rocket.getStage(1);
|
||||
BodyTube coreBody = (BodyTube) coreStage.getChild(0);
|
||||
|
||||
// Booster stage
|
||||
ParallelStage boosterStage = (ParallelStage) rocket.getStage(2);
|
||||
boosterStage.setInstanceCount(1);
|
||||
boosterStage.setRadius(RadiusMethod.RELATIVE, 0);
|
||||
NoseCone boosterCone = (NoseCone) boosterStage.getChild(0);
|
||||
BodyTube boosterBody = (BodyTube) boosterStage.getChild(1);
|
||||
|
||||
// Add inline pod set
|
||||
PodSet podSet = new PodSet();
|
||||
podSet.setName("Inline Pod Set");
|
||||
podSet.setInstanceCount(1);
|
||||
podSet.setRadius(RadiusMethod.FREE, 0);
|
||||
coreBody.addChild(podSet);
|
||||
podSet.setAxialOffset(AxialMethod.BOTTOM, 0);
|
||||
NoseCone podSetCone = new NoseCone();
|
||||
podSetCone.setLength(0.1);
|
||||
podSetCone.setBaseRadius(0.05);
|
||||
podSet.addChild(podSetCone);
|
||||
BodyTube podSetBody = new BodyTube(0.2, 0.05, 0.001);
|
||||
podSetBody.setName("Pod Set Body");
|
||||
podSet.addChild(podSetBody);
|
||||
TrapezoidFinSet finSet = new TrapezoidFinSet();
|
||||
podSetBody.addChild(finSet);
|
||||
|
||||
// Add last stage
|
||||
AxialStage lastStage = new AxialStage();
|
||||
BodyTube lastStageBody = new BodyTube(0.2, 0.05, 0.001);
|
||||
lastStageBody.setName("Last Stage Body");
|
||||
lastStage.addChild(lastStageBody);
|
||||
rocket.addChild(lastStage);
|
||||
|
||||
assertNull(payloadFairingNoseCone.getPreviousSymmetricComponent());
|
||||
assertEquals(payloadFairingNoseCone, payloadBody.getPreviousSymmetricComponent());
|
||||
assertEquals(payloadBody, payloadFairingTail.getPreviousSymmetricComponent());
|
||||
assertEquals(payloadFairingTail, upperStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(upperStageBody, interstageBody.getPreviousSymmetricComponent());
|
||||
|
||||
assertNull(boosterCone.getPreviousSymmetricComponent());
|
||||
assertEquals(boosterCone, boosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 1: pod set is larger, and at the back of the core stage
|
||||
assertEquals(podSetBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 2: pod set is smaller, and at the back of the core stage
|
||||
podSetBody.setOuterRadius(0.02);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 3: pod set is equal, and at the back of the core stage
|
||||
podSetBody.setOuterRadius(0.0385);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 4: pod set is larger, and at the front of the core stage
|
||||
podSetBody.setOuterRadius(0.05);
|
||||
podSet.setAxialOffset(AxialMethod.TOP, 0);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 5: pod set is smaller, and at the front of the core stage
|
||||
podSetBody.setOuterRadius(0.02);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 6: pod set is equal, and at the front of the core stage
|
||||
podSetBody.setOuterRadius(0.0385);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 7: pod set is same length as core stage, and larger, and at the front of the core stage
|
||||
podSetBody.setOuterRadius(0.05);
|
||||
podSetBody.setLength(0.7);
|
||||
assertEquals(podSetBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 8: pod set is same length as core stage, and smaller, and at the front of the core stage
|
||||
podSetBody.setOuterRadius(0.02);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 9: pod set is in larger, and in the middle of the core stage
|
||||
podSetBody.setLength(0.2);
|
||||
podSetBody.setOuterRadius(0.05);
|
||||
podSet.setAxialOffset(AxialMethod.MIDDLE, 0);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 10: pod set is in larger, and behind the back of the core stage
|
||||
podSet.setAxialOffset(AxialMethod.BOTTOM, 1);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Add a booster inside the pod set
|
||||
ParallelStage insideBooster = new ParallelStage();
|
||||
insideBooster.setName("Inside Booster");
|
||||
insideBooster.setInstanceCount(1);
|
||||
insideBooster.setRadius(RadiusMethod.FREE, 0);
|
||||
podSetBody.addChild(insideBooster);
|
||||
insideBooster.setAxialOffset(AxialMethod.BOTTOM, 0);
|
||||
BodyTube insideBoosterBody = new BodyTube(0.2, 0.06, 0.001);
|
||||
insideBoosterBody.setName("Inside Booster Body");
|
||||
insideBooster.addChild(insideBoosterBody);
|
||||
|
||||
// Case 1: inside booster is larger than pod set and flush to its end (both are at the back of the core stage)
|
||||
podSet.setAxialOffset(AxialMethod.BOTTOM, 0);
|
||||
insideBoosterBody.setOuterRadius(0.06);
|
||||
assertEquals(insideBoosterBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Case 2: inside booster is smaller than pod set and flush to its end
|
||||
insideBoosterBody.setOuterRadius(0.04);
|
||||
assertEquals(podSetBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Case 3: inside booster is equal the pod set and flush to its end
|
||||
insideBoosterBody.setOuterRadius(0.05);
|
||||
assertEquals(podSetBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Case 4: inside booster is larger than pod set and before the back (pod set at the back of the core stage)
|
||||
insideBooster.setAxialOffset(AxialMethod.BOTTOM, -1);
|
||||
insideBoosterBody.setOuterRadius(0.06);
|
||||
assertEquals(podSetBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Case 5: inside booster is larger than pod set and after the back (pod set at the back of the core stage)
|
||||
insideBooster.setAxialOffset(AxialMethod.BOTTOM, 1);
|
||||
assertEquals(podSetBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetBody, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Case 6: inside booster is larger than pod set, pod set is before the back of the core stage, inside booster is an equal amount after the back of the pod set
|
||||
podSet.setAxialOffset(AxialMethod.BOTTOM, -1.5);
|
||||
insideBooster.setAxialOffset(AxialMethod.BOTTOM, 1.5);
|
||||
assertEquals(insideBoosterBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetBody, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Case 7: inside booster is larger than pod set, pod set is after the back of the core stage, inside booster is an equal amount before the back of the pod set
|
||||
podSet.setAxialOffset(AxialMethod.BOTTOM, 1.5);
|
||||
insideBooster.setAxialOffset(AxialMethod.BOTTOM, -1.5);
|
||||
assertEquals(insideBoosterBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Case 8: inside booster is larger than pod set, pod set is before the back of the core stage, inside booster is flush with the back of the pod set
|
||||
podSet.setAxialOffset(AxialMethod.BOTTOM, -1.5);
|
||||
insideBooster.setAxialOffset(AxialMethod.BOTTOM, 0);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Case 9: inside booster is larger than pod set, pod set is after the back of the core stage, inside booster is flush with the back of the pod set
|
||||
podSet.setAxialOffset(AxialMethod.BOTTOM, 1.5);
|
||||
insideBooster.setAxialOffset(AxialMethod.BOTTOM, 0);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNextSymmetricComponent() {
|
||||
Rocket rocket = TestRockets.makeFalcon9Heavy();
|
||||
AxialStage payloadStage = rocket.getStage(0);
|
||||
NoseCone payloadFairingNoseCone = (NoseCone) payloadStage.getChild(0);
|
||||
BodyTube payloadBody = (BodyTube) payloadStage.getChild(1);
|
||||
Transition payloadFairingTail = (Transition) payloadStage.getChild(2);
|
||||
BodyTube upperStageBody = (BodyTube) payloadStage.getChild(3);
|
||||
BodyTube interstageBody = (BodyTube) payloadStage.getChild(4);
|
||||
|
||||
assertEquals(payloadBody, payloadFairingNoseCone.getNextSymmetricComponent());
|
||||
assertEquals(payloadFairingTail, payloadBody.getNextSymmetricComponent());
|
||||
assertEquals(upperStageBody, payloadFairingTail.getNextSymmetricComponent());
|
||||
assertEquals(interstageBody, upperStageBody.getNextSymmetricComponent());
|
||||
|
||||
AxialStage coreStage = rocket.getStage(1);
|
||||
BodyTube coreBody = (BodyTube) coreStage.getChild(0);
|
||||
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertNull(coreBody.getNextSymmetricComponent());
|
||||
|
||||
ParallelStage boosterStage = (ParallelStage) rocket.getStage(2);
|
||||
NoseCone boosterCone = (NoseCone) boosterStage.getChild(0);
|
||||
BodyTube boosterBody = (BodyTube) boosterStage.getChild(1);
|
||||
|
||||
assertEquals(boosterBody, boosterCone.getNextSymmetricComponent());
|
||||
assertNull(boosterBody.getNextSymmetricComponent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNextSymmetricComponentInlineComponentAssembly() {
|
||||
Rocket rocket = TestRockets.makeFalcon9Heavy();
|
||||
|
||||
// Stage 0
|
||||
AxialStage payloadStage = rocket.getStage(0);
|
||||
NoseCone payloadFairingNoseCone = (NoseCone) payloadStage.getChild(0);
|
||||
BodyTube payloadBody = (BodyTube) payloadStage.getChild(1);
|
||||
Transition payloadFairingTail = (Transition) payloadStage.getChild(2);
|
||||
BodyTube upperStageBody = (BodyTube) payloadStage.getChild(3);
|
||||
BodyTube interstageBody = (BodyTube) payloadStage.getChild(4);
|
||||
|
||||
// Stage 1
|
||||
AxialStage coreStage = rocket.getStage(1);
|
||||
BodyTube coreBody = (BodyTube) coreStage.getChild(0);
|
||||
|
||||
// Booster stage
|
||||
ParallelStage boosterStage = (ParallelStage) rocket.getStage(2);
|
||||
boosterStage.setInstanceCount(1);
|
||||
boosterStage.setRadius(RadiusMethod.RELATIVE, 0);
|
||||
NoseCone boosterCone = (NoseCone) boosterStage.getChild(0);
|
||||
BodyTube boosterBody = (BodyTube) boosterStage.getChild(1);
|
||||
|
||||
// Add inline pod set
|
||||
PodSet podSet = new PodSet();
|
||||
podSet.setName("Inline Pod Set");
|
||||
podSet.setInstanceCount(1);
|
||||
podSet.setRadius(RadiusMethod.FREE, 0);
|
||||
coreBody.addChild(podSet);
|
||||
podSet.setAxialOffset(AxialMethod.TOP, 0);
|
||||
BodyTube podSetBody = new BodyTube(0.2, 0.05, 0.001);
|
||||
podSetBody.setName("Pod Set Body");
|
||||
podSet.addChild(podSetBody);
|
||||
TrapezoidFinSet finSet = new TrapezoidFinSet();
|
||||
podSetBody.addChild(finSet);
|
||||
NoseCone podSetCone = new NoseCone();
|
||||
podSetCone.setLength(0.1);
|
||||
podSetCone.setBaseRadius(0.05);
|
||||
podSetCone.setFlipped(true);
|
||||
podSet.addChild(podSetCone);
|
||||
|
||||
// Add last stage
|
||||
AxialStage lastStage = new AxialStage();
|
||||
BodyTube lastStageBody = new BodyTube(0.2, 0.05, 0.001);
|
||||
lastStageBody.setName("Last Stage Body");
|
||||
lastStage.addChild(lastStageBody);
|
||||
rocket.addChild(lastStage);
|
||||
|
||||
assertEquals(payloadBody, payloadFairingNoseCone.getNextSymmetricComponent());
|
||||
assertEquals(payloadFairingTail, payloadBody.getNextSymmetricComponent());
|
||||
assertEquals(upperStageBody, payloadFairingTail.getNextSymmetricComponent());
|
||||
assertEquals(interstageBody, upperStageBody.getNextSymmetricComponent());
|
||||
|
||||
assertNull(lastStageBody.getNextSymmetricComponent());
|
||||
assertEquals(boosterBody, boosterCone.getNextSymmetricComponent());
|
||||
|
||||
// case 1: pod set is larger, and at the front of the core stage
|
||||
assertEquals(podSetBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 2: pod set is smaller, and at the front of the core stage
|
||||
podSetBody.setOuterRadius(0.02);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 3: pod set is equal, and at the front of the core stage
|
||||
podSetBody.setOuterRadius(0.0385);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 4: pod set is larger, and at the back of the core stage
|
||||
podSetBody.setOuterRadius(0.05);
|
||||
podSet.setAxialOffset(AxialMethod.BOTTOM, 0);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 5: pod set is smaller, and at the back of the core stage
|
||||
podSetBody.setOuterRadius(0.02);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 6: pod set is equal, and at the back of the core stage
|
||||
podSetBody.setOuterRadius(0.0385);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 7: pod set is same length as core stage, and larger, and at the back of the core stage
|
||||
podSetBody.setOuterRadius(0.05);
|
||||
podSetBody.setLength(0.7);
|
||||
assertEquals(podSetBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 8: pod set is same length as core stage, and smaller, and at the back of the core stage
|
||||
podSetBody.setOuterRadius(0.02);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 9: pod set is in larger, and in the middle of the core stage
|
||||
podSetBody.setLength(0.2);
|
||||
podSetBody.setOuterRadius(0.05);
|
||||
podSet.setAxialOffset(AxialMethod.MIDDLE, 0);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 10: pod set is in larger, and behind the front of the core stage
|
||||
podSet.setAxialOffset(AxialMethod.TOP, 1);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// Add a booster inside the pod set
|
||||
ParallelStage insideBooster = new ParallelStage();
|
||||
insideBooster.setName("Inside Booster");
|
||||
insideBooster.setInstanceCount(1);
|
||||
insideBooster.setRadius(RadiusMethod.FREE, 0);
|
||||
podSetBody.addChild(insideBooster);
|
||||
insideBooster.setAxialOffset(AxialMethod.TOP, 0);
|
||||
BodyTube insideBoosterBody = new BodyTube(0.2, 0.06, 0.001);
|
||||
insideBoosterBody.setName("Inside Booster Body");
|
||||
insideBooster.addChild(insideBoosterBody);
|
||||
|
||||
// Case 1: inside booster is larger than pod set and flush to its front (both are at the front of the core stage)
|
||||
podSet.setAxialOffset(AxialMethod.TOP, 0);
|
||||
insideBoosterBody.setOuterRadius(0.06);
|
||||
assertEquals(insideBoosterBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
|
||||
// Case 2: inside booster is smaller than pod set and flush to its front
|
||||
insideBoosterBody.setOuterRadius(0.04);
|
||||
assertEquals(podSetBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
|
||||
// Case 3: inside booster is equal the pod set and flush to its front
|
||||
insideBoosterBody.setOuterRadius(0.05);
|
||||
assertEquals(podSetBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
|
||||
// Case 4: inside booster is larger than pod set and before the front (pod set at the front of the core stage)
|
||||
insideBooster.setAxialOffset(AxialMethod.TOP, -1);
|
||||
insideBoosterBody.setOuterRadius(0.06);
|
||||
assertEquals(podSetBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
|
||||
// Case 5: inside booster is larger than pod set and after the front (pod set at the front of the core stage)
|
||||
insideBooster.setAxialOffset(AxialMethod.TOP, 1);
|
||||
assertEquals(podSetBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
|
||||
// Case 6: inside booster is larger than pod set, pod set is before the front of the core stage, inside booster is an equal amount after the front of the pod set
|
||||
podSet.setAxialOffset(AxialMethod.TOP, -1.5);
|
||||
insideBooster.setAxialOffset(AxialMethod.TOP, 1.5);
|
||||
assertEquals(insideBoosterBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
|
||||
// Case 7: inside booster is larger than pod set, pod set is after the front of the core stage, inside booster is an equal amount before the front of the pod set
|
||||
podSet.setAxialOffset(AxialMethod.TOP, 1.5);
|
||||
insideBooster.setAxialOffset(AxialMethod.TOP, -1.5);
|
||||
assertEquals(insideBoosterBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
|
||||
// Case 8: inside booster is larger than pod set, pod set is before the front of the core stage, inside booster is flush with the front of the pod set
|
||||
podSet.setAxialOffset(AxialMethod.TOP, -1.5);
|
||||
insideBooster.setAxialOffset(AxialMethod.TOP, 0);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
|
||||
// Case 9: inside booster is larger than pod set, pod set is after the front of the core stage, inside booster is flush with the front of the pod set
|
||||
podSet.setAxialOffset(AxialMethod.TOP, 1.5);
|
||||
insideBooster.setAxialOffset(AxialMethod.TOP, 0);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
}
|
||||
}
|
@ -8,443 +8,380 @@ import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SymmetricComponentVolumeTest extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void simpleConeFilled() {
|
||||
NoseCone nc = new NoseCone();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setFilled(true);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
double volume = Math.PI / 3.0;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.75, cg.x, epsilonPercent * 0.75);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleConeWithShoulderFilled() {
|
||||
NoseCone nc = new NoseCone();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setFilled(true);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setAftShoulderRadius(1.0);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderThickness(1.0);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
double volume = Math.PI / 3.0;
|
||||
volume += Math.PI;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume + "\t" + mass);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(1.312, cg.x, epsilonPercent * 1.071);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleConeHollow() {
|
||||
NoseCone nc = new NoseCone();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.5);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
double volume = Math.PI / 3.0; // outer volume
|
||||
|
||||
// manually projected Thickness of 0.5 on to radius to determine
|
||||
// the innerConeDimen. Since the outer cone is "square" (height = radius),
|
||||
// we only need to compute this one dimension in order to compute the
|
||||
// volume of the inner cone.
|
||||
double innerConeDimen = 1.0 - Math.sqrt(2.0) / 2.0;
|
||||
double innerVolume = Math.PI / 3.0 * innerConeDimen * innerConeDimen * innerConeDimen;
|
||||
volume -= innerVolume;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.7454, cg.x, epsilonPercent * 0.7454);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleConeWithShoulderHollow() {
|
||||
NoseCone nc = new NoseCone();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.5);
|
||||
nc.setAftShoulderRadius(1.0);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderThickness(0.5);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
double volume = Math.PI / 3.0; // outer volume
|
||||
|
||||
// manually projected Thickness of 0.5 on to radius to determine
|
||||
// the innerConeDimen. Since the outer cone is "square" (height = radius),
|
||||
// we only need to compute this one dimension in order to compute the
|
||||
// volume of the inner cone.
|
||||
double innerConeDimen = 1.0 - Math.sqrt(2.0) / 2.0;
|
||||
double innerVolume = Math.PI / 3.0 * innerConeDimen * innerConeDimen * innerConeDimen;
|
||||
volume -= innerVolume;
|
||||
|
||||
volume += Math.PI - Math.PI * 0.5 * 0.5;
|
||||
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(1.2719, cg.x, epsilonPercent * 1.2719);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleTransitionFilled() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(4.0);
|
||||
nc.setFilled(true);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(1.0);
|
||||
nc.setAftRadius(2.0);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
double volume = Math.PI / 3.0 * (2.0 * 2.0 + 2.0 * 1.0 + 1.0 * 1.0) * 4.0;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(2.4285, cg.x, epsilonPercent * 2.4285);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleTransitionWithShouldersFilled() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(4.0);
|
||||
nc.setFilled(true);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(1.0);
|
||||
nc.setAftRadius(2.0);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderRadius(2.0);
|
||||
nc.setAftShoulderThickness(2.0);
|
||||
nc.setForeShoulderLength(1.0);
|
||||
nc.setForeShoulderRadius(1.0);
|
||||
nc.setForeShoulderThickness(1.0);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
double volume = Math.PI / 3.0 * (2.0 * 2.0 + 2.0 * 1.0 + 1.0 * 1.0) * 4.0;
|
||||
// plus aft shoulder:
|
||||
volume += Math.PI * 1.0 * 2.0 * 2.0;
|
||||
// plus fore shoulder:
|
||||
volume += Math.PI * 1.0 * 1.0 * 1.0;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(2.8023, cg.x, epsilonPercent * 2.8023);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleTransitionHollow1() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(0.5);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.5);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
// Volume of filled transition =
|
||||
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
|
||||
|
||||
// magic 2D cad drawing...
|
||||
//
|
||||
// Since the thickness >= fore radius, the
|
||||
// hollowed out portion of the transition
|
||||
// forms a cone.
|
||||
// the dimensions of this cone were determined
|
||||
// using a 2d cad tool.
|
||||
|
||||
double innerConeRadius = 0.441;
|
||||
double innerConeLength = 0.882;
|
||||
double innerVolume = Math.PI / 3.0 * innerConeLength * innerConeRadius * innerConeRadius;
|
||||
|
||||
double volume = filledVolume - innerVolume;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.5884, cg.x, epsilonPercent * 0.5884);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleTransitionWithShouldersHollow1() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(0.5);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.5);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderRadius(1.0);
|
||||
nc.setAftShoulderThickness(0.5);
|
||||
nc.setForeShoulderLength(1.0);
|
||||
nc.setForeShoulderRadius(0.5);
|
||||
nc.setForeShoulderThickness(0.5); // note this means fore shoulder is filled.
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
// Volume of filled transition =
|
||||
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
|
||||
|
||||
// magic 2D cad drawing...
|
||||
//
|
||||
// Since the thickness >= fore radius, the
|
||||
// hollowed out portion of the transition
|
||||
// forms a cone.
|
||||
// the dimensions of this cone were determined
|
||||
// using a 2d cad tool.
|
||||
|
||||
double innerConeRadius = 0.441;
|
||||
double innerConeLength = 0.882;
|
||||
double innerVolume = Math.PI / 3.0 * innerConeLength * innerConeRadius * innerConeRadius;
|
||||
|
||||
double volume = filledVolume - innerVolume;
|
||||
|
||||
// Now add aft shoulder
|
||||
volume += Math.PI * 1.0 * 1.0 * 1.0 - Math.PI * 1.0 * 0.5 * 0.5;
|
||||
// Now add fore shoulder
|
||||
volume += Math.PI * 1.0 * 0.5 * 0.5;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.8581, cg.x, epsilonPercent * 0.8581);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleTransitionHollow2() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(0.5);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.25);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
// Volume of filled transition =
|
||||
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
|
||||
|
||||
// magic 2D cad drawing...
|
||||
//
|
||||
// Since the thickness < fore radius, the
|
||||
// hollowed out portion of the transition
|
||||
// forms a transition.
|
||||
// the dimensions of this transition were determined
|
||||
// using a 2d cad tool.
|
||||
|
||||
double innerTransitionAftRadius = 0.7205;
|
||||
double innerTransitionForeRadius = 0.2205;
|
||||
double innerVolume = Math.PI / 3.0
|
||||
* (innerTransitionAftRadius * innerTransitionAftRadius + innerTransitionAftRadius * innerTransitionForeRadius + innerTransitionForeRadius * innerTransitionForeRadius);
|
||||
|
||||
double volume = filledVolume - innerVolume;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.56827, cg.x, epsilonPercent * 0.56827);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleTransitionWithShouldersHollow2() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(0.5);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.25);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderRadius(1.0);
|
||||
nc.setAftShoulderThickness(0.25);
|
||||
nc.setForeShoulderLength(1.0);
|
||||
nc.setForeShoulderRadius(0.5);
|
||||
nc.setForeShoulderThickness(0.25);
|
||||
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
// Volume of filled transition =
|
||||
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
|
||||
|
||||
// magic 2D cad drawing...
|
||||
//
|
||||
// Since the thickness < fore radius, the
|
||||
// hollowed out portion of the transition
|
||||
// forms a transition.
|
||||
// the dimensions of this transition were determined
|
||||
// using a 2d cad tool.
|
||||
|
||||
double innerTransitionAftRadius = 0.7205;
|
||||
double innerTransitionForeRadius = 0.2205;
|
||||
double innerVolume = Math.PI / 3.0
|
||||
* (innerTransitionAftRadius * innerTransitionAftRadius + innerTransitionAftRadius * innerTransitionForeRadius + innerTransitionForeRadius * innerTransitionForeRadius);
|
||||
|
||||
double volume = filledVolume - innerVolume;
|
||||
|
||||
// now add aft shoulder
|
||||
volume += Math.PI * 1.0 * 1.0 * 1.0 - Math.PI * 1.0 * 0.75 * 0.75;
|
||||
// now add fore shoulder
|
||||
volume += Math.PI * 1.0 * 0.5 * 0.5 - Math.PI * 1.0 * 0.25 * 0.25;
|
||||
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.7829, cg.x, epsilonPercent * 0.7829);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleConeFilled() {
|
||||
NoseCone nc = new NoseCone();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setFilled(true);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
double volume = Math.PI / 3.0;
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.75, cg.x, epsilonPercent * 0.75);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleConeWithShoulderFilled() {
|
||||
NoseCone nc = new NoseCone();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setFilled(true);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setAftShoulderRadius(1.0);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderThickness(1.0);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
double volume = Math.PI / 3.0;
|
||||
volume += Math.PI;
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(1.312, cg.x, epsilonPercent * 1.071);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleConeHollow() {
|
||||
NoseCone nc = new NoseCone();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.5);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
double volume = Math.PI / 3.0; // outer volume
|
||||
|
||||
// manually projected Thickness of 0.5 on to radius to determine
|
||||
// the innerConeDimen. Since the outer cone is "square" (height = radius),
|
||||
// we only need to compute this one dimension in order to compute the
|
||||
// volume of the inner cone.
|
||||
double innerConeDimen = 1.0 - Math.sqrt(2.0) / 2.0;
|
||||
double innerVolume = Math.PI / 3.0 * innerConeDimen * innerConeDimen * innerConeDimen;
|
||||
volume -= innerVolume;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.7454, cg.x, epsilonPercent * 0.7454);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleConeWithShoulderHollow() {
|
||||
NoseCone nc = new NoseCone();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.5);
|
||||
nc.setAftShoulderRadius(1.0);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderThickness(0.5);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
double volume = Math.PI / 3.0; // outer volume
|
||||
|
||||
// manually projected Thickness of 0.5 on to radius to determine
|
||||
// the innerConeDimen. Since the outer cone is "square" (height = radius),
|
||||
// we only need to compute this one dimension in order to compute the
|
||||
// volume of the inner cone.
|
||||
double innerConeDimen = 1.0 - Math.sqrt(2.0) / 2.0;
|
||||
double innerVolume = Math.PI / 3.0 * innerConeDimen * innerConeDimen * innerConeDimen;
|
||||
volume -= innerVolume;
|
||||
volume += Math.PI - Math.PI * 0.5 * 0.5;
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(1.2719, cg.x, epsilonPercent * 1.2719);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleTransitionFilled() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(4.0);
|
||||
nc.setFilled(true);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(1.0);
|
||||
nc.setAftRadius(2.0);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
double volume = Math.PI / 3.0 * (2.0 * 2.0 + 2.0 * 1.0 + 1.0 * 1.0) * 4.0;
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(2.4285, cg.x, epsilonPercent * 2.4285);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleTransitionWithShouldersFilled() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(4.0);
|
||||
nc.setFilled(true);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(1.0);
|
||||
nc.setAftRadius(2.0);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderRadius(2.0);
|
||||
nc.setAftShoulderThickness(2.0);
|
||||
nc.setForeShoulderLength(1.0);
|
||||
nc.setForeShoulderRadius(1.0);
|
||||
nc.setForeShoulderThickness(1.0);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
double volume = Math.PI / 3.0 * (2.0 * 2.0 + 2.0 * 1.0 + 1.0 * 1.0) * 4.0;
|
||||
// plus aft shoulder:
|
||||
volume += Math.PI * 1.0 * 2.0 * 2.0;
|
||||
// plus fore shoulder:
|
||||
volume += Math.PI * 1.0 * 1.0 * 1.0;
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(2.8023, cg.x, epsilonPercent * 2.8023);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleTransitionHollow1() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(0.5);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.5);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
// Volume of filled transition =
|
||||
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
|
||||
|
||||
// magic 2D cad drawing...
|
||||
//
|
||||
// Since the thickness >= fore radius, the
|
||||
// hollowed out portion of the transition
|
||||
// forms a cone.
|
||||
// the dimensions of this cone were determined
|
||||
// using a 2d cad tool.
|
||||
|
||||
double innerConeRadius = 0.441;
|
||||
double innerConeLength = 0.882;
|
||||
double innerVolume = Math.PI / 3.0 * innerConeLength * innerConeRadius * innerConeRadius;
|
||||
double volume = filledVolume - innerVolume;
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.5884, cg.x, epsilonPercent * 0.5884);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleTransitionWithShouldersHollow1() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(0.5);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.5);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderRadius(1.0);
|
||||
nc.setAftShoulderThickness(0.5);
|
||||
nc.setForeShoulderLength(1.0);
|
||||
nc.setForeShoulderRadius(0.5);
|
||||
nc.setForeShoulderThickness(0.5); // note this means fore shoulder is filled.
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
// Volume of filled transition =
|
||||
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
|
||||
|
||||
// magic 2D cad drawing...
|
||||
//
|
||||
// Since the thickness >= fore radius, the
|
||||
// hollowed out portion of the transition
|
||||
// forms a cone.
|
||||
// the dimensions of this cone were determined
|
||||
// using a 2d cad tool.
|
||||
|
||||
double innerConeRadius = 0.441;
|
||||
double innerConeLength = 0.882;
|
||||
double innerVolume = Math.PI / 3.0 * innerConeLength * innerConeRadius * innerConeRadius;
|
||||
|
||||
double volume = filledVolume - innerVolume;
|
||||
|
||||
// Now add aft shoulder
|
||||
volume += Math.PI * 1.0 * 1.0 * 1.0 - Math.PI * 1.0 * 0.5 * 0.5;
|
||||
// Now add fore shoulder
|
||||
volume += Math.PI * 1.0 * 0.5 * 0.5;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.8581, cg.x, epsilonPercent * 0.8581);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleTransitionHollow2() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(0.5);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.25);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
// Volume of filled transition =
|
||||
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
|
||||
|
||||
// magic 2D cad drawing...
|
||||
//
|
||||
// Since the thickness < fore radius, the
|
||||
// hollowed out portion of the transition
|
||||
// forms a transition.
|
||||
// the dimensions of this transition were determined
|
||||
// using a 2d cad tool.
|
||||
|
||||
double innerTransitionAftRadius = 0.7205;
|
||||
double innerTransitionForeRadius = 0.2205;
|
||||
double innerVolume = Math.PI / 3.0
|
||||
* (innerTransitionAftRadius * innerTransitionAftRadius + innerTransitionAftRadius * innerTransitionForeRadius + innerTransitionForeRadius * innerTransitionForeRadius);
|
||||
|
||||
double volume = filledVolume - innerVolume;
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.56827, cg.x, epsilonPercent * 0.56827);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleTransitionWithShouldersHollow2() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(0.5);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.25);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderRadius(1.0);
|
||||
nc.setAftShoulderThickness(0.25);
|
||||
nc.setForeShoulderLength(1.0);
|
||||
nc.setForeShoulderRadius(0.5);
|
||||
nc.setForeShoulderThickness(0.25);
|
||||
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
// Volume of filled transition =
|
||||
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
|
||||
|
||||
// magic 2D cad drawing...
|
||||
//
|
||||
// Since the thickness < fore radius, the
|
||||
// hollowed out portion of the transition
|
||||
// forms a transition.
|
||||
// the dimensions of this transition were determined
|
||||
// using a 2d cad tool.
|
||||
|
||||
double innerTransitionAftRadius = 0.7205;
|
||||
double innerTransitionForeRadius = 0.2205;
|
||||
double innerVolume = Math.PI / 3.0
|
||||
* (innerTransitionAftRadius * innerTransitionAftRadius + innerTransitionAftRadius * innerTransitionForeRadius + innerTransitionForeRadius * innerTransitionForeRadius);
|
||||
|
||||
double volume = filledVolume - innerVolume;
|
||||
|
||||
// now add aft shoulder
|
||||
volume += Math.PI * 1.0 * 1.0 * 1.0 - Math.PI * 1.0 * 0.75 * 0.75;
|
||||
// now add fore shoulder
|
||||
volume += Math.PI * 1.0 * 0.5 * 0.5 - Math.PI * 1.0 * 0.25 * 0.25;
|
||||
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.7829, cg.x, epsilonPercent * 0.7829);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import net.sf.openrocket.gui.widgets.SelectColorToggleButton;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.rocketcomponent.AxialStage;
|
||||
import net.sf.openrocket.rocketcomponent.BodyTube;
|
||||
import net.sf.openrocket.rocketcomponent.ComponentAssembly;
|
||||
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
|
||||
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||
@ -40,7 +41,7 @@ public class StageSelector extends JPanel implements StateChangeListener {
|
||||
private void updateButtons( final FlightConfiguration configuration ) {
|
||||
buttons.clear();
|
||||
this.removeAll();
|
||||
List<RocketComponent> assemblies = configuration.getRocket().getChildAssemblies();
|
||||
List<ComponentAssembly> assemblies = configuration.getRocket().getAllChildAssemblies();
|
||||
|
||||
for (RocketComponent stage : assemblies) {
|
||||
if (!(stage instanceof AxialStage)) continue;
|
||||
|
Loading…
x
Reference in New Issue
Block a user