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/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/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..fe11df0dc 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)); } @@ -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 d95f9fb8f..dda55bd73 100644 --- a/swing/src/net/sf/openrocket/gui/print/DesignReport.java +++ b/swing/src/net/sf/openrocket/gui/print/DesignReport.java @@ -28,7 +28,9 @@ 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; import net.sf.openrocket.rocketcomponent.FlightConfiguration; import net.sf.openrocket.rocketcomponent.FlightConfigurationId; @@ -162,7 +164,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(); @@ -177,8 +179,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); @@ -190,8 +192,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 { @@ -213,7 +214,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 +228,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 +277,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); @@ -326,30 +330,26 @@ public class DesignReport { DecimalFormat ttwFormat = new DecimalFormat("0.00"); - 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); - FlightConfiguration config = rocket.getFlightConfiguration( motorId); + FlightConfiguration config = rocket.getFlightConfiguration(motorId); int totalMotorCount = 0; double totalPropMass = 0; 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++; - stageMass = massCalc.getCGAnalysis( config).get(stage).weight; + config.activateStagesThrough((AxialStage) c); + RigidBody launchInfo = MassCalculator.calculateLaunch(config); + stageMass = launchInfo.getMass(); // Calculate total thrust-to-weight from only lowest stage motors totalTTW = 0; topBorder = true; @@ -358,55 +358,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; } } 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/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 ) {