From 6dae530acc8d77bc51ccf16dbbef430b74611f02 Mon Sep 17 00:00:00 2001 From: Billy Olsen Date: Sat, 14 Mar 2020 20:01:54 -0700 Subject: [PATCH 1/7] Fix IllegalStateException when export/print Correct the logic for detecting if a motor has an invalid FlightConfigurationId and throw an IllegalStateException only in the case that it has an error. Additionally, fix the lookup for the stageMass. The wrong value was passed to the MassCalculator.getCGAnalysis(..) which resulted in a NullPointerException. Fixes #531 Signed-off-by: Billy Olsen --- swing/src/net/sf/openrocket/gui/print/DesignReport.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/print/DesignReport.java b/swing/src/net/sf/openrocket/gui/print/DesignReport.java index d95f9fb8f..9aeed6c2f 100644 --- a/swing/src/net/sf/openrocket/gui/print/DesignReport.java +++ b/swing/src/net/sf/openrocket/gui/print/DesignReport.java @@ -328,7 +328,7 @@ public class DesignReport { MassCalculator massCalc = new MassCalculator(); - if( !motorId.hasError() ){ + if( motorId.hasError() ){ throw new IllegalStateException("Attempted to add motor data with an invalid fcid"); } rocket.createFlightConfiguration(motorId); @@ -349,7 +349,7 @@ public class DesignReport { config.clearAllStages(); config.setOnlyStage(stage); stage++; - stageMass = massCalc.getCGAnalysis( config).get(stage).weight; + stageMass = massCalc.getCGAnalysis(config).get(c).weight; // Calculate total thrust-to-weight from only lowest stage motors totalTTW = 0; topBorder = true; From ca64e9e82a865a43354de04f6a80b82eb43b9edc Mon Sep 17 00:00:00 2001 From: Billy Olsen Date: Sat, 14 Mar 2020 20:09:37 -0700 Subject: [PATCH 2/7] Fix issues with drawing rocket diagram in print/pdf Some refactoring of the code for the RocketFigure class caused changes which prevent the rocket from being rendered correctly when printing a report or exporting as PDF. The issue was due to shapes not being added to the rocket and pixel dimensions being incorrect for the logic in the DesignReport. This change ensures that rocket shapes are added when the RocketFigure's updateFigure method is called. It also modifies the PrintFigure to expose some of the underlying geometries of the subject_bounds, which are necessary for the pixel and drawing calculations used in the DesignReport. Signed-off-by: Billy Olsen --- .../sf/openrocket/gui/print/DesignReport.java | 39 ++++++++++--------- .../sf/openrocket/gui/print/PrintFigure.java | 14 ++++++- .../gui/scalefigure/RocketFigure.java | 6 +++ 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/print/DesignReport.java b/swing/src/net/sf/openrocket/gui/print/DesignReport.java index 9aeed6c2f..53f84def4 100644 --- a/swing/src/net/sf/openrocket/gui/print/DesignReport.java +++ b/swing/src/net/sf/openrocket/gui/print/DesignReport.java @@ -177,8 +177,8 @@ public class DesignReport { canvas.beginText(); canvas.setFontAndSize(ITextHelper.getBaseFont(), PrintUtilities.NORMAL_FONT_SIZE); - int figHeightPts = (int) (PrintUnit.METERS.toPoints(figure.getHeight()) * 0.4 * (scale / PrintUnit.METERS - .toPoints(1))); + double figureHeightInPoints = PrintUnit.METERS.toPoints(figure.getFigureHeight()); + int figHeightPts = (int) (figureHeightInPoints * SCALE_FUDGE_FACTOR * (scale / PrintUnit.METERS.toPoints(1))); final int diagramHeight = pageImageableHeight * 2 - 70 - (figHeightPts); canvas.moveText(document.leftMargin() + pageSize.getBorderWidthLeft(), diagramHeight); canvas.moveTextWithLeading(0, -16); @@ -213,7 +213,11 @@ public class DesignReport { canvas.endText(); try { - //Move the internal pointer of the document below that of what was just written using the direct byte buffer. + /* + * Move the internal pointer of the document below the rocket diagram and + * the key attributes. The height of the rocket figure is already calculated + * as diagramHeigt and the height of the attributes text is finalY - initialY. + */ Paragraph paragraph = new Paragraph(); float finalY = canvas.getYTLM(); int heightOfDiagramAndText = (int) (pageSize.getHeight() - (finalY - initialY + diagramHeight)); @@ -223,28 +227,26 @@ public class DesignReport { List simulations = rocketDocument.getSimulations(); - int motorNumber = 0; - for( FlightConfigurationId fcid : rocket.getIds()){ - + boolean firstMotor = true; + for (FlightConfigurationId fcid : rocket.getIds()) { PdfPTable parent = new PdfPTable(2); parent.setWidthPercentage(100); parent.setHorizontalAlignment(Element.ALIGN_LEFT); parent.setSpacingBefore(0); parent.setWidths(new int[] { 1, 3 }); - - int leading = 0; - //The first motor config is always null. Skip it and the top-most motor, then set the leading. - if ( motorNumber > 1) { - leading = 25; - } + /* The first motor information will get no spacing + * before it, while each subsequent table will need + * a spacing of 25. + */ + int leading = (firstMotor) ? 0 : 25; FlightData flight = findSimulation( fcid, simulations); addFlightData(flight, rocket, fcid, parent, leading); addMotorData(rocket, fcid, parent); document.add(parent); - motorNumber++; + firstMotor = false; } } catch (DocumentException e) { log.error("Could not modify document.", e); @@ -274,21 +276,22 @@ public class DesignReport { theFigure.updateFigure(); double scale = - (thePageImageableWidth * 2.2) / theFigure.getWidth(); + (thePageImageableWidth * 2.2) / theFigure.getFigureWidth(); theFigure.setScale(scale); - /* - * page dimensions are in points-per-inch, which, in Java2D, are the same as pixels-per-inch; thus we don't need any conversion + /* Conveniently, page dimensions are in points-per-inch, which, in + * Java2D, are the same as pixels-per-inch; thus we don't need any + * conversion for the figure size. */ theFigure.setSize(thePageImageableWidth, thePageImageableHeight); theFigure.updateFigure(); final DefaultFontMapper mapper = new DefaultFontMapper(); Graphics2D g2d = theCanvas.createGraphics(thePageImageableWidth, thePageImageableHeight * 2, mapper); - final double halfFigureHeight = SCALE_FUDGE_FACTOR * theFigure.getFigureHeightPx() / 2; + final double halfFigureHeight = SCALE_FUDGE_FACTOR * theFigure.getFigureHeight() / 2; int y = PrintUnit.POINTS_PER_INCH; //If the y dimension is negative, then it will potentially be drawn off the top of the page. Move the origin //to allow for this. - if (theFigure.getHeight() < 0.0d) { + if (theFigure.getDimensions().getY() < 0.0d) { y += (int) halfFigureHeight; } g2d.translate(20, y); diff --git a/swing/src/net/sf/openrocket/gui/print/PrintFigure.java b/swing/src/net/sf/openrocket/gui/print/PrintFigure.java index 344713505..0027e7a89 100644 --- a/swing/src/net/sf/openrocket/gui/print/PrintFigure.java +++ b/swing/src/net/sf/openrocket/gui/print/PrintFigure.java @@ -3,6 +3,8 @@ */ package net.sf.openrocket.gui.print; +import java.awt.geom.Rectangle2D; + import net.sf.openrocket.gui.scalefigure.RocketFigure; import net.sf.openrocket.rocketcomponent.Rocket; @@ -27,7 +29,15 @@ public class PrintFigure extends RocketFigure { updateFigure(); } - public double getFigureHeightPx() { - return this.getSize().height; + public double getFigureHeight() { + return this.subjectBounds_m.getHeight(); + } + + public double getFigureWidth() { + return this.subjectBounds_m.getWidth(); + } + + public Rectangle2D getDimensions() { + return this.subjectBounds_m.getBounds2D(); } } diff --git a/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java b/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java index 5775390a1..ffb277118 100644 --- a/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java +++ b/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java @@ -315,6 +315,12 @@ public class RocketFigure extends AbstractScaleFigure { } + @Override + public void updateFigure() { + updateShapes(this.figureShapes); + super.updateFigure(); + } + public RocketComponent[] getComponentsByPoint(double x, double y) { // Calculate point in shapes' coordinates Point2D.Double p = new Point2D.Double(x, y); From d5598d73809dbc44243ec2ab4f3b84d2bad77015 Mon Sep 17 00:00:00 2001 From: Billy Olsen Date: Sat, 14 Mar 2020 20:16:43 -0700 Subject: [PATCH 3/7] Clean up some code in DesignReport Clean up some of the code in DesignReport, including some refactoring TODOs in the addMotorData method. Signed-off-by: Billy Olsen --- .../sf/openrocket/gui/print/DesignReport.java | 109 ++++++++++-------- 1 file changed, 58 insertions(+), 51 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/print/DesignReport.java b/swing/src/net/sf/openrocket/gui/print/DesignReport.java index 53f84def4..2d116b2da 100644 --- a/swing/src/net/sf/openrocket/gui/print/DesignReport.java +++ b/swing/src/net/sf/openrocket/gui/print/DesignReport.java @@ -29,6 +29,7 @@ import net.sf.openrocket.gui.figureelements.RocketInfo; import net.sf.openrocket.gui.scalefigure.RocketPanel; import net.sf.openrocket.masscalc.MassCalculator; import net.sf.openrocket.motor.Motor; +import net.sf.openrocket.motor.MotorConfiguration; import net.sf.openrocket.rocketcomponent.AxialStage; import net.sf.openrocket.rocketcomponent.FlightConfiguration; import net.sf.openrocket.rocketcomponent.FlightConfigurationId; @@ -162,7 +163,7 @@ public class DesignReport { PrintUtilities.addText(document, PrintUtilities.BIG_BOLD, ROCKET_DESIGN); Rocket rocket = rocketDocument.getRocket(); - final FlightConfiguration configuration = rocket.getSelectedConfiguration();//.clone(); + final FlightConfiguration configuration = rocket.getSelectedConfiguration(); configuration.setAllStages(); PdfContentByte canvas = writer.getDirectContent(); @@ -190,8 +191,7 @@ public class DesignReport { canvas.newlineShowText(STAGES); canvas.showText("" + rocket.getStageCount()); - - if ( configuration.hasMotors()){ + if (configuration.hasMotors()) { if (configuration.getStageCount() > 1) { canvas.newlineShowText(MASS_WITH_MOTORS); } else { @@ -361,55 +361,62 @@ public class DesignReport { if (c instanceof MotorMount && ((MotorMount) c).isMotorMount()) { MotorMount mount = (MotorMount) c; - // TODO: refactor this... it's redundant with containing if, and could probably be simplified - if (mount.isMotorMount() && (mount.getMotorConfig(motorId) != null) &&(null != mount.getMotorConfig(motorId).getMotor())) { - Motor motor = mount.getMotorConfig(motorId).getMotor(); - int motorCount = mount.getMotorCount(); - - - int border = Rectangle.NO_BORDER; - if (topBorder) { - border = Rectangle.TOP; - topBorder = false; - } - - String name = motor.getDesignation(); - if (motorCount > 1) { - name += " (" + Chars.TIMES + motorCount + ")"; - } - - final PdfPCell motorVCell = ITextHelper.createCell(name, border); - motorVCell.setPaddingLeft(mPad); - motorTable.addCell(motorVCell); - motorTable.addCell(ITextHelper.createCell( - UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit(motor.getAverageThrustEstimate()), border)); - motorTable.addCell(ITextHelper.createCell( - UnitGroup.UNITS_FLIGHT_TIME.getDefaultUnit().toStringUnit(motor.getBurnTimeEstimate()), border)); - motorTable.addCell(ITextHelper.createCell( - UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit(motor.getMaxThrustEstimate()), border)); - motorTable.addCell(ITextHelper.createCell( - UnitGroup.UNITS_IMPULSE.getDefaultUnit().toStringUnit(motor.getTotalImpulseEstimate()), border)); - - double ttw = motor.getAverageThrustEstimate() / (stageMass * GRAVITY_CONSTANT); - motorTable.addCell(ITextHelper.createCell( - ttwFormat.format(ttw) + ":1", border)); - - double propMass = (motor.getLaunchMass() - motor.getBurnoutMass()); - motorTable.addCell(ITextHelper.createCell( - UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(propMass), border)); - - final Unit motorUnit = UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit(); - motorTable.addCell(ITextHelper.createCell(motorUnit.toString(motor.getDiameter()) + - "/" + - motorUnit.toString(motor.getLength()) + " " + - motorUnit.toString(), border)); - - // Sum up total count - totalMotorCount += motorCount; - totalPropMass += propMass * motorCount; - totalImpulse += motor.getTotalImpulseEstimate() * motorCount; - totalTTW += ttw * motorCount; + MotorConfiguration motorConfig = mount.getMotorConfig(motorId); + if (null == motorConfig) { + log.warn("Unable to find motorConfig for motorId {}", motorId); + continue; } + + Motor motor = motorConfig.getMotor(); + if (null == motor) { + log.warn("Motor instance is null for motorId {}", motorId); + continue; + } + + int motorCount = mount.getMotorCount(); + + int border = Rectangle.NO_BORDER; + if (topBorder) { + border = Rectangle.TOP; + topBorder = false; + } + + String name = motor.getDesignation(); + if (motorCount > 1) { + name += " (" + Chars.TIMES + motorCount + ")"; + } + + final PdfPCell motorVCell = ITextHelper.createCell(name, border); + motorVCell.setPaddingLeft(mPad); + motorTable.addCell(motorVCell); + motorTable.addCell(ITextHelper.createCell( + UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit(motor.getAverageThrustEstimate()), border)); + motorTable.addCell(ITextHelper.createCell( + UnitGroup.UNITS_FLIGHT_TIME.getDefaultUnit().toStringUnit(motor.getBurnTimeEstimate()), border)); + motorTable.addCell(ITextHelper.createCell( + UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit(motor.getMaxThrustEstimate()), border)); + motorTable.addCell(ITextHelper.createCell( + UnitGroup.UNITS_IMPULSE.getDefaultUnit().toStringUnit(motor.getTotalImpulseEstimate()), border)); + + double ttw = motor.getAverageThrustEstimate() / (stageMass * GRAVITY_CONSTANT); + motorTable.addCell(ITextHelper.createCell( + ttwFormat.format(ttw) + ":1", border)); + + double propMass = (motor.getLaunchMass() - motor.getBurnoutMass()); + motorTable.addCell(ITextHelper.createCell( + UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(propMass), border)); + + final Unit motorUnit = UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit(); + motorTable.addCell(ITextHelper.createCell(motorUnit.toString(motor.getDiameter()) + + "/" + + motorUnit.toString(motor.getLength()) + " " + + motorUnit.toString(), border)); + + // Sum up total count + totalMotorCount += motorCount; + totalPropMass += propMass * motorCount; + totalImpulse += motor.getTotalImpulseEstimate() * motorCount; + totalTTW += ttw * motorCount; } } From 94534ee8f88bbf3298db73a613a2a7f2243745fd Mon Sep 17 00:00:00 2001 From: Billy Olsen Date: Mon, 16 Mar 2020 07:42:56 -0700 Subject: [PATCH 4/7] Fix number of motors and stageMass for DesignReport Fix the number of motors that are reported. A previous change made the MotorMount.getMotorCount() return the number of motors which have been configured. However, according to the javadocs of the MotorMount interface, the getMotorCount() method is supposed to return the number of motors that a MotorMount can take for configuring it. This restores the InnerTube and BodyTube getMotorCount behavior and adds a new getMotorConfigurationCount() method to provide the new behavior. Additionally, the stageMass calculations in the DesignReport were using a deprecated method which does not return proper component weights. Change this to use the MassCalculator.calculateLaunch(...) method, which is consistent with the RocketPanel behavior. Signed-off-by: Billy Olsen --- core/src/net/sf/openrocket/rocketcomponent/BodyTube.java | 7 ++++++- core/src/net/sf/openrocket/rocketcomponent/InnerTube.java | 7 ++++++- .../src/net/sf/openrocket/rocketcomponent/MotorMount.java | 8 ++++++++ .../rocketcomponent/FlightConfigurationTest.java | 2 +- swing/src/net/sf/openrocket/gui/print/DesignReport.java | 8 ++++---- 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java index be4d06a9a..141146bc6 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java +++ b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java @@ -371,6 +371,11 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial return this.motors.getDefault(); } + @Override + public MotorConfigurationSet getMotorConfigurationSet() { + return this.motors; + } + @Override public MotorConfiguration getMotorConfig( final FlightConfigurationId fcid){ return this.motors.get(fcid); @@ -432,7 +437,7 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial @Override public int getMotorCount() { - return this.motors.size(); + return this.getClusterConfiguration().getClusterCount(); } @Override diff --git a/core/src/net/sf/openrocket/rocketcomponent/InnerTube.java b/core/src/net/sf/openrocket/rocketcomponent/InnerTube.java index 0b21dcf3d..9eda2dcd3 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/InnerTube.java +++ b/core/src/net/sf/openrocket/rocketcomponent/InnerTube.java @@ -257,6 +257,11 @@ public class InnerTube extends ThicknessRingComponent implements AxialPositionab public MotorConfiguration getDefaultMotorConfig(){ return this.motors.getDefault(); } + + @Override + public MotorConfigurationSet getMotorConfigurationSet() { + return this.motors; + } @Override public MotorConfiguration getMotorConfig( final FlightConfigurationId fcid){ @@ -321,7 +326,7 @@ public class InnerTube extends ThicknessRingComponent implements AxialPositionab @Override public int getMotorCount() { - return this.motors.size(); + return this.getClusterConfiguration().getClusterCount(); } diff --git a/core/src/net/sf/openrocket/rocketcomponent/MotorMount.java b/core/src/net/sf/openrocket/rocketcomponent/MotorMount.java index ab47b44a5..4c6b2f112 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/MotorMount.java +++ b/core/src/net/sf/openrocket/rocketcomponent/MotorMount.java @@ -3,6 +3,7 @@ package net.sf.openrocket.rocketcomponent; import java.util.Iterator; import net.sf.openrocket.motor.MotorConfiguration; +import net.sf.openrocket.motor.MotorConfigurationSet; import net.sf.openrocket.util.ChangeSource; import net.sf.openrocket.util.Coordinate; @@ -80,6 +81,13 @@ public interface MotorMount extends ChangeSource, FlightConfigurableComponent { // duplicate of RocketComponent public Coordinate[] getLocations(); + /** + * Returns the set of motors configured for flight/simulation in this motor mount. + * @return the MotorConfigurationSet containing the set of motors configured in + * this motor mount. + */ + public MotorConfigurationSet getMotorConfigurationSet(); + /** * * @param fcid id for which to return the motor (null retrieves the default) diff --git a/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java b/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java index 46cbd903b..d9267ec2c 100644 --- a/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java +++ b/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java @@ -201,7 +201,7 @@ public class FlightConfigurationTest extends BaseTestCase { InnerTube smmt = (InnerTube)rkt.getChild(0).getChild(1).getChild(2); int expectedMotorCount = 5; - int actualMotorCount = smmt.getMotorCount(); + int actualMotorCount = smmt.getMotorConfigurationSet().size(); assertThat("number of motor configurations doesn't match.", actualMotorCount, equalTo(expectedMotorCount)); } diff --git a/swing/src/net/sf/openrocket/gui/print/DesignReport.java b/swing/src/net/sf/openrocket/gui/print/DesignReport.java index 2d116b2da..12094b560 100644 --- a/swing/src/net/sf/openrocket/gui/print/DesignReport.java +++ b/swing/src/net/sf/openrocket/gui/print/DesignReport.java @@ -28,6 +28,7 @@ import net.sf.openrocket.gui.figureelements.FigureElement; import net.sf.openrocket.gui.figureelements.RocketInfo; import net.sf.openrocket.gui.scalefigure.RocketPanel; import net.sf.openrocket.masscalc.MassCalculator; +import net.sf.openrocket.masscalc.RigidBody; import net.sf.openrocket.motor.Motor; import net.sf.openrocket.motor.MotorConfiguration; import net.sf.openrocket.rocketcomponent.AxialStage; @@ -329,13 +330,11 @@ public class DesignReport { DecimalFormat ttwFormat = new DecimalFormat("0.00"); - MassCalculator massCalc = new MassCalculator(); - if( motorId.hasError() ){ throw new IllegalStateException("Attempted to add motor data with an invalid fcid"); } rocket.createFlightConfiguration(motorId); - FlightConfiguration config = rocket.getFlightConfiguration( motorId); + FlightConfiguration config = rocket.getFlightConfiguration(motorId); int totalMotorCount = 0; double totalPropMass = 0; @@ -352,7 +351,8 @@ public class DesignReport { config.clearAllStages(); config.setOnlyStage(stage); stage++; - stageMass = massCalc.getCGAnalysis(config).get(c).weight; + RigidBody launchInfo = MassCalculator.calculateLaunch(config); + stageMass = launchInfo.getMass(); // Calculate total thrust-to-weight from only lowest stage motors totalTTW = 0; topBorder = true; From 5bf8a7af15d15052b9afdc91e2b70c1fafdcae5c Mon Sep 17 00:00:00 2001 From: Billy Olsen Date: Mon, 16 Mar 2020 20:51:22 -0700 Subject: [PATCH 5/7] Update stage logic for DesignReport Stages need to be activated correctly in order to properly calculate the mass for all components that contribute to the current launch scenario. This change ensures that all of the stages from the top-most stage to the currently active stage are set as activated when stage mass is being calculated. Signed-off-by: Billy Olsen --- .../rocketcomponent/FlightConfiguration.java | 28 ++++++++++++++++++- .../FlightConfigurationTest.java | 15 ++++++++++ .../sf/openrocket/gui/print/DesignReport.java | 5 +--- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java index 4bb7fdc8d..803013df3 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java @@ -105,7 +105,7 @@ public class FlightConfiguration implements FlightConfigurableParameter + *
  • StageA - top most stage, containing nose cone etc.
  • + *
  • StageB - middle stage
  • + *
  • StageC - bottom stage
  • + * + * + * invoking FlightConfiguration.activateStagesThrough(StageB) + * will cause both StageA and StageB to be marked as active, and StageC + * will be marked as inactive. + * + * @param stage the AxialStage to activate all stages up to (inclusive) + */ + public void activateStagesThrough(final AxialStage stage) { + clearAllStages(); + for (int i=0; i <= stage.getStageNumber(); i++) { + _setStageActive(i, true); + } + updateMotors(); + } + /** * This method flags the specified stage as active, and all other stages as inactive. * diff --git a/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java b/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java index d9267ec2c..fe11df0dc 100644 --- a/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java +++ b/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java @@ -294,6 +294,21 @@ public class FlightConfigurationTest extends BaseTestCase { config.toggleStage(0); assertThat(" toggle stage #0: ", config.isStageActive(0), equalTo(false)); + + AxialStage sustainer = rkt.getTopmostStage(); + AxialStage booster = rkt.getBottomCoreStage(); + assertThat(" sustainer stage is stage #0: ", sustainer.getStageNumber(), equalTo(0)); + assertThat(" booster stage is stage #1: ", booster.getStageNumber(), equalTo(1)); + + config.clearAllStages(); + config.activateStagesThrough(sustainer); + assertThat(" sustainer stage is active: ", config.isStageActive(sustainer.getStageNumber()), equalTo(true)); + assertThat(" booster stage is inactive: ", config.isStageActive(booster.getStageNumber()), equalTo(false)); + + config.clearAllStages(); + config.activateStagesThrough(booster); + assertThat(" sustainer stage is active: ", config.isStageActive(sustainer.getStageNumber()), equalTo(true)); + assertThat(" booster stage is active: ", config.isStageActive(booster.getStageNumber()), equalTo(true)); } diff --git a/swing/src/net/sf/openrocket/gui/print/DesignReport.java b/swing/src/net/sf/openrocket/gui/print/DesignReport.java index 12094b560..dda55bd73 100644 --- a/swing/src/net/sf/openrocket/gui/print/DesignReport.java +++ b/swing/src/net/sf/openrocket/gui/print/DesignReport.java @@ -341,16 +341,13 @@ public class DesignReport { double totalImpulse = 0; double totalTTW = 0; - int stage = 0; double stageMass = 0; boolean topBorder = false; for (RocketComponent c : rocket) { if (c instanceof AxialStage) { - config.clearAllStages(); - config.setOnlyStage(stage); - stage++; + config.activateStagesThrough((AxialStage) c); RigidBody launchInfo = MassCalculator.calculateLaunch(config); stageMass = launchInfo.getMass(); // Calculate total thrust-to-weight from only lowest stage motors From 5977bfa95ae3a3e022c64cb3a0257cd0af00f68e Mon Sep 17 00:00:00 2001 From: Billy Olsen Date: Thu, 19 Mar 2020 20:32:15 -0700 Subject: [PATCH 6/7] Add scaleFactor back into some shapes NoseCones aren't rendered correctly when printing/exporting as PDF due to the scaleFactor not being honored correctly in TransitionShapes. There was a good refactor to move some of the scaling pieces out, however the PrintableNoseCone didn't benefit from these changes. This restores part of the scaleFactor bits to the TransitionShapes in order to get the printing to correctly work again. This code should be transitioned to the new method for scaling. Signed-off-by: Billy Olsen --- .../gui/rocketfigure/SymmetricComponentShapes.java | 12 ++++++++---- .../gui/rocketfigure/TransitionShapes.java | 14 +++++++------- .../sf/openrocket/gui/rocketfigure/TubeShapes.java | 13 +++++++++---- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/SymmetricComponentShapes.java b/swing/src/net/sf/openrocket/gui/rocketfigure/SymmetricComponentShapes.java index 11efa0ebc..a21a7656a 100644 --- a/swing/src/net/sf/openrocket/gui/rocketfigure/SymmetricComponentShapes.java +++ b/swing/src/net/sf/openrocket/gui/rocketfigure/SymmetricComponentShapes.java @@ -19,6 +19,10 @@ public class SymmetricComponentShapes extends RocketComponentShape { // TODO: LOW: Uses only first component of cluster (not currently clusterable) public static RocketComponentShape[] getShapesSide( final RocketComponent component, final Transformation transformation) { + return getShapesSide(component, transformation, 1.0d); + } + + public static RocketComponentShape[] getShapesSide( final RocketComponent component, final Transformation transformation, final double scaleFactor ) { SymmetricComponent c = (SymmetricComponent) component; @@ -82,14 +86,14 @@ public class SymmetricComponentShapes extends RocketComponentShape { // TODO: LOW: curved path instead of linear Path2D.Double path = new Path2D.Double(); - path.moveTo((nose.x + points.get(len - 1).x) , (nose.y+points.get(len - 1).y) ); + path.moveTo((nose.x + points.get(len - 1).x) * scaleFactor, (nose.y+points.get(len - 1).y) * scaleFactor); for (i = len - 2; i >= 0; i--) { - path.lineTo((nose.x+points.get(i).x), (nose.y+points.get(i).y) ); + path.lineTo((nose.x+points.get(i).x) * scaleFactor, (nose.y+points.get(i).y) * scaleFactor); } for (i = 0; i < len; i++) { - path.lineTo((nose.x+points.get(i).x) , (nose.y-points.get(i).y) ); + path.lineTo((nose.x+points.get(i).x) * scaleFactor, (nose.y-points.get(i).y) * scaleFactor); } - path.lineTo((nose.x+points.get(len - 1).x) , (nose.y+points.get(len - 1).y) ); + path.lineTo((nose.x+points.get(len - 1).x) * scaleFactor , (nose.y+points.get(len - 1).y) * scaleFactor); path.closePath(); //s[len] = path; diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/TransitionShapes.java b/swing/src/net/sf/openrocket/gui/rocketfigure/TransitionShapes.java index be46b169e..33699ecdf 100644 --- a/swing/src/net/sf/openrocket/gui/rocketfigure/TransitionShapes.java +++ b/swing/src/net/sf/openrocket/gui/rocketfigure/TransitionShapes.java @@ -37,15 +37,15 @@ public class TransitionShapes extends RocketComponentShape { double r2 = transition.getAftRadius(); Path2D.Float path = new Path2D.Float(); - path.moveTo( (frontCenter.x), (frontCenter.y+ r1)); - path.lineTo( (frontCenter.x+length), (frontCenter.y+r2)); - path.lineTo( (frontCenter.x+length), (frontCenter.y-r2)); - path.lineTo( (frontCenter.x), (frontCenter.y-r1)); + path.moveTo( (frontCenter.x) * scaleFactor, (frontCenter.y+ r1) * scaleFactor); + path.lineTo( (frontCenter.x+length) * scaleFactor, (frontCenter.y+r2) * scaleFactor); + path.lineTo( (frontCenter.x+length) * scaleFactor, (frontCenter.y-r2) * scaleFactor); + path.lineTo( (frontCenter.x) * scaleFactor, (frontCenter.y-r1) * scaleFactor); path.closePath(); mainShapes = new RocketComponentShape[] { new RocketComponentShape( path, component) }; } else { - mainShapes = SymmetricComponentShapes.getShapesSide(component, transformation); + mainShapes = SymmetricComponentShapes.getShapesSide(component, transformation, scaleFactor); } Shape foreShoulder=null, aftShoulder=null; @@ -57,7 +57,7 @@ public class TransitionShapes extends RocketComponentShape { final Transformation offsetTransform = Transformation.getTranslationTransform(-transition.getForeShoulderLength(), 0, 0); final Transformation foreShoulderTransform = transformation.applyTransformation(offsetTransform); - foreShoulder = TubeShapes.getShapesSide( foreShoulderTransform, shoulderLength, shoulderRadius); + foreShoulder = TubeShapes.getShapesSide( foreShoulderTransform, shoulderLength, shoulderRadius, scaleFactor); arrayLength++; } if (transition.getAftShoulderLength() > 0.0005) { @@ -66,7 +66,7 @@ public class TransitionShapes extends RocketComponentShape { final Transformation offsetTransform = Transformation.getTranslationTransform(transition.getLength(), 0, 0); final Transformation aftShoulderTransform = transformation.applyTransformation(offsetTransform); - aftShoulder = TubeShapes.getShapesSide(aftShoulderTransform, shoulderLength, shoulderRadius); + aftShoulder = TubeShapes.getShapesSide(aftShoulderTransform, shoulderLength, shoulderRadius, scaleFactor); arrayLength++; } if (foreShoulder==null && aftShoulder==null) diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/TubeShapes.java b/swing/src/net/sf/openrocket/gui/rocketfigure/TubeShapes.java index ebd94cc88..8645499b9 100644 --- a/swing/src/net/sf/openrocket/gui/rocketfigure/TubeShapes.java +++ b/swing/src/net/sf/openrocket/gui/rocketfigure/TubeShapes.java @@ -10,14 +10,19 @@ import net.sf.openrocket.util.Transformation; public class TubeShapes extends RocketComponentShape { + public static Shape getShapesSide( final Transformation transformation, final double length, final double radius ){ + return getShapesSide(transformation, length, radius, 1.0d); + } + + public static Shape getShapesSide( final Transformation transformation, final double length, final double radius, final double scaleFactor ){ final Coordinate instanceAbsoluteLocation = transformation.transform(Coordinate.ZERO); - return new Rectangle2D.Double((instanceAbsoluteLocation.x), //x - the X coordinate of the upper-left corner of the newly constructed Rectangle2D - (instanceAbsoluteLocation.y-radius), // y - the Y coordinate of the upper-left corner of the newly constructed Rectangle2D - length, // w - the width of the newly constructed Rectangle2D - 2*radius); // h - the height of the newly constructed Rectangle2D + return new Rectangle2D.Double((instanceAbsoluteLocation.x) * scaleFactor, //x - the X coordinate of the upper-left corner of the newly constructed Rectangle2D + (instanceAbsoluteLocation.y-radius) * scaleFactor, // y - the Y coordinate of the upper-left corner of the newly constructed Rectangle2D + length * scaleFactor, // w - the width of the newly constructed Rectangle2D + 2*radius * scaleFactor); // h - the height of the newly constructed Rectangle2D } public static Shape getShapesBack( final Transformation transformation, final double radius ) { From d98e2cb6f8bbf7b80157de7ee4afca5f5fffcf5e Mon Sep 17 00:00:00 2001 From: Billy Olsen Date: Tue, 24 Mar 2020 20:01:05 -0700 Subject: [PATCH 7/7] Remove unnecessary override of updateFigure in RocketFigure Previously, updateFigure was overridden in RocketFigure in order to ensure that all component shapes were added to the rocket prior to calling the paintComponent method. This is superfluous as the paintComponent method already adds the shapes prior to rendering. Signed-off-by: Billy Olsen --- .../src/net/sf/openrocket/gui/scalefigure/RocketFigure.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java b/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java index ffb277118..5775390a1 100644 --- a/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java +++ b/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java @@ -315,12 +315,6 @@ public class RocketFigure extends AbstractScaleFigure { } - @Override - public void updateFigure() { - updateShapes(this.figureShapes); - super.updateFigure(); - } - public RocketComponent[] getComponentsByPoint(double x, double y) { // Calculate point in shapes' coordinates Point2D.Double p = new Point2D.Double(x, y);