From 2215d41cc2809c0db1a4b34afd2eedb83a862ec4 Mon Sep 17 00:00:00 2001 From: Daniel_M_Williams Date: Sun, 24 Jan 2016 21:47:12 -0500 Subject: [PATCH 1/3] [Test] added Transition Test file. --- .../rocketcomponent/TransitionTest.java | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 core/test/net/sf/openrocket/rocketcomponent/TransitionTest.java diff --git a/core/test/net/sf/openrocket/rocketcomponent/TransitionTest.java b/core/test/net/sf/openrocket/rocketcomponent/TransitionTest.java new file mode 100644 index 000000000..5e709f077 --- /dev/null +++ b/core/test/net/sf/openrocket/rocketcomponent/TransitionTest.java @@ -0,0 +1,173 @@ +package net.sf.openrocket.rocketcomponent; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import org.junit.Test; + +import net.sf.openrocket.util.MathUtil; +import net.sf.openrocket.util.TestRockets; +import net.sf.openrocket.util.BaseTestCase.BaseTestCase; + +public class TransitionTest extends BaseTestCase { + protected final double EPSILON = MathUtil.EPSILON*1000; + + @Test + public void testVerifyConicNose(){ + NoseCone nose = new NoseCone(Transition.Shape.CONICAL, 0.06, 0.01); + assertEquals("nose cone length is wrong ", 0.06, nose.getLength(), EPSILON ); + assertEquals("nose cone fore radius is wrong ", 0.00, nose.getForeRadius(), EPSILON ); + assertEquals("nose cone aft radius is wrong ", 0.01, nose.getAftRadius(), EPSILON ); + assertThat("nose cone shape type is wrong ", Transition.Shape.CONICAL, equalTo(nose.getType())); + assertEquals("nose cone shape parameter is wrong ", 0.0, nose.getShapeParameter(), EPSILON ); + + assertEquals("bad shape - conical forward ", 0.0, nose.getRadius(0.00), EPSILON ); + assertEquals("bad shape - conical forward ", 0.0025, nose.getRadius(0.015), EPSILON ); + assertEquals("bad shape - conical forward ", 0.005, nose.getRadius(0.03), EPSILON ); + assertEquals("bad shape - conical forward ", 0.0075, nose.getRadius(0.045), EPSILON ); + assertEquals("bad shape - conical forward ", 0.01, nose.getRadius(0.06), EPSILON ); + + } + + @Test + public void testVerifyForwardConicTransition(){ + Transition nose = new Transition(); + nose.setType( Transition.Shape.CONICAL); + nose.setForeRadius( 0.5); + nose.setAftRadius( 1.0); + nose.setLength( 5.0); + + assertEquals("nose cone length is wrong ", 5.0, nose.getLength(), EPSILON ); + assertEquals("nose cone fore radius is wrong ", 0.5, nose.getForeRadius(), EPSILON ); + assertEquals("nose cone aft radius is wrong ", 1.0, nose.getAftRadius(), EPSILON ); + assertThat("nose cone shape type is wrong ", Transition.Shape.CONICAL, equalTo(nose.getType())); + assertEquals("nose cone shape parameter is wrong ", 0.0, nose.getShapeParameter(), EPSILON ); + + assertEquals("bad shape - conical forward transition", 0.5, nose.getRadius(0.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.6, nose.getRadius(1.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.7, nose.getRadius(2.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.8, nose.getRadius(3.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.9, nose.getRadius(4.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 1.0, nose.getRadius(5.0), EPSILON ); + + } + + + @Test + public void testVerifyBackwardConicTransition(){ + Transition nose = new Transition(); + nose.setType( Transition.Shape.CONICAL); + nose.setForeRadius( 1.0); + nose.setAftRadius( 0.5); + nose.setLength( 5.0); + + assertEquals("nose cone length is wrong ", 5.0, nose.getLength(), EPSILON ); + assertEquals("nose cone fore radius is wrong ", 1.0, nose.getForeRadius(), EPSILON ); + assertEquals("nose cone aft radius is wrong ", 0.5, nose.getAftRadius(), EPSILON ); + assertThat("nose cone shape type is wrong ", Transition.Shape.CONICAL, equalTo(nose.getType())); + assertEquals("nose cone shape parameter is wrong ", 0.0, nose.getShapeParameter(), EPSILON ); + + assertEquals("bad shape - conical forward transition", 1.0, nose.getRadius(0.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.9, nose.getRadius(1.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.8, nose.getRadius(2.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.7, nose.getRadius(3.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.6, nose.getRadius(4.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.5, nose.getRadius(5.0), EPSILON ); + + } + + + @Test + public void testVerifyOgiveNoseCone(){ + Transition nose = new Transition(); + nose.setType( Transition.Shape.OGIVE); + nose.setForeRadius( 0.0); + nose.setAftRadius( 1.0); + nose.setLength( 8.0); + + assertEquals("nose cone length is wrong ", 8.0, nose.getLength(), EPSILON ); + assertEquals("nose cone fore radius is wrong ", 0.0, nose.getForeRadius(), EPSILON ); + assertEquals("nose cone aft radius is wrong ", 1.0, nose.getAftRadius(), EPSILON ); + assertThat("nose cone shape type is wrong ", Transition.Shape.OGIVE, equalTo(nose.getType())); + assertEquals("nose cone shape parameter is wrong ", 1.0, nose.getShapeParameter(), EPSILON ); + + assertEquals("bad shape - conical forward transition", 0.0, nose.getRadius(0.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.23720214511, nose.getRadius(1.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.44135250736, nose.getRadius(2.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.61308144666, nose.getRadius(3.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.75290684574, nose.getRadius(4.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.86124225056, nose.getRadius(5.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.93840316661, nose.getRadius(6.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.98461174156, nose.getRadius(7.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 1.0, nose.getRadius(8.0), EPSILON ); + + } + + @Test + public void testVerifyForwardOgiveTransition(){ + Transition nose = new Transition(); + nose.setType( Transition.Shape.OGIVE); + nose.setForeRadius( 0.44135); + nose.setAftRadius( 1.0); + nose.setLength( 6.0); + + assertEquals("nose cone length is wrong ", 6.0, nose.getLength(), EPSILON ); + assertEquals("nose cone fore radius is wrong ", 0.44135, nose.getForeRadius(), EPSILON ); + assertEquals("nose cone aft radius is wrong ", 1.0, nose.getAftRadius(), EPSILON ); + assertThat("nose cone shape type is wrong ", Transition.Shape.OGIVE, equalTo(nose.getType())); + assertEquals("nose cone shape parameter is wrong ", 1.0, nose.getShapeParameter(), EPSILON ); + + assertEquals("bad shape - conical forward transition", 0.44135250736, nose.getRadius(0.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.61308144666, nose.getRadius(1.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.75290684574, nose.getRadius(2.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.86124225056, nose.getRadius(3.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.93840316661, nose.getRadius(4.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.98461174156, nose.getRadius(5.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 1.0, nose.getRadius(6.0), EPSILON ); + + } + + @Test + public void testVerifyBackwardOgiveTransition(){ + Transition nose = new Transition(); + nose.setType( Transition.Shape.OGIVE); + nose.setForeRadius( 1.0); + nose.setAftRadius( 0.44135); + nose.setLength( 6.0); + + assertEquals("nose cone length is wrong ", 6.0, nose.getLength(), EPSILON ); + assertEquals("nose cone fore radius is wrong ", 1.0, nose.getForeRadius(), EPSILON ); + assertEquals("nose cone aft radius is wrong ", 0.44135, nose.getAftRadius(), EPSILON ); + assertThat("nose cone shape type is wrong ", Transition.Shape.OGIVE, equalTo(nose.getType())); + assertEquals("nose cone shape parameter is wrong ",1.0, nose.getShapeParameter(), EPSILON ); + + assertEquals("bad shape - conical forward transition", 1.0, nose.getRadius(0.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.98461174156, nose.getRadius(1.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.93840316661, nose.getRadius(2.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.86124225056, nose.getRadius(3.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.75290684574, nose.getRadius(4.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.61308144666, nose.getRadius(5.0), EPSILON ); + assertEquals("bad shape - conical forward transition", 0.44135250736, nose.getRadius(6.0), EPSILON ); + + + + } + + @Test + public void testStockIntegration(){ + Rocket rocket = TestRockets.makeEstesAlphaIII(); + NoseCone nose = (NoseCone)rocket.getChild(0).getChild(0); + + assertEquals("Alpha3 nose cone length is wrong ", 0.07, nose.getLength(), EPSILON ); + assertEquals("Alpha3 nose cone fore radius is wrong ", 0.00, nose.getForeRadius(), EPSILON ); + assertEquals("Alpha3 nose cone aft radius is wrong ", 0.012, nose.getAftRadius(), EPSILON ); + assertThat("Alpha3 nose cone shape type is wrong ", Transition.Shape.OGIVE, equalTo(nose.getType())); + assertEquals("Alpha3 nose cone shape parameter is wrong ", 1.0, nose.getShapeParameter(), EPSILON ); + + assertEquals("Alpha3 nose cone aft shoulder length is wrong ", 0.02, nose.getAftShoulderLength(), EPSILON ); + assertEquals("Alpha3 nose cone aft shoulder radius is wrong ", 0.011, nose.getAftShoulderRadius(), EPSILON ); + + } + +} From 7029dd0c3c728e386240fff25621414ec24ae661 Mon Sep 17 00:00:00 2001 From: Daniel_M_Williams Date: Fri, 11 Mar 2016 18:36:26 -0500 Subject: [PATCH 2/3] [Rename] Changed variable names for clarity. --- .../net/sf/openrocket/masscalc/MassCalculator.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/src/net/sf/openrocket/masscalc/MassCalculator.java b/core/src/net/sf/openrocket/masscalc/MassCalculator.java index 411d37b1e..f9a93a666 100644 --- a/core/src/net/sf/openrocket/masscalc/MassCalculator.java +++ b/core/src/net/sf/openrocket/masscalc/MassCalculator.java @@ -373,18 +373,18 @@ public class MassCalculator implements Monitorable { private MassData calculateAssemblyMassData(RocketComponent component, String indent) { - Coordinate parentCM = component.getComponentCG(); - double parentIx = component.getRotationalUnitInertia() * parentCM.weight; - double parentIt = component.getLongitudinalUnitInertia() * parentCM.weight; - MassData parentData = new MassData( parentCM, parentIx, parentIt); + Coordinate compCM = component.getComponentCG(); + double compIx = component.getRotationalUnitInertia() * compCM.weight; + double compIt = component.getLongitudinalUnitInertia() * compCM.weight; + MassData parentData = new MassData( compCM, compIx, compIt); if (!component.getOverrideSubcomponents()) { if (component.isMassOverridden()) - parentCM = parentCM.setWeight(MathUtil.max(component.getOverrideMass(), MIN_MASS)); + compCM = compCM.setWeight(MathUtil.max(component.getOverrideMass(), MIN_MASS)); if (component.isCGOverridden()) - parentCM = parentCM.setXYZ(component.getOverrideCG()); + compCM = compCM.setXYZ(component.getOverrideCG()); } - if(( debug) &&( 0 < component.getChildCount()) && (MIN_MASS < parentCM.weight)){ + if(( debug) &&( 0 < component.getChildCount()) && (MIN_MASS < compCM.weight)){ System.err.println(String.format("%-32s: %s ",indent+">>["+ component.getName()+"]", parentData.toDebug() )); } From 438f58c4382df26569dc93012a10e9bbbb982867 Mon Sep 17 00:00:00 2001 From: Daniel_M_Williams Date: Fri, 11 Mar 2016 19:13:23 -0500 Subject: [PATCH 3/3] [Bugfix] Fixed MassCalculator Issues - Instancing, CGx & CM Override - Fixed Bug in MassCalculator -- demonstrated by MassCalculatorTest.testBoosterTotalCM() et al. -- errors: 1) under-counts instanced children 2) erroneously required component have children before instancing mass -- N.B. This method is ripe for refactoring, to make it MUCH cleaner.... - Updated numbers on MassCalculator Unit Tests - Added Test for motor configuration multiplicity (FlightConfigurationTest) --- .../openrocket/masscalc/MassCalculator.java | 56 +++-- .../rocketcomponent/FlightConfiguration.java | 21 +- .../net/sf/openrocket/util/TestRockets.java | 2 + .../masscalc/MassCalculatorTest.java | 205 +++++++++++------- .../FlightConfigurationTest.java | 20 +- 5 files changed, 170 insertions(+), 134 deletions(-) diff --git a/core/src/net/sf/openrocket/masscalc/MassCalculator.java b/core/src/net/sf/openrocket/masscalc/MassCalculator.java index f9a93a666..040861910 100644 --- a/core/src/net/sf/openrocket/masscalc/MassCalculator.java +++ b/core/src/net/sf/openrocket/masscalc/MassCalculator.java @@ -376,7 +376,6 @@ public class MassCalculator implements Monitorable { Coordinate compCM = component.getComponentCG(); double compIx = component.getRotationalUnitInertia() * compCM.weight; double compIt = component.getLongitudinalUnitInertia() * compCM.weight; - MassData parentData = new MassData( compCM, compIx, compIt); if (!component.getOverrideSubcomponents()) { if (component.isMassOverridden()) @@ -384,8 +383,17 @@ public class MassCalculator implements Monitorable { if (component.isCGOverridden()) compCM = compCM.setXYZ(component.getOverrideCG()); } - if(( debug) &&( 0 < component.getChildCount()) && (MIN_MASS < compCM.weight)){ - System.err.println(String.format("%-32s: %s ",indent+">>["+ component.getName()+"]", parentData.toDebug() )); + + // default if not instanced (instance count == 1) + MassData resultantData = new MassData( compCM, compIx, compIt); + + if( debug && (MIN_MASS < compCM.weight)){ + System.err.println(String.format("%-32s: %s ",indent+"ea["+ component.getName()+"]", compCM )); + if( component.isMassOverridden() && component.isMassOverridden() && component.getOverrideSubcomponents()){ + System.err.println(indent+" ?["+ component.isMassOverridden()+"]["+ + component.isMassOverridden()+"]["+ + component.getOverrideSubcomponents()+"]"); + } } MassData childrenData = MassData.ZERO_DATA; @@ -401,50 +409,40 @@ public class MassCalculator implements Monitorable { childrenData = childrenData.add( childData ); } - + resultantData = resultantData.add( childrenData); - MassData resultantData = parentData; // default if not instanced - // compensate for component-instancing propogating to children's data - int instanceCount = component.getInstanceCount(); - boolean hasChildren = ( 0 < component.getChildCount()); - if (( 1 < instanceCount )&&( hasChildren )){ -// if(( debug )){ -// System.err.println(String.format("%s Found instanceable with %d children: %s (t= %s)", -// indent, component.getInstanceCount(), component.getName(), component.getClass().getSimpleName() )); -// } + // if instanced, adjust children's data too. + if ( 1 < component.getInstanceCount() ){ + if( debug ){ + System.err.println(String.format("%s Found instanceable with %d children: %s (t= %s)", + indent, component.getInstanceCount(), component.getName(), component.getClass().getSimpleName() )); + } final double curIxx = childrenData.getIxx(); // MOI about x-axis final double curIyy = childrenData.getIyy(); // MOI about y axis final double curIzz = childrenData.getIzz(); // MOI about z axis - Coordinate eachCM = childrenData.cm; + Coordinate templateCM = resultantData.cm; MassData instAccumData = new MassData(); // accumulator for instance MassData Coordinate[] instanceLocations = ((Instanceable) component).getInstanceOffsets(); for( Coordinate curOffset : instanceLocations ){ -// if( debug){ -// //System.err.println(String.format("%-32s: %s", indent+" inst Accum", instAccumData.toCMDebug() )); -// System.err.println(String.format("%-32s: %s", indent+" inst Accum", instAccumData.toDebug() )); -// } - - Coordinate instanceCM = curOffset.add(eachCM); - + Coordinate instanceCM = curOffset.add(templateCM); MassData instanceData = new MassData( instanceCM, curIxx, curIyy, curIzz); // 3) Project the template data to the new CM // and add to the total instAccumData = instAccumData.add( instanceData); } - - childrenData = instAccumData; + + resultantData = instAccumData; + + if( debug && (MIN_MASS < compCM.weight)){ + System.err.println(String.format("%-32s: %s ", indent+"x"+component.getInstanceCount()+"["+component.getName()+"][asbly]", resultantData.toDebug())); + } + } - // combine the parent's and children's data - resultantData = parentData.add( childrenData); - if( debug){ - System.err.println(String.format("%-32s: %s ", indent+"<==>["+component.getName()+"][asbly]", resultantData.toDebug())); - } - // move to parent's reference point resultantData = resultantData.move( component.getOffset() ); if( component instanceof ParallelStage ){ diff --git a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java index 9c2bf85ea..00ca73533 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java @@ -100,20 +100,19 @@ public class FlightConfiguration implements FlightConfigurableParameterfalse) or active (true) */ - private void setStageActive(final int stageNumber, final boolean _active ) { + private void _setStageActive(final int stageNumber, final boolean _active ) { if ((0 <= stageNumber) && (stages.containsKey(stageNumber))) { stages.get(stageNumber).active = _active; return; @@ -156,6 +156,7 @@ public class FlightConfiguration implements FlightConfigurableParameter