diff --git a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java index 2a43e7279..03b979543 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java +++ b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java @@ -45,6 +45,8 @@ public class BodyTube extends SymmetricComponent implements BoxBounded, MotorMou this.outerRadius = Math.max(radius, 0); this.length = Math.max(length, 0); motors = new MotorConfigurationSet(this); + super.displayOrder_side = 0; // Order for displaying the component in the 2D side view + super.displayOrder_back = 1; // Order for displaying the component in the 2D back view } public BodyTube(double length, double radius, boolean filled) { diff --git a/core/src/net/sf/openrocket/rocketcomponent/Bulkhead.java b/core/src/net/sf/openrocket/rocketcomponent/Bulkhead.java index deedd0814..638c0a8d4 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/Bulkhead.java +++ b/core/src/net/sf/openrocket/rocketcomponent/Bulkhead.java @@ -13,6 +13,8 @@ public class Bulkhead extends RadiusRingComponent { public Bulkhead() { setOuterRadiusAutomatic(true); setLength(0.002); + super.displayOrder_side = 8; // Order for displaying the component in the 2D side view + super.displayOrder_back = 6; // Order for displaying the component in the 2D back view } @Override diff --git a/core/src/net/sf/openrocket/rocketcomponent/CenteringRing.java b/core/src/net/sf/openrocket/rocketcomponent/CenteringRing.java index be94964ec..cc24ce7e5 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/CenteringRing.java +++ b/core/src/net/sf/openrocket/rocketcomponent/CenteringRing.java @@ -13,6 +13,8 @@ public class CenteringRing extends RadiusRingComponent { setOuterRadiusAutomatic(true); setInnerRadiusAutomatic(true); setLength(0.002); + super.displayOrder_side = 7; // Order for displaying the component in the 2D side view + super.displayOrder_back = 5; // Order for displaying the component in the 2D back view } private static final Translator trans = Application.getTranslator(); diff --git a/core/src/net/sf/openrocket/rocketcomponent/EngineBlock.java b/core/src/net/sf/openrocket/rocketcomponent/EngineBlock.java index 748b548ac..0f4a2aee1 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/EngineBlock.java +++ b/core/src/net/sf/openrocket/rocketcomponent/EngineBlock.java @@ -16,6 +16,8 @@ public class EngineBlock extends ThicknessRingComponent implements AxialPosition setOuterRadiusAutomatic(true); setThickness(0.005); setLength(0.005); + super.displayOrder_side = 9; // Order for displaying the component in the 2D side view + super.displayOrder_back = 15; // Order for displaying the component in the 2D back view } @Override diff --git a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java index be8333acf..7c07b0c57 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java @@ -134,6 +134,8 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona public FinSet() { super( AxialMethod.BOTTOM); this.filletMaterial = Application.getPreferences().getDefaultComponentMaterial(this.getClass(), Material.Type.BULK); + super.displayOrder_side = 4; // Order for displaying the component in the 2D side view + super.displayOrder_back = 4; // Order for displaying the component in the 2D back view } @Override diff --git a/core/src/net/sf/openrocket/rocketcomponent/InnerTube.java b/core/src/net/sf/openrocket/rocketcomponent/InnerTube.java index 4d167d58d..bd7cfcd42 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/InnerTube.java +++ b/core/src/net/sf/openrocket/rocketcomponent/InnerTube.java @@ -48,6 +48,9 @@ public class InnerTube extends ThicknessRingComponent implements AxialPositionab this.setLength(0.070); motors = new MotorConfigurationSet(this); + + super.displayOrder_side = 5; // Order for displaying the component in the 2D side view + super.displayOrder_back = 14; // Order for displaying the component in the 2D back view } diff --git a/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java b/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java index 26a4a126c..bf90d26e6 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java +++ b/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java @@ -37,6 +37,8 @@ public class LaunchLug extends ExternalComponent implements AnglePositionable, B radius = 0.01 / 2; thickness = 0.001; length = 0.03; + super.displayOrder_side = 15; // Order for displaying the component in the 2D side view + super.displayOrder_back = 12; // Order for displaying the component in the 2D back view } diff --git a/core/src/net/sf/openrocket/rocketcomponent/MassComponent.java b/core/src/net/sf/openrocket/rocketcomponent/MassComponent.java index 0bfb75c03..7524fc0d4 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/MassComponent.java +++ b/core/src/net/sf/openrocket/rocketcomponent/MassComponent.java @@ -41,11 +41,15 @@ public class MassComponent extends MassObject { public MassComponent() { super(); + super.displayOrder_side = 13; // Order for displaying the component in the 2D side view + super.displayOrder_back = 10; // Order for displaying the component in the 2D back view } public MassComponent(double length, double radius, double mass) { super(length, radius); this.mass = mass; + super.displayOrder_side = 13; // Order for displaying the component in the 2D side view + super.displayOrder_back = 10; // Order for displaying the component in the 2D back view } diff --git a/core/src/net/sf/openrocket/rocketcomponent/NoseCone.java b/core/src/net/sf/openrocket/rocketcomponent/NoseCone.java index bc9855953..a7316fdb3 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/NoseCone.java +++ b/core/src/net/sf/openrocket/rocketcomponent/NoseCone.java @@ -42,6 +42,9 @@ public class NoseCone extends Transition implements InsideColorComponent { super.setAftRadiusAutomatic(false); super.setAftRadius(radius); + + super.displayOrder_side = 1; // Order for displaying the component in the 2D side view + super.displayOrder_back = 0; // Order for displaying the component in the 2D back view } diff --git a/core/src/net/sf/openrocket/rocketcomponent/Parachute.java b/core/src/net/sf/openrocket/rocketcomponent/Parachute.java index aabb6117f..721d5fab3 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/Parachute.java +++ b/core/src/net/sf/openrocket/rocketcomponent/Parachute.java @@ -23,6 +23,8 @@ public class Parachute extends RecoveryDevice { this.diameter = 0.3; this.lineMaterial = Application.getPreferences().getDefaultComponentMaterial(Parachute.class, Material.Type.LINE); this.lineLength = 0.3; + super.displayOrder_side = 11; // Order for displaying the component in the 2D side view + super.displayOrder_back = 9; // Order for displaying the component in the 2D back view } diff --git a/core/src/net/sf/openrocket/rocketcomponent/RailButton.java b/core/src/net/sf/openrocket/rocketcomponent/RailButton.java index 5ce537034..9a7a637bf 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/RailButton.java +++ b/core/src/net/sf/openrocket/rocketcomponent/RailButton.java @@ -69,12 +69,16 @@ public class RailButton extends ExternalComponent implements AnglePositionable, this.setStandoff( 0.002); this.setInstanceSeparation( this.outerDiameter_m * 6); this.setMaterial(Databases.findMaterial(Material.Type.BULK, "Delrin")); + super.displayOrder_side = 14; // Order for displaying the component in the 2D side view + super.displayOrder_back = 11; // Order for displaying the component in the 2D back view } public RailButton( final double od, final double ht ) { this(); this.setOuterDiameter( od); this.setTotalHeight( ht); + super.displayOrder_side = 14; // Order for displaying the component in the 2D side view + super.displayOrder_back = 11; // Order for displaying the component in the 2D back view } public RailButton( final double od, final double id, final double ht, final double flangeThickness, final double _standoff ) { @@ -86,6 +90,8 @@ public class RailButton extends ExternalComponent implements AnglePositionable, this.setStandoff( _standoff); this.setInstanceSeparation( od*2); this.setMaterial(Databases.findMaterial(Material.Type.BULK, "Delrin")); + super.displayOrder_side = 14; // Order for displaying the component in the 2D side view + super.displayOrder_back = 11; // Order for displaying the component in the 2D back view } private static final RailButton make1010Button(){ diff --git a/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java b/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java index 269ec1813..92c8f3fea 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java +++ b/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java @@ -126,8 +126,17 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab * Used to invalidate the component after calling {@link #copyFrom(RocketComponent)}. */ private Invalidator invalidator = new Invalidator(this); - - + + + /** + * This is for determining the order in which the component should be drawn in the 2D views, both + * in the side view and in the back view. + * Lower values will be placed more in the back, higher values more in the front. + * A high enough init value is picked to not mess with pre-defined values. + */ + protected int displayOrder_side = 100; + protected int displayOrder_back = 100; + //// NOTE !!! All fields must be copied in the method copyFrom()! //// @@ -2014,6 +2023,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab this.name = src.name; this.comment = src.comment; this.id = src.id; + this.displayOrder_side = src.displayOrder_side; + this.displayOrder_back = src.displayOrder_back; // Add source components to invalidation tree for (RocketComponent c : src) { @@ -2229,4 +2240,19 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab return false; } + public int getDisplayOrder_side() { + return displayOrder_side; + } + + public void setDisplayOrder_side(int displayOrder_side) { + this.displayOrder_side = displayOrder_side; + } + + public int getDisplayOrder_back() { + return displayOrder_back; + } + + public void setDisplayOrder_back(int displayOrder_back) { + this.displayOrder_back = displayOrder_back; + } } diff --git a/core/src/net/sf/openrocket/rocketcomponent/ShockCord.java b/core/src/net/sf/openrocket/rocketcomponent/ShockCord.java index 8012a87e1..d2f9cc7fa 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/ShockCord.java +++ b/core/src/net/sf/openrocket/rocketcomponent/ShockCord.java @@ -15,6 +15,8 @@ public class ShockCord extends MassObject { public ShockCord() { material = Application.getPreferences().getDefaultComponentMaterial(ShockCord.class, Material.Type.LINE); cordLength = 0.4; + super.displayOrder_side = 12; // Order for displaying the component in the 2D side view + super.displayOrder_back = 7; // Order for displaying the component in the 2D back view } diff --git a/core/src/net/sf/openrocket/rocketcomponent/Streamer.java b/core/src/net/sf/openrocket/rocketcomponent/Streamer.java index 058392e93..33352590e 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/Streamer.java +++ b/core/src/net/sf/openrocket/rocketcomponent/Streamer.java @@ -21,6 +21,8 @@ public class Streamer extends RecoveryDevice { public Streamer() { this.stripLength = 0.5; this.stripWidth = 0.05; + super.displayOrder_side = 10; // Order for displaying the component in the 2D side view + super.displayOrder_back = 8; // Order for displaying the component in the 2D back view } diff --git a/core/src/net/sf/openrocket/rocketcomponent/Transition.java b/core/src/net/sf/openrocket/rocketcomponent/Transition.java index f8852c12a..304750066 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/Transition.java +++ b/core/src/net/sf/openrocket/rocketcomponent/Transition.java @@ -58,6 +58,9 @@ public class Transition extends SymmetricComponent implements InsideColorCompone this.type = Shape.CONICAL; this.shapeParameter = 0; this.clipped = true; + + super.displayOrder_side = 2; // Order for displaying the component in the 2D side view + super.displayOrder_back = 2; // Order for displaying the component in the 2D back view } //////// Length //////// diff --git a/core/src/net/sf/openrocket/rocketcomponent/TubeCoupler.java b/core/src/net/sf/openrocket/rocketcomponent/TubeCoupler.java index 4f50099c3..14b3ad233 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/TubeCoupler.java +++ b/core/src/net/sf/openrocket/rocketcomponent/TubeCoupler.java @@ -13,6 +13,8 @@ public class TubeCoupler extends ThicknessRingComponent implements RadialParent setOuterRadiusAutomatic(true); setThickness(0.002); setLength(0.06); + super.displayOrder_side = 6; // Order for displaying the component in the 2D side view + super.displayOrder_back = 13; // Order for displaying the component in the 2D back view } @Override diff --git a/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java b/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java index 4dd4843b6..1dcc33dd2 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java @@ -56,6 +56,8 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable, public TubeFinSet() { super(AxialMethod.BOTTOM); length = 0.10; + super.displayOrder_side = 3; // Order for displaying the component in the 2D side view + super.displayOrder_back = 3; // Order for displaying the component in the 2D back view } public void setLength(double length) { diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/RocketComponentShape.java b/swing/src/net/sf/openrocket/gui/rocketfigure/RocketComponentShape.java index 29603ffc3..8bc9cf7a3 100644 --- a/swing/src/net/sf/openrocket/gui/rocketfigure/RocketComponentShape.java +++ b/swing/src/net/sf/openrocket/gui/rocketfigure/RocketComponentShape.java @@ -71,6 +71,4 @@ public class RocketComponentShape { } return toReturn; } - - } diff --git a/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java b/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java index a5574267b..ab3330a0b 100644 --- a/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java +++ b/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java @@ -14,8 +14,7 @@ import java.awt.geom.Ellipse2D; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.LinkedHashSet; +import java.util.*; import java.util.Map.Entry; import org.slf4j.Logger; @@ -74,10 +73,15 @@ public class RocketFigure extends AbstractScaleFigure { private double rotation; private Transformation axialRotation; - /* - * figureComponents contains the corresponding RocketComponents of the figureShapes + /** + * The shapes to be drawn are stored in this Priority Queue, where the first shape to be drawn is the one with + * the highest priority, namely being the one where the corresponding RocketComponent has the highest displayOrder + * (declared in RocketComponent, can be overridden in separate components). */ - private final ArrayList figureShapes = new ArrayList(); + private final PriorityQueue figureShapes_side = new PriorityQueue<>( + Comparator.comparingInt(o -> -o.component.getDisplayOrder_side())); + private final PriorityQueue figureShapes_back = new PriorityQueue<>( + Comparator.comparingInt(o -> -o.component.getDisplayOrder_back())); private final ArrayList relativeExtra = new ArrayList(); @@ -190,13 +194,23 @@ public class RocketFigure extends AbstractScaleFigure { Graphics2D g2 = (Graphics2D) g; AffineTransform baseTransform = g2.getTransform(); + + PriorityQueue figureShapes; + if (currentViewType == RocketPanel.VIEW_TYPE.SideView) + figureShapes = figureShapes_side; + else if (currentViewType == RocketPanel.VIEW_TYPE.BackView) + figureShapes = figureShapes_back; + else { + log.warn("Unknown view type for paintComponent"); + return; + } updateSubjectDimensions(); updateCanvasOrigin(); updateCanvasSize(); updateTransform(); - updateShapes(this.figureShapes); + updateShapes(figureShapes); g2.transform(projection); @@ -207,12 +221,12 @@ public class RocketFigure extends AbstractScaleFigure { RenderingHints.VALUE_RENDER_QUALITY); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - - int shapeCount = figureShapes.size(); + // Draw all shapes - for (int i = 0; i < shapeCount; i++) { - RocketComponentShape rcs = figureShapes.get(i); - RocketComponent c = rcs.getComponent(); + PriorityQueue figureShapesCopy = new PriorityQueue<>(figureShapes); + while (!figureShapesCopy.isEmpty()) { + RocketComponentShape rcs = figureShapesCopy.poll(); + RocketComponent c = rcs.getComponent(); boolean selected = false; // Check if component is in the selection @@ -330,16 +344,27 @@ public class RocketFigure extends AbstractScaleFigure { } LinkedHashSet l = new LinkedHashSet(); - - for (int i = 0; i < figureShapes.size(); i++) { - RocketComponentShape rcs = this.figureShapes.get(i); + + PriorityQueue figureShapes; + if (currentViewType == RocketPanel.VIEW_TYPE.SideView) + figureShapes = figureShapes_side; + else if (currentViewType == RocketPanel.VIEW_TYPE.BackView) + figureShapes = figureShapes_back; + else { + log.warn("Unknown view type for getComponentsByPoint"); + return null; + } + + PriorityQueue figureShapesCopy = new PriorityQueue<>(figureShapes); + while (!figureShapesCopy.isEmpty()) { + RocketComponentShape rcs = figureShapesCopy.poll(); if (rcs.shape.contains(p)) l.add(rcs.component); } return l.toArray(new RocketComponent[0]); } - private void updateShapes(ArrayList allShapes) { + private void updateShapes(PriorityQueue allShapes) { // source input final FlightConfiguration config = rocket.getSelectedConfiguration(); @@ -369,8 +394,8 @@ public class RocketFigure extends AbstractScaleFigure { * * @return the ArrayList containing all the shapes to draw. */ - private static ArrayList addThisShape( - ArrayList allShapes, // this is the output parameter + private static PriorityQueue addThisShape( + PriorityQueue allShapes, // this is the output parameter final RocketPanel.VIEW_TYPE viewType, final RocketComponent component, final Transformation transformation) { @@ -405,9 +430,7 @@ public class RocketFigure extends AbstractScaleFigure { RocketComponentShape[] returnValue = (RocketComponentShape[]) m.invokeStatic(component, transformation); - for ( RocketComponentShape curShape : returnValue ){ - allShapes.add( curShape ); - } + allShapes.addAll(Arrays.asList(returnValue)); return allShapes; }