From f03e31596a6b7893af28f399233bebc4c5501657 Mon Sep 17 00:00:00 2001 From: JoePfeiffer Date: Wed, 18 Jan 2023 09:16:33 -0700 Subject: [PATCH 1/6] Make previous/next symmetric component search look for in-line pods --- .../rocketcomponent/SymmetricComponent.java | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/core/src/net/sf/openrocket/rocketcomponent/SymmetricComponent.java b/core/src/net/sf/openrocket/rocketcomponent/SymmetricComponent.java index f3152ef96..a7b2ebc68 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/SymmetricComponent.java +++ b/core/src/net/sf/openrocket/rocketcomponent/SymmetricComponent.java @@ -599,7 +599,7 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou /** * Return the previous symmetric component, or null if none exists. - * + * * @return the previous SymmetricComponent, or null. */ public final SymmetricComponent getPreviousSymmetricComponent() { @@ -611,8 +611,8 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou // (b) BodyTube -- for Parallel Stages & PodSets final RocketComponent grandParent = this.parent.getParent(); - int searchParentIndex = grandParent.getChildPosition(this.parent); // position of stage w/in parent - int searchSiblingIndex = this.parent.getChildPosition(this)-1; // guess at index of previous stage + int searchParentIndex = grandParent.getChildPosition(this.parent); // position of component w/in parent + int searchSiblingIndex = this.parent.getChildPosition(this)-1; // guess at index of previous component while( 0 <= searchParentIndex ) { final RocketComponent searchParent = grandParent.getChild(searchParentIndex); @@ -620,12 +620,8 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou if(searchParent instanceof ComponentAssembly){ while (0 <= searchSiblingIndex) { final RocketComponent searchSibling = searchParent.getChild(searchSiblingIndex); - if (searchSibling instanceof SymmetricComponent) { - SymmetricComponent candidate = (SymmetricComponent) searchSibling; - if (inline(candidate)) { - return candidate; - } - return null; + if ((searchSibling instanceof SymmetricComponent) && inline(searchSibling)) { + return (SymmetricComponent) searchSibling; } --searchSiblingIndex; } @@ -635,6 +631,13 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou searchSiblingIndex = grandParent.getChild(searchParentIndex).getChildCount() - 1; } } + + // one last thing -- I could be the child of a PodSet, and in line with + // the SymmetricComponent that is my grandParent + if ((grandParent instanceof SymmetricComponent) && inline(grandParent)) { + return (SymmetricComponent) grandParent; + } + return null; } @@ -662,12 +665,8 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou if(searchParent instanceof ComponentAssembly){ while (searchSiblingIndex < searchParent.getChildCount()) { final RocketComponent searchSibling = searchParent.getChild(searchSiblingIndex); - if (searchSibling instanceof SymmetricComponent) { - SymmetricComponent candidate = (SymmetricComponent) searchSibling; - if (inline(candidate)) { - return candidate; - } - return null; + if ((searchSibling instanceof SymmetricComponent) && inline(searchSibling)) { + return (SymmetricComponent) searchSibling; } ++searchSiblingIndex; } @@ -675,6 +674,19 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou ++searchParentIndex; searchSiblingIndex = 0; } + + // One last thing -- I could have a child that is a PodSet that is in line + // with me + for (RocketComponent child : getChildren()) { + if (child instanceof PodSet) { + for (RocketComponent grandchild : child.getChildren()) { + if ((grandchild instanceof SymmetricComponent) && inline(grandchild)) { + return (SymmetricComponent) grandchild; + } + } + } + } + return null; } @@ -682,7 +694,7 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou * Determine whether a candidate symmetric component is in line with us * */ - private boolean inline(final SymmetricComponent candidate) { + private boolean inline(final RocketComponent candidate) { // if we share a parent, we are in line if (this.parent == candidate.parent) return true; From 098223eb31b958b353350953e2d088d6525880d5 Mon Sep 17 00:00:00 2001 From: JoePfeiffer Date: Wed, 18 Jan 2023 10:14:08 -0700 Subject: [PATCH 2/6] Check for gaps and overlaps in airframe --- core/resources/l10n/messages.properties | 2 ++ .../aerodynamics/BarrowmanCalculator.java | 33 ++++++++++--------- .../sf/openrocket/aerodynamics/Warning.java | 6 ++++ 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index b5b965b22..b87bfd771 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -1864,6 +1864,8 @@ Warning.LargeAOA.str1 = Large angle of attack encountered. Warning.LargeAOA.str2 = Large angle of attack encountered ( Warning.DISCONTINUITY = Discontinuity in rocket body diameter Warning.OPEN_AIRFRAME_FORWARD = Forward end of airframe is open (radius is > 0) +Warning.AIRFRAME_GAP = Gap in rocket airframe +Warning.AIRFRAME_OVERLAP = Two airframe sections overlap Warning.THICK_FIN = Thick fins may not simulate accurately. Warning.JAGGED_EDGED_FIN = Jagged-edged fin predictions may be inaccurate. Warning.LISTENERS_AFFECTED = Listeners modified the flight simulation diff --git a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java index ce2d5ce61..686119fac 100644 --- a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java +++ b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java @@ -309,25 +309,28 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { // We're going to say it's discontinuous if it is presented to the user as having two different // string representations. Hopefully there are enough digits in the string that it will // present as different if the discontinuity is big enough to matter. - if (!UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(2.0*sym.getForeRadius()).equals(UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(2.0*prevComp.getAftRadius()))) { - // if ( !MathUtil.equals(sym.getForeRadius(), prevComp.getAftRadius())) { - warnings.add( Warning.DIAMETER_DISCONTINUITY, sym + ", " + prevComp); + if (!UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(2.0*sym.getForeRadius()) + .equals(UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(2.0*prevComp.getAftRadius()))) { + warnings.add( Warning.DIAMETER_DISCONTINUITY, prevComp + ", " + sym); + } + + // check for gap in airframe. We'll use a textual comparison as above to see if there is a + // gap or overlap, then use arithmetic comparison to see which it is. This won't be quite as reliable + // as the case for radius, since we never actually display the absolute X position + double compX = comp.toAbsolute(Coordinate.NUL)[0].x; + double prevX = prevComp.toAbsolute(new Coordinate(prevComp.getLength(), 0, 0, 0))[0].x; + if (!UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(compX) + .equals(UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(prevX))) { + if (compX > prevX) { + warnings.add(Warning.AIRFRAME_GAP, prevComp + ", " + sym); + } else { + warnings.add(Warning.AIRFRAME_OVERLAP, prevComp + ", " + sym); + } } } - - // double x = component.toAbsolute(Coordinate.NUL)[0].x; - // // Check for lengthwise discontinuity - // if (x > componentX + 0.0001) { - // if (!MathUtil.equals(radius, 0)) { - // warnings.add(Warning.DISCONTINUITY); - // radius = 0; - //} - //componentX = component.toAbsolute(new Coordinate(component.getLengthAerodynamic()))[0].x; - - }else if( comp instanceof ComponentAssembly ){ + } else if (comp instanceof ComponentAssembly) { checkGeometry(configuration, comp, warnings); } - } } diff --git a/core/src/net/sf/openrocket/aerodynamics/Warning.java b/core/src/net/sf/openrocket/aerodynamics/Warning.java index b3c31fecc..6274a71c1 100644 --- a/core/src/net/sf/openrocket/aerodynamics/Warning.java +++ b/core/src/net/sf/openrocket/aerodynamics/Warning.java @@ -361,6 +361,12 @@ public abstract class Warning { /** A Warning that a ComponentAssembly has an open forward end */ public static final Warning OPEN_AIRFRAME_FORWARD = new Other(trans.get("Warning.OPEN_AIRFRAME_FORWARD")); + + /** A Warning that there is a gap in the airframe */ + public static final Warning AIRFRAME_GAP = new Other(trans.get("Warning.AIRFRAME_GAP")); + + /** A Warning that two airframe components overlap*/ + public static final Warning AIRFRAME_OVERLAP = new Other(trans.get("Warning.AIRFRAME_OVERLAP")); /** A Warning that the fins are thick compared to the rocket body. */ ////Thick fins may not be modeled accurately. From 6a64aa38d43e5b8b4c4c44c699ede238fe2a9a10 Mon Sep 17 00:00:00 2001 From: JoePfeiffer Date: Thu, 19 Jan 2023 19:48:42 -0700 Subject: [PATCH 3/6] Add gap check for disabled stage Add overlap checks for pod and parent component --- core/resources/l10n/messages.properties | 4 +- .../aerodynamics/BarrowmanCalculator.java | 109 +++++++++++++----- .../sf/openrocket/aerodynamics/Warning.java | 8 +- 3 files changed, 89 insertions(+), 32 deletions(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index b87bfd771..e1e08101f 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -1865,7 +1865,9 @@ Warning.LargeAOA.str2 = Large angle of attack encountered ( Warning.DISCONTINUITY = Discontinuity in rocket body diameter Warning.OPEN_AIRFRAME_FORWARD = Forward end of airframe is open (radius is > 0) Warning.AIRFRAME_GAP = Gap in rocket airframe -Warning.AIRFRAME_OVERLAP = Two airframe sections overlap +Warning.AIRFRAME_OVERLAP = Overlap in airframe components +Warning.PODSET_FORWARD = In-line podset forward of parent airframe component +Warning.PODSET_OVERLAP = In-line podset overlaps parent airframe component Warning.THICK_FIN = Thick fins may not simulate accurately. Warning.JAGGED_EDGED_FIN = Jagged-edged fin predictions may be inaccurate. Warning.LISTENERS_AFFECTED = Listeners modified the flight simulation diff --git a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java index 686119fac..4dd02050d 100644 --- a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java +++ b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java @@ -18,6 +18,8 @@ import net.sf.openrocket.rocketcomponent.FinSet; import net.sf.openrocket.rocketcomponent.FlightConfiguration; import net.sf.openrocket.rocketcomponent.InstanceContext; import net.sf.openrocket.rocketcomponent.InstanceMap; +import net.sf.openrocket.rocketcomponent.ParallelStage; +import net.sf.openrocket.rocketcomponent.PodSet; import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.SymmetricComponent; @@ -278,6 +280,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { @Override public void checkGeometry(FlightConfiguration configuration, final RocketComponent treeRoot, WarningSet warnings ){ Queue queue = new LinkedList<>(); + for (RocketComponent child : treeRoot.getChildren()) { // Ignore inactive stages if (child instanceof AxialStage && !configuration.isStageActive(child.getStageNumber())) { @@ -285,11 +288,18 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { } queue.add(child); } + + SymmetricComponent prevComp = null; + if ((treeRoot instanceof ComponentAssembly) && + (!(treeRoot instanceof Rocket))) { + prevComp = ((SymmetricComponent) (treeRoot.getChild(0))).getPreviousSymmetricComponent(); + } - SymmetricComponent prevComp = null; while(null != queue.peek()) { RocketComponent comp = queue.poll(); - if( comp instanceof SymmetricComponent ){ + if(( comp instanceof SymmetricComponent ) || + ((comp instanceof AxialStage) && + !(comp instanceof ParallelStage))) { for (RocketComponent child : comp.getChildren()) { // Ignore inactive stages if (child instanceof AxialStage && !configuration.isStageActive(child.getStageNumber())) { @@ -297,38 +307,77 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { } queue.add(child); } - - SymmetricComponent sym = (SymmetricComponent) comp; - prevComp = sym.getPreviousSymmetricComponent(); - if( null == prevComp){ - if (sym.getForeRadius() - sym.getThickness() > MathUtil.EPSILON) { - warnings.add(Warning.OPEN_AIRFRAME_FORWARD, sym.toString()); - } - } else { - // Check for radius discontinuity - // We're going to say it's discontinuous if it is presented to the user as having two different - // string representations. Hopefully there are enough digits in the string that it will - // present as different if the discontinuity is big enough to matter. - if (!UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(2.0*sym.getForeRadius()) - .equals(UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(2.0*prevComp.getAftRadius()))) { - warnings.add( Warning.DIAMETER_DISCONTINUITY, prevComp + ", " + sym); - } - // check for gap in airframe. We'll use a textual comparison as above to see if there is a - // gap or overlap, then use arithmetic comparison to see which it is. This won't be quite as reliable - // as the case for radius, since we never actually display the absolute X position - double compX = comp.toAbsolute(Coordinate.NUL)[0].x; - double prevX = prevComp.toAbsolute(new Coordinate(prevComp.getLength(), 0, 0, 0))[0].x; - if (!UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(compX) - .equals(UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(prevX))) { - if (compX > prevX) { - warnings.add(Warning.AIRFRAME_GAP, prevComp + ", " + sym); - } else { - warnings.add(Warning.AIRFRAME_OVERLAP, prevComp + ", " + sym); + if (comp instanceof SymmetricComponent) { + SymmetricComponent sym = (SymmetricComponent) comp; + if( null == prevComp){ + if (sym.getForeRadius() - sym.getThickness() > MathUtil.EPSILON) { + warnings.add(Warning.OPEN_AIRFRAME_FORWARD, sym.toString()); + } + } else { + // Check for radius discontinuity + // We're going to say it's discontinuous if it is presented to the user as having two different + // string representations. Hopefully there are enough digits in the string that it will + // present as different if the discontinuity is big enough to matter. + if (!UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(2.0*sym.getForeRadius()) + .equals(UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(2.0*prevComp.getAftRadius()))) { + warnings.add( Warning.DIAMETER_DISCONTINUITY, prevComp + ", " + sym); + } + + // check for gap gap or overlap in airframe. We'll use a textual comparison to see if there is a + // gap or overlap, then use arithmetic comparison to see which it is. This won't be quite as reliable + // as the case for radius, since we never actually display the absolute X position + + double symXfore = sym.toAbsolute(Coordinate.NUL)[0].x; + double prevXfore = prevComp.toAbsolute(Coordinate.NUL)[0].x; + + double symXaft = sym.toAbsolute(new Coordinate(comp.getLength(), 0, 0, 0))[0].x; + double prevXaft = prevComp.toAbsolute(new Coordinate(prevComp.getLength(), 0, 0, 0))[0].x; + + if (!UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(symXfore) + .equals(UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(prevXaft))) { + if (symXfore > prevXaft) { + warnings.add(Warning.AIRFRAME_GAP, prevComp + ", " + sym); + } else { + // If we only have the component with a single forward compartment bring up + // a body component overlap message + if ((symXfore >= prevXfore) && + ((symXaft >= prevXaft) || (null == sym.getNextSymmetricComponent()))) { + warnings.add(Warning.AIRFRAME_OVERLAP, prevComp + ", " + sym); + } else { + // We have a PodSet that is either overlapping or completely forward of its parent component. + // We'll find the forward-most and aft-most components and figure out which + SymmetricComponent firstComp = prevComp; + SymmetricComponent scout = prevComp; + while (null != scout) { + firstComp = scout; + scout = scout.getPreviousSymmetricComponent(); + } + double firstCompXfore = firstComp.toAbsolute(Coordinate.NUL)[0].x; + + SymmetricComponent lastComp = sym; + scout = sym; + while (null != scout) { + lastComp = scout; + scout = scout.getNextSymmetricComponent(); + } + double lastCompXaft = lastComp.toAbsolute(new Coordinate(lastComp.getLength(), 0, 0, 0))[0].x; + + // completely forward vs. overlap + if (lastCompXaft <= firstCompXfore) { + warnings.add(Warning.PODSET_FORWARD, comp.getParent().toString()); + } else { + warnings.add(Warning.PODSET_OVERLAP, comp.getParent().toString()); + } + } + + } } } + prevComp = sym; } - } else if (comp instanceof ComponentAssembly) { + } else if ((comp instanceof PodSet) || + (comp instanceof ParallelStage)) { checkGeometry(configuration, comp, warnings); } } diff --git a/core/src/net/sf/openrocket/aerodynamics/Warning.java b/core/src/net/sf/openrocket/aerodynamics/Warning.java index 6274a71c1..3c17c1e17 100644 --- a/core/src/net/sf/openrocket/aerodynamics/Warning.java +++ b/core/src/net/sf/openrocket/aerodynamics/Warning.java @@ -365,8 +365,14 @@ public abstract class Warning { /** A Warning that there is a gap in the airframe */ public static final Warning AIRFRAME_GAP = new Other(trans.get("Warning.AIRFRAME_GAP")); - /** A Warning that two airframe components overlap*/ + /** A Warning that there are overlapping airframe components */ public static final Warning AIRFRAME_OVERLAP = new Other(trans.get("Warning.AIRFRAME_OVERLAP")); + + /** A Warning that an inline podset is completely forward of its parent component */ + public static final Warning PODSET_FORWARD = new Other(trans.get("Warning.PODSET_FORWARD")); + + /** A Warning that an inline podset overlaps its parent component */ + public static final Warning PODSET_OVERLAP = new Other(trans.get("Warning.PODSET_OVERLAP")); /** A Warning that the fins are thick compared to the rocket body. */ ////Thick fins may not be modeled accurately. From 458e9e3d3d3e3dd105a029b109c33c9cb39cb5c8 Mon Sep 17 00:00:00 2001 From: JoePfeiffer Date: Fri, 20 Jan 2023 11:33:34 -0700 Subject: [PATCH 4/6] Add unit test for in-line pods --- .../net/sf/openrocket/util/TestRockets.java | 61 ++++++++++++++++++- .../aerodynamics/BarrowmanCalculatorTest.java | 50 +++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) diff --git a/core/src/net/sf/openrocket/util/TestRockets.java b/core/src/net/sf/openrocket/util/TestRockets.java index bb9ba1347..2471997b2 100644 --- a/core/src/net/sf/openrocket/util/TestRockets.java +++ b/core/src/net/sf/openrocket/util/TestRockets.java @@ -1743,10 +1743,69 @@ public class TestRockets { return rocket; } + // Alpha III modified to have an inline pod + public static final Rocket makeEstesAlphaIIIwithInlinePod() { + + Rocket rocket = TestRockets.makeEstesAlphaIII(); + + // Find rocket components to manipulate + final InstanceMap imap = rocket.getSelectedConfiguration().getActiveInstances(); + AxialStage stage = null; + BodyTube body = null; + + RocketComponent c = null; + for(Map.Entry> entry: imap.entrySet() ) { + c = entry.getKey(); + + // reference everything to the bottom + c.setAxialMethod(AxialMethod.BOTTOM); + + if (c instanceof AxialStage) { + stage = (AxialStage) c; + } + + if (c instanceof BodyTube) { + body = (BodyTube) c; + } + } + + // disconnect the body from the stage + stage.removeChild(body); + + // We need to reference the components hooked to the body to its aft end, not forward + + // Make a shorter copy of the body tube and connect it the Stage + // Notice -- total lengths of the short tubes must add up to match the original + BodyTube frontTube = new BodyTube(body.getLength()/2.0, body.getOuterRadius(), body.getThickness()); + frontTube.setName("Front Body Tube"); + stage.addChild(frontTube); + + // Add a PodSet to the front body tube. + PodSet pod = new PodSet(); + pod.setInstanceCount(1); + pod.setRadiusMethod(RadiusMethod.COAXIAL); + frontTube.addChild(pod); + pod.setAxialMethod(AxialMethod.TOP); + pod.setAxialOffset(frontTube.getLength()); + + // Add another even shorter tube to the pod + BodyTube middleTube = new BodyTube(body.getLength()/4.0, body.getOuterRadius(), body.getThickness()); + middleTube.setName("Middle Body Tube"); + pod.addChild(middleTube); + + // Shorten the original body tube, rename it, and put it on the pod + body.setName("Aft body tube"); + body.setLength(body.getLength()/4.0); + pod.addChild(body); + + return rocket; + + } + /** * dump a test rocket to a file, so we can open it in OR */ - static void dumpRocket(Rocket rocket, String filename) { + public static void dumpRocket(Rocket rocket, String filename) { OpenRocketDocument doc = OpenRocketDocumentFactory.createDocumentFromRocket(rocket); OpenRocketSaver saver = new OpenRocketSaver(); diff --git a/core/test/net/sf/openrocket/aerodynamics/BarrowmanCalculatorTest.java b/core/test/net/sf/openrocket/aerodynamics/BarrowmanCalculatorTest.java index 2acd0f49c..9293773bc 100644 --- a/core/test/net/sf/openrocket/aerodynamics/BarrowmanCalculatorTest.java +++ b/core/test/net/sf/openrocket/aerodynamics/BarrowmanCalculatorTest.java @@ -19,6 +19,7 @@ import net.sf.openrocket.rocketcomponent.FinSet; import net.sf.openrocket.rocketcomponent.FlightConfiguration; import net.sf.openrocket.rocketcomponent.NoseCone; import net.sf.openrocket.rocketcomponent.ParallelStage; +import net.sf.openrocket.rocketcomponent.PodSet; import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.Transition; import net.sf.openrocket.rocketcomponent.TrapezoidFinSet; @@ -442,4 +443,53 @@ public class BarrowmanCalculatorTest { assertEquals(" Estes Alpha III with multiple empty stages cp y value is incorrect:", cp_calcRef.y, cp_calcMulti.y , EPSILON); assertEquals(" Estes Alpha III with multiple empty stages cp z value is incorrect:", cp_calcRef.z, cp_calcMulti.z , EPSILON); } + + /** + * Tests in-line pod aerodynamics and warnings + * + */ + @Test + public void testInlinePods() { + WarningSet warnings = new WarningSet(); + + // reference rocket and results + final Rocket refRocket = TestRockets.makeEstesAlphaIII(); + final FlightConfiguration refConfig = refRocket.getSelectedConfiguration(); + final FlightConditions refConditions = new FlightConditions(refConfig); + + final BarrowmanCalculator refCalc = new BarrowmanCalculator(); + double refCP = refCalc.getCP(refConfig, refConditions, warnings).x; + final AerodynamicForces refForces = refCalc.getAerodynamicForces(refConfig, refConditions, warnings); + assertTrue("reference rocket should have no warnings", warnings.isEmpty()); + final double refCD = refForces.getCD(); + + // test rocket + final Rocket testRocket = TestRockets.makeEstesAlphaIIIwithInlinePod(); + final PodSet pod = (PodSet) testRocket.getChild(0).getChild(1).getChild(0); + 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); + assertTrue("test rocket should have no warnings", warnings.isEmpty()); + + assertEquals("ref and test rocket CP should match", refCP, testCP, EPSILON); + + final double testCD = testForces.getCD(); + assertEquals("ref and test rocket CD should match", refCD, testCD, EPSILON); + + // move the pod back. + pod.setAxialOffset(pod.getAxialOffset() + 0.1); + testCP = testCalc.getCP(testConfig, testConditions, warnings).x; + assertFalse("should be warning from gap in airframe", warnings.isEmpty()); + + // move the pod forward. + warnings.clear(); + pod.setAxialOffset(pod.getAxialOffset() - 0.2); + testCP = testCalc.getCP(testConfig, testConditions, warnings).x; + assertFalse("should be warning from airframe overlap", warnings.isEmpty()); + } + } From c286eeaa16c8182e3b2dd94fa0dfde087314e51d Mon Sep 17 00:00:00 2001 From: JoePfeiffer Date: Fri, 20 Jan 2023 17:45:47 -0700 Subject: [PATCH 5/6] check for children before taking child in geometry check. --- .../net/sf/openrocket/aerodynamics/BarrowmanCalculator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java index 4dd02050d..129f4f17c 100644 --- a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java +++ b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java @@ -291,7 +291,8 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { SymmetricComponent prevComp = null; if ((treeRoot instanceof ComponentAssembly) && - (!(treeRoot instanceof Rocket))) { + (!(treeRoot instanceof Rocket)) && + (treeRoot.getChildCount() > 0)) { prevComp = ((SymmetricComponent) (treeRoot.getChild(0))).getPreviousSymmetricComponent(); } From 84aece8ffc45e409cb6a569c834d988d89e2dff9 Mon Sep 17 00:00:00 2001 From: JoePfeiffer Date: Fri, 20 Jan 2023 17:45:47 -0700 Subject: [PATCH 6/6] check for children before taking child in geometry check. --- .../sf/openrocket/rocketcomponent/SymmetricComponent.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/src/net/sf/openrocket/rocketcomponent/SymmetricComponent.java b/core/src/net/sf/openrocket/rocketcomponent/SymmetricComponent.java index a7b2ebc68..a4fcf4376 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/SymmetricComponent.java +++ b/core/src/net/sf/openrocket/rocketcomponent/SymmetricComponent.java @@ -593,6 +593,7 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou * indicates a preferred radius, a negative value indicates that a * match was not found. */ + protected abstract double getRearAutoRadius(); @@ -626,7 +627,10 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou --searchSiblingIndex; } } + + // Look forward to the previous stage --searchParentIndex; + if( 0 <= searchParentIndex){ searchSiblingIndex = grandParent.getChild(searchParentIndex).getChildCount() - 1; } @@ -671,6 +675,8 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou ++searchSiblingIndex; } } + + // Look aft to the next stage ++searchParentIndex; searchSiblingIndex = 0; }