From 54ca2bbe0e3c72546873304c6e1e5258b1112855 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Thu, 8 Sep 2022 23:31:05 +0200 Subject: [PATCH 01/13] [#1643] Round motor filter panel diameter labels --- .../gui/dialogs/motor/thrustcurve/MotorFilterPanel.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java index 8dc619ac8..ac61bd458 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java @@ -38,6 +38,7 @@ import net.sf.openrocket.motor.Manufacturer; import net.sf.openrocket.rocketcomponent.MotorMount; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.startup.Application; +import net.sf.openrocket.unit.Unit; import net.sf.openrocket.unit.UnitGroup; import net.sf.openrocket.gui.widgets.SelectColorButton; @@ -64,8 +65,13 @@ public abstract class MotorFilterPanel extends JPanel { * updates: motorDiameters, diameterLabels */ private static void scaleDiameterLabels(){ + Unit unit = UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit(); for( int i = 0; i < motorDiameters.length; i++ ) { - diameterLabels.put( i, new JLabel(UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toString(motorDiameters[i]))); + // Round the labels, because for imperial units, the labels can otherwise overlap + double diam = unit.toUnit(motorDiameters[i]); + diam = unit.round(diam); + diam = unit.fromUnit(diam); + diameterLabels.put( i, new JLabel(unit.toString(diam))); } diameterLabels.get( motorDiameters.length-1).setText("+"); } From ac5ee7537a4971857193215d2861ac04ca612b5a Mon Sep 17 00:00:00 2001 From: SiboVG Date: Fri, 16 Sep 2022 15:05:28 +0200 Subject: [PATCH 02/13] Remove unused imports --- core/src/net/sf/openrocket/rocketcomponent/AxialStage.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/src/net/sf/openrocket/rocketcomponent/AxialStage.java b/core/src/net/sf/openrocket/rocketcomponent/AxialStage.java index 8e0f533c5..ff8d9820b 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/AxialStage.java +++ b/core/src/net/sf/openrocket/rocketcomponent/AxialStage.java @@ -1,8 +1,5 @@ package net.sf.openrocket.rocketcomponent; -import java.util.ArrayList; -import java.util.Collection; - import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.rocketcomponent.position.AxialMethod; import net.sf.openrocket.startup.Application; From 6585e071409704f771d5efd79cdc4aa1c3001d3a Mon Sep 17 00:00:00 2001 From: SiboVG Date: Mon, 19 Sep 2022 09:24:38 +0200 Subject: [PATCH 03/13] [#1617] Set stage with no children as inactive --- .../rocketcomponent/FlightConfiguration.java | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java index 72fdacac1..9fbd3d2c9 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java @@ -241,8 +241,10 @@ public class FlightConfiguration implements FlightConfigurableParameter 0 && + stages.get(stageNumber) != null && stages.get(stageNumber).active; } public Collection getAllComponents() { @@ -379,12 +381,8 @@ public class FlightConfiguration implements FlightConfigurableParameter activeStages = new ArrayList<>(); for (StageFlags flags : this.stages.values()) { - if (flags.active) { - AxialStage stage = rocket.getStage(flags.stageNumber); - if (stage == null) { - continue; - } - activeStages.add(stage); + if (isStageActive(flags.stageNumber)) { + activeStages.add( rocket.getStage(flags.stageNumber)); } } @@ -392,13 +390,7 @@ public class FlightConfiguration implements FlightConfigurableParameter Date: Mon, 19 Sep 2022 14:32:46 +0200 Subject: [PATCH 04/13] Disable stage selector if stage has no children + ttips --- core/resources/l10n/messages.properties | 2 ++ .../gui/components/StageSelector.java | 21 ++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index b1719fd2f..9fae17c83 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -64,6 +64,8 @@ RocketPanel.lbl.Stability = Stability: RocketPanel.checkbox.ShowCGCP = Show CG/CP RocketPanel.checkbox.ShowCGCP.ttip = Disabling this checkbox hides the CG and CP markings in the rocket view. RocketPanel.lbl.Stages = Stages: +RocketPanel.btn.Stages.Toggle.ttip = Toggle this button to activate or deactive the corresponding stage in your design. +RocketPanel.btn.Stages.NoChildren.ttip = This stages does not have any child components and is therefore marked as inactive.
Add components to the stage to activate it. RocketPanel.ttip.Rotation = Change the rocket's roll rotation (only affects the rocket view) ! BasicFrame diff --git a/swing/src/net/sf/openrocket/gui/components/StageSelector.java b/swing/src/net/sf/openrocket/gui/components/StageSelector.java index da1aace86..f0e9ce289 100644 --- a/swing/src/net/sf/openrocket/gui/components/StageSelector.java +++ b/swing/src/net/sf/openrocket/gui/components/StageSelector.java @@ -11,18 +11,21 @@ import javax.swing.JToggleButton; import net.miginfocom.swing.MigLayout; 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.ComponentChangeEvent; import net.sf.openrocket.rocketcomponent.FlightConfiguration; import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.startup.Application; import net.sf.openrocket.util.StateChangeListener; @SuppressWarnings("serial") public class StageSelector extends JPanel implements StateChangeListener { + private static final Translator trans = Application.getTranslator(); private final Rocket rocket; private List buttons = new ArrayList(); @@ -61,9 +64,16 @@ public class StageSelector extends JPanel implements StateChangeListener { private class StageAction extends AbstractAction { private final AxialStage stage; - + public StageAction(final AxialStage stage) { this.stage = stage; + if (this.stage.getChildCount() == 0) { + putValue(SHORT_DESCRIPTION, trans.get("RocketPanel.btn.Stages.NoChildren.ttip")); + setEnabled(false); + } else { + putValue(SHORT_DESCRIPTION, trans.get("RocketPanel.btn.Stages.Toggle.ttip")); + } + updateUI(); } @Override @@ -77,6 +87,15 @@ public class StageSelector extends JPanel implements StateChangeListener { @Override public void actionPerformed(ActionEvent e) { + // Don't toggle the state if the stage has no children (and is therefore inactive) + if (stage.getChildCount() == 0) { + putValue(SHORT_DESCRIPTION, trans.get("RocketPanel.btn.Stages.NoChildren.ttip")); + setEnabled(false); + return; + } else { + setEnabled(true); + putValue(SHORT_DESCRIPTION, trans.get("RocketPanel.btn.Stages.Toggle.ttip")); + } rocket.getSelectedConfiguration().toggleStage(stage.getStageNumber()); rocket.fireComponentChangeEvent(ComponentChangeEvent.AEROMASS_CHANGE | ComponentChangeEvent.MOTOR_CHANGE ); } From baa841818c2d6f8e5046aae4a00c02340dd17d4c Mon Sep 17 00:00:00 2001 From: SiboVG Date: Tue, 20 Sep 2022 10:25:58 +0200 Subject: [PATCH 05/13] [#1681] Fix sim table spotlight when no simulations --- swing/src/net/sf/openrocket/gui/main/SimulationPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java index 5d8cd2e53..423f23d25 100644 --- a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java +++ b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java @@ -1006,7 +1006,7 @@ public class SimulationPanel extends JPanel { */ public void takeTheSpotlight() { simulationTable.requestFocusInWindow(); - if (simulationTable.getSelectedRows().length > 0) { + if (simulationTable.getRowCount() == 0 || simulationTable.getSelectedRows().length > 0) { return; } if (previousSelection == null || previousSelection.length == 0) { From 08116c3d32ad82b0fd0a4889d260c3621f8ba1d1 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Tue, 20 Sep 2022 17:48:17 +0200 Subject: [PATCH 06/13] Replace stage active flag checks with isStageActive This is more reliable as it takes other factors into account (e.g. if the stage has no children) --- .../sf/openrocket/rocketcomponent/FlightConfiguration.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java index 9fbd3d2c9..effe1da8c 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java @@ -399,7 +399,7 @@ public class FlightConfiguration implements FlightConfigurableParameter Date: Tue, 20 Sep 2022 23:23:59 +0200 Subject: [PATCH 07/13] Fix typo --- core/resources/l10n/messages.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 9fae17c83..4b1c2b4b8 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -64,7 +64,7 @@ RocketPanel.lbl.Stability = Stability: RocketPanel.checkbox.ShowCGCP = Show CG/CP RocketPanel.checkbox.ShowCGCP.ttip = Disabling this checkbox hides the CG and CP markings in the rocket view. RocketPanel.lbl.Stages = Stages: -RocketPanel.btn.Stages.Toggle.ttip = Toggle this button to activate or deactive the corresponding stage in your design. +RocketPanel.btn.Stages.Toggle.ttip = Toggle this button to activate or deactivate the corresponding stage in your design. RocketPanel.btn.Stages.NoChildren.ttip = This stages does not have any child components and is therefore marked as inactive.
Add components to the stage to activate it. RocketPanel.ttip.Rotation = Change the rocket's roll rotation (only affects the rocket view) From 9d3c6d83643a2ed9743f1e201f43eeacc589669e Mon Sep 17 00:00:00 2001 From: SiboVG Date: Wed, 21 Sep 2022 01:04:06 +0200 Subject: [PATCH 08/13] Clean up limit by length & diameter checkbox model --- .../motor/thrustcurve/MotorFilterPanel.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java index ac61bd458..42907a5d3 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java @@ -102,6 +102,7 @@ public abstract class MotorFilterPanel extends JPanel { final JSpinner maxLengthSpinner; final UnitSelector maxLengthUnitSelect; private boolean limitDiameter = false; + boolean limitByLength = false; private Double mountDiameter = null; @@ -119,7 +120,7 @@ public abstract class MotorFilterPanel extends JPanel { List unselectedManusFromPreferences = ((SwingPreferences) Application.getPreferences()).getExcludedMotorManufacturers(); filter.setExcludedManufacturers(unselectedManusFromPreferences); - boolean limitByLengthPref = ((SwingPreferences) Application.getPreferences()).getBoolean("motorFilterLimitLength", false); + limitByLength = ((SwingPreferences) Application.getPreferences()).getBoolean("motorFilterLimitLength", false); limitDiameter = ((SwingPreferences) Application.getPreferences()).getBoolean("motorFilterLimitDiameter", false); //// Hide used motor files @@ -245,9 +246,10 @@ public abstract class MotorFilterPanel extends JPanel { // Motor Dimension selection { sub.add( new JLabel(trans.get("TCMotorSelPan.Diameter")), "split 2, wrap"); - limitDiameterCheckBox = new JCheckBox( trans.get("TCMotorSelPan.checkbox.limitdiameter")); + final BooleanModel limitByDiameterModel = new BooleanModel(limitDiameter); + limitDiameterCheckBox = new JCheckBox(limitByDiameterModel); + limitDiameterCheckBox.setText(trans.get("TCMotorSelPan.checkbox.limitdiameter")); GUIUtil.changeFontSize(limitDiameterCheckBox, -1); - limitDiameterCheckBox.setSelected(limitDiameter); limitDiameterCheckBox.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent e) { @@ -279,12 +281,13 @@ public abstract class MotorFilterPanel extends JPanel { } }); sub.add( diameterSlider, "growx, wrap"); + limitByDiameterModel.addEnableComponent(diameterSlider, false); } { // length selection sub.add( new JLabel(trans.get("TCMotorSelPan.Length")), "split 2, wrap"); - final BooleanModel limitByLengthModel = new BooleanModel(limitByLengthPref); + final BooleanModel limitByLengthModel = new BooleanModel(limitByLength); limitByLengthCheckBox = new JCheckBox( limitByLengthModel ); limitByLengthCheckBox.setText( trans.get("TCMotorSelPan.checkbox.limitlength")); GUIUtil.changeFontSize(limitByLengthCheckBox, -1); @@ -292,7 +295,7 @@ public abstract class MotorFilterPanel extends JPanel { limitByLengthCheckBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - //boolean limitByLength = limitByLengthCheckBox.isSelected(); + limitByLength = limitByLengthCheckBox.isSelected(); MotorFilterPanel.this.setLimitLength(); onSelectionChanged(); } @@ -377,7 +380,6 @@ public abstract class MotorFilterPanel extends JPanel { minLengthUnitSelect.setSelectedUnit(UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit()); maxLengthUnitSelect.setSelectedUnit(UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit()); - boolean limitByLength = limitByLengthCheckBox.isSelected(); ((SwingPreferences) Application.getPreferences()).putBoolean("motorFilterLimitLength", limitByLength); if ( mountLength != null & limitByLength ) { lengthSlider.setValueAt(1, (int) Math.min(1000,Math.round(1000*mountLength))); From 5cafd876089280d6b963a630bd6552c6a54611b5 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Wed, 21 Sep 2022 01:57:48 +0200 Subject: [PATCH 09/13] Use double-precision diameter labels --- .../dialogs/motor/thrustcurve/MotorFilterPanel.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java index 42907a5d3..5276daa8d 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java @@ -69,9 +69,14 @@ public abstract class MotorFilterPanel extends JPanel { for( int i = 0; i < motorDiameters.length; i++ ) { // Round the labels, because for imperial units, the labels can otherwise overlap double diam = unit.toUnit(motorDiameters[i]); - diam = unit.round(diam); - diam = unit.fromUnit(diam); - diameterLabels.put( i, new JLabel(unit.toString(diam))); + double diamRounded = unit.round(diam * 10) / 10; // 10 multiplication for 2-decimal precision + diam = unit.fromUnit(diamRounded); + String formatted = unit.toString(diam); + // Remove the leading zero for numbers between 0 and 1 + if (diamRounded > 0 && diamRounded < 1) { + formatted = formatted.substring(1); + } + diameterLabels.put( i, new JLabel(formatted)); } diameterLabels.get( motorDiameters.length-1).setText("+"); } From 582021e3747b7ae7acc54a8d5dfbae74d95bf3f7 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Thu, 22 Sep 2022 23:13:40 +0200 Subject: [PATCH 10/13] Don't paint ticks in length slider --- .../gui/dialogs/motor/thrustcurve/MotorFilterPanel.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java index 5276daa8d..49674d686 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java @@ -340,9 +340,6 @@ public abstract class MotorFilterPanel extends JPanel { lengthSlider = new MultiSlider(MultiSlider.HORIZONTAL,0, 1000, 0, 1000); lengthSlider.setBounded(true); // thumbs cannot cross - lengthSlider.setMajorTickSpacing(100); - lengthSlider.setPaintTicks(true); - lengthSlider.setLabelTable(diameterLabels); lengthSlider.addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { From 9d8ca907bbb022679e1a7382eb130bb1006ce9c0 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Fri, 23 Sep 2022 02:43:02 +0200 Subject: [PATCH 11/13] Add unit tests for simulating empty stages --- .../aerodynamics/BarrowmanCalculatorTest.java | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/core/test/net/sf/openrocket/aerodynamics/BarrowmanCalculatorTest.java b/core/test/net/sf/openrocket/aerodynamics/BarrowmanCalculatorTest.java index 828a49447..a26de0d72 100644 --- a/core/test/net/sf/openrocket/aerodynamics/BarrowmanCalculatorTest.java +++ b/core/test/net/sf/openrocket/aerodynamics/BarrowmanCalculatorTest.java @@ -46,6 +46,26 @@ public class BarrowmanCalculatorTest { // Application.setInjector(injector); // } } + + /** + * Test a completely empty rocket. + */ + @Test + public void testEmptyRocket() { + // First test completely empty rocket + Rocket rocket = new Rocket(); + FlightConfiguration config = rocket.getSelectedConfiguration(); + BarrowmanCalculator calc = new BarrowmanCalculator(); + FlightConditions conditions = new FlightConditions(config); + WarningSet warnings = new WarningSet(); + + Coordinate cp_calc = calc.getCP(config, conditions, warnings); + + assertEquals(" Empty rocket CNa value is incorrect:", 0.0, cp_calc.weight , 0.0); + assertEquals(" Empty rocket cp x value is incorrect:", 0.0, cp_calc.x , 0.0); + assertEquals(" Empty rocket cp y value is incorrect:", 0.0, cp_calc.y , 0.0); + assertEquals(" Empty rocket cp z value is incorrect:", 0.0, cp_calc.z , 0.0); + } @Test public void testCPSimpleDry() { @@ -351,4 +371,67 @@ public class BarrowmanCalculatorTest { assertEquals(" Alpha III With Pods rocket cp z value is incorrect:", cpNoPods.z, cpPods.z, EPSILON); assertEquals(" Alpha III With Pods rocket CNa value is incorrect:", cpPods.weight, cpNoPods.weight - 3.91572, EPSILON); } + + /** + * Tests whether adding extra empty stages has an effect. + */ + @Test + public void testEmptyStages() { + // Reference rocket + Rocket rocketRef = TestRockets.makeEstesAlphaIII(); + FlightConfiguration configRef = rocketRef.getSelectedConfiguration(); + BarrowmanCalculator calcRef = new BarrowmanCalculator(); + FlightConditions conditionsRef = new FlightConditions(configRef); + WarningSet warnings = new WarningSet(); + + Coordinate cp_calcRef = calcRef.getCP(configRef, conditionsRef, warnings); + + // First test with adding an empty stage in the front of the design + Rocket rocketFront = TestRockets.makeEstesAlphaIII(); + AxialStage stage1 = new AxialStage(); // To be placed in front of the design + rocketFront.addChild(stage1, 0); + FlightConfiguration configFront = rocketFront.getSelectedConfiguration(); + BarrowmanCalculator calcFront = new BarrowmanCalculator(); + FlightConditions conditionsFront = new FlightConditions(configFront); + warnings = new WarningSet(); + + Coordinate cp_calcFront = calcFront.getCP(configFront, conditionsFront, warnings); + + assertEquals(" Estes Alpha III with front empty stage CNa value is incorrect:", cp_calcRef.weight, cp_calcFront.weight , EPSILON); + assertEquals(" Estes Alpha III with front empty stage cp x value is incorrect:", cp_calcRef.x, cp_calcFront.x , EPSILON); + assertEquals(" Estes Alpha III with front empty stage cp y value is incorrect:", cp_calcRef.y, cp_calcFront.y , EPSILON); + assertEquals(" Estes Alpha III with front empty stage cp z value is incorrect:", cp_calcRef.z, cp_calcFront.z , EPSILON); + + // Now test with adding an empty stage in the rear of the design + Rocket rocketRear = TestRockets.makeEstesAlphaIII(); + AxialStage stage2 = new AxialStage(); // To be placed in the rear of the design + rocketRear.addChild(stage2); + FlightConfiguration configRear = rocketRear.getSelectedConfiguration(); + BarrowmanCalculator calcRear = new BarrowmanCalculator(); + FlightConditions conditionsRear = new FlightConditions(configRear); + warnings = new WarningSet(); + + Coordinate cp_calcRear = calcRear.getCP(configRear, conditionsRear, warnings); + + assertEquals(" Estes Alpha III with rear empty stage CNa value is incorrect:", cp_calcRef.weight, cp_calcRear.weight , EPSILON); + assertEquals(" Estes Alpha III with rear empty stage cp x value is incorrect:", cp_calcRef.x, cp_calcRear.x , EPSILON); + assertEquals(" Estes Alpha III with rear empty stage cp y value is incorrect:", cp_calcRef.y, cp_calcRear.y , EPSILON); + assertEquals(" Estes Alpha III with rear empty stage cp z value is incorrect:", cp_calcRef.z, cp_calcRear.z , EPSILON); + + // Test with multiple empty stages + Rocket rocketMulti = rocketFront; + AxialStage stage3 = new AxialStage(); // To be placed in the rear of the design + rocketMulti.addChild(stage3); + FlightConfiguration configMulti = rocketMulti.getSelectedConfiguration(); + BarrowmanCalculator calcMulti = new BarrowmanCalculator(); + FlightConditions conditionsMulti = new FlightConditions(configMulti); + warnings = new WarningSet(); + + Coordinate cp_calcMulti = calcMulti.getCP(configMulti, conditionsMulti, warnings); + + assertEquals(" Estes Alpha III with multiple empty stages CNa value is incorrect:", cp_calcRef.weight, cp_calcMulti.weight , EPSILON); + assertEquals(" Estes Alpha III with multiple empty stages cp x value is incorrect:", cp_calcRef.x, cp_calcMulti.x , EPSILON); + 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); + } } From fab8fc6b6d934b20ed8d9e3bd3134afc4d5b9f94 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Fri, 23 Sep 2022 16:36:02 +0200 Subject: [PATCH 12/13] Add no-junit-report unit test targets in root --- build.xml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/build.xml b/build.xml index b568e33ea..dd726a6eb 100644 --- a/build.xml +++ b/build.xml @@ -44,15 +44,26 @@ + + + + + + + - + + + + + From cf7238c1283db88fe3e88e458c5bdf1db5ddaa69 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Fri, 23 Sep 2022 19:51:53 +0200 Subject: [PATCH 13/13] Add empty stage unit tests for mass calc --- .../masscalc/MassCalculatorTest.java | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/core/test/net/sf/openrocket/masscalc/MassCalculatorTest.java b/core/test/net/sf/openrocket/masscalc/MassCalculatorTest.java index abbef4482..07ee2fdbb 100644 --- a/core/test/net/sf/openrocket/masscalc/MassCalculatorTest.java +++ b/core/test/net/sf/openrocket/masscalc/MassCalculatorTest.java @@ -23,6 +23,29 @@ public class MassCalculatorTest extends BaseTestCase { // tolerance for compared double test results private static final double EPSILON = 0.00000001; // note: this precision matches MathUtil.java + @Test + public void testEmptyRocket() { + Rocket rocket = new Rocket(); + FlightConfiguration config = rocket.getEmptyConfiguration(); + + final RigidBody actualStructure = MassCalculator.calculateStructure(config); + final double actualRocketDryMass = actualStructure.cm.weight; + final Coordinate actualRocketDryCM = actualStructure.cm; + + assertEquals(" Empty Rocket Empty Mass is incorrect: ", 0, actualRocketDryMass, 0); + + Coordinate expCM = new Coordinate(0, 0, 0, 0); + assertEquals("Empty Rocket CM.x is incorrect: ", expCM.x, actualRocketDryCM.x, 0); + assertEquals("Empty Rocket CM.y is incorrect: ", expCM.y, actualRocketDryCM.y, 0); + assertEquals("Empty Rocket CM.z is incorrect: ", expCM.z, actualRocketDryCM.z, 0); + assertEquals("Empty Rocket CM is incorrect: ", expCM, actualRocketDryCM); + + double actualMOIrot = actualStructure.getRotationalInertia(); + double actualMOIlong = actualStructure.getLongitudinalInertia(); + assertEquals("Empty Rocket Rotational MOI calculated incorrectly: ", 0, actualMOIrot, 0); + assertEquals("Empty Rocket Longitudinal MOI calculated incorrectly: ", 0, actualMOIlong, 0); + } + @Test public void testAlphaIIIStructure() { Rocket rocket = TestRockets.makeEstesAlphaIII(); @@ -1144,5 +1167,69 @@ public class MassCalculatorTest extends BaseTestCase { assertEquals(" Booster Launch CM is incorrect: ", expCM, structure.getCM()); } + + @Test + public void testEmptyStages() { + Rocket rocketRef = TestRockets.makeEstesAlphaIII(); // Reference rocket + FlightConfiguration configRef = rocketRef.getEmptyConfiguration(); + configRef.setAllStages(); + + final RigidBody structureRef = MassCalculator.calculateStructure(configRef); + final double rocketDryMassRef = structureRef.cm.weight; + final Coordinate rocketDryCMRef = structureRef.cm; + + Rocket rocket = TestRockets.makeEstesAlphaIII(); + AxialStage stage1 = new AxialStage(); // To be added to the front of the rocket + AxialStage stage2 = new AxialStage(); // To be added to the rear of the rocket + rocket.addChild(stage1, 0); + rocket.addChild(stage2); + FlightConfiguration config = rocket.getEmptyConfiguration(); + config.setAllStages(); + + final RigidBody structure = MassCalculator.calculateStructure(config); + final double rocketDryMass = structure.cm.weight; + final Coordinate rocketDryCM = structure.cm; + + assertEquals(" Empty Stages Rocket Empty Mass is incorrect: ", rocketDryMassRef, rocketDryMass, EPSILON); + + assertEquals("Empty Stages Rocket CM.x is incorrect: ", rocketDryCMRef.x, rocketDryCM.x, EPSILON); + assertEquals("Empty Stages Rocket CM.y is incorrect: ", rocketDryCMRef.y, rocketDryCM.y, EPSILON); + assertEquals("Empty Stages Rocket CM.z is incorrect: ", rocketDryCMRef.z, rocketDryCM.z, EPSILON); + assertEquals("Empty Stages Rocket CM is incorrect: ", rocketDryCMRef, rocketDryCM); + + double MOIrotRef = structureRef.getRotationalInertia(); + double MOIlongRef = structureRef.getLongitudinalInertia(); + + double MOIrot = structure.getRotationalInertia(); + double MOIlong = structure.getLongitudinalInertia(); + assertEquals("Empty Stages Rocket Rotational MOI calculated incorrectly: ", MOIrotRef, MOIrot, EPSILON); + assertEquals("Empty Stages Rocket Longitudinal MOI calculated incorrectly: ", MOIlongRef, MOIlong, EPSILON); + + // if we use a mass override, setting to same mass, we should get same result + AxialStage sustainerRef = (AxialStage) rocketRef.getChild(0); + sustainerRef.setSubcomponentsOverridden(true); + sustainerRef.setMassOverridden(true); + sustainerRef.setOverrideMass(rocketDryMassRef); + + AxialStage sustainer = (AxialStage) rocket.getChild(0); + sustainer.setSubcomponentsOverridden(true); + sustainer.setMassOverridden(true); + sustainer.setOverrideMass(rocketDryMass); + + final RigidBody overrideStructureRef = MassCalculator.calculateStructure(configRef); + final Coordinate overrideRocketDryCMRef = overrideStructureRef.cm; + + final RigidBody overrideStructure = MassCalculator.calculateStructure(config); + final Coordinate overrideRocketDryCM = overrideStructure.cm; + + assertEquals("Empty Stages Rocket Override CM is incorrect: ", overrideRocketDryCMRef, overrideRocketDryCM); + + double overrideMOIrotRef = overrideStructureRef.getRotationalInertia(); + double overrideMOIlongRef = overrideStructureRef.getLongitudinalInertia(); + double overrideMOIrot = overrideStructure.getRotationalInertia(); + double overrideMOIlong = overrideStructure.getLongitudinalInertia(); + assertEquals("Empty Stages Rocket Rotational MOI calculated incorrectly: ", overrideMOIrotRef, overrideMOIrot, EPSILON); + assertEquals("Empty Stages Rocket Longitudinal MOI calculated incorrectly: ", overrideMOIlongRef, overrideMOIlong, EPSILON); + } }