1 package net.sf.openrocket.gui.print;
3 import net.sf.openrocket.gui.print.visitor.CenteringRingStrategy;
4 import net.sf.openrocket.rocketcomponent.CenteringRing;
5 import net.sf.openrocket.rocketcomponent.ClusterConfiguration;
6 import net.sf.openrocket.rocketcomponent.InnerTube;
7 import net.sf.openrocket.util.ArrayList;
8 import net.sf.openrocket.util.Coordinate;
10 import java.awt.Color;
11 import java.awt.Graphics;
12 import java.awt.Graphics2D;
13 import java.awt.Shape;
14 import java.awt.geom.Ellipse2D;
15 import java.util.HashSet;
16 import java.util.List;
20 * This class creates a renderable centering ring. It depends only on AWT/Swing and can be called from other actors
21 * (like iText handlers) to render the centering ring on different graphics contexts.
23 public class PrintableCenteringRing extends AbstractPrintable<CenteringRing> {
25 * If the component to be drawn is a centering ring, save a reference to it.
27 private CenteringRing target;
30 * The line length of the cross hairs.
32 private final int lineLength = 10;
35 * A set of the inner 'holes'. At least one, but will have many if clustered.
37 private Set<CenteringRingStrategy.Dimension> innerCenterPoints = new HashSet<CenteringRingStrategy.Dimension>();
40 * Construct a simple, non-clustered, printable centering ring, or if the motor mount represents a clustered
41 * configuration then get the cluster points to create the centering ring.
43 * @param theRing the component to print
44 * @param theMotorMount the motor mount if clustered, else null
46 private PrintableCenteringRing(CenteringRing theRing, InnerTube theMotorMount) {
47 super(false, theRing);
48 if (theMotorMount == null || theMotorMount.getClusterConfiguration().equals(ClusterConfiguration.SINGLE)) {
50 final float v = (float) PrintUnit.METERS.toPoints(target.getOuterRadius());
51 innerCenterPoints.add(
52 new CenteringRingStrategy.Dimension(v, v,
53 (float) PrintUnit.METERS.toPoints((target.getInnerRadius()))));
56 List<Coordinate> coords = theMotorMount.getClusterPoints();
57 List<Coordinate> points = new ArrayList<Coordinate>();
58 for (Coordinate coordinate : coords) {
59 points.add(coordinate.setX(theMotorMount.getOuterRadius()));
61 populateCenterPoints(points);
66 * Constructor for a clustered centering ring. This version is for a "split cluster", where each motor mount tube
67 * is a distinct entity.
69 * @param theRing the centering ring component
70 * @param theMotorMounts a list of the motor mount tubes that are physically supported by the centering ring
72 private PrintableCenteringRing(CenteringRing theRing, List<InnerTube> theMotorMounts) {
73 super(false, theRing);
74 List<Coordinate> points = new ArrayList<Coordinate>();
75 //Transform the radial positions of the tubes.
76 for (InnerTube it : theMotorMounts) {
77 if (it.getClusterCount() > 1) {
78 List<Coordinate> c = it.getClusterPoints();
79 for (Coordinate coordinate : c) {
80 points.add(coordinate.setX(it.getOuterRadius()));
84 double y = it.getRadialShiftY();
85 double z = it.getRadialShiftZ();
86 Coordinate coordinate = new Coordinate(it.getOuterRadius(), y, z);
87 points.add(coordinate);
90 populateCenterPoints(points);
94 * Factory method to create a printable centering ring.
96 * @param theRing the component to print
97 * @param theMotorMounts the motor mount if clustered, else null
99 public static PrintableCenteringRing create(CenteringRing theRing, List<InnerTube> theMotorMounts) {
100 if (theMotorMounts == null) {
101 return new PrintableCenteringRing(theRing, (InnerTube) null);
103 else if (theMotorMounts.size() <= 1) {
104 return new PrintableCenteringRing(theRing, theMotorMounts.isEmpty() ? null : theMotorMounts.get(0));
107 return new PrintableCenteringRing(theRing, theMotorMounts);
112 * Initialize the set of center points for each motor mount tube, based on the tube coordinates.
114 * @param theCoords the list of tube coordinates; each coordinate is in the OR units (meters) and must be
115 * transformed to the printing (points) coordinate system
117 private void populateCenterPoints(final List<Coordinate> theCoords) {
118 float radius = (float) PrintUnit.METERS.toPoints(target.getOuterRadius());
119 for (Coordinate coordinate : theCoords) {
120 innerCenterPoints.add(new CenteringRingStrategy.Dimension(
121 (float) PrintUnit.METERS.toPoints(coordinate.y) + radius, //center point x
122 (float) PrintUnit.METERS.toPoints(coordinate.z) + radius, //center point y
123 (float) PrintUnit.METERS.toPoints(coordinate.x))); //radius of motor mount
128 * @param component the centering ring component
131 protected void init(final CenteringRing component) {
135 double radius = target.getOuterRadius();
136 setSize((int) PrintUnit.METERS.toPoints(2 * radius),
137 (int) PrintUnit.METERS.toPoints(2 * radius));
141 * Draw a centering ring.
143 * @param g2 the graphics context
146 protected void draw(Graphics2D g2) {
147 double radius = PrintUnit.METERS.toPoints(target.getOuterRadius());
149 Color original = g2.getBackground();
150 Shape outerCircle = new Ellipse2D.Double(0, 0, radius * 2, radius * 2);
151 g2.setColor(Color.lightGray);
152 g2.fill(outerCircle);
153 g2.setColor(Color.black);
154 g2.draw(outerCircle);
156 for (CenteringRingStrategy.Dimension next : innerCenterPoints) {
157 drawInnerCircle(g2, next.getWidth(), next.getHeight(), next.getBreadth());
159 g2.setColor(original);
163 * Draw one inner circle, representing the motor mount tube, with cross hairs in the center.
165 * @param g2 the graphics context
166 * @param theCenterX the center x in points
167 * @param theCenterY the center y in points
169 private void drawInnerCircle(final Graphics2D g2, final double theCenterX, final double theCenterY,
170 final double innerRadius) {
171 Shape innerCircle = new Ellipse2D.Double(theCenterX - innerRadius, theCenterY - innerRadius, innerRadius * 2, innerRadius * 2);
172 g2.setColor(Color.white);
173 g2.fill(innerCircle);
174 g2.setColor(Color.black);
175 g2.draw(innerCircle);
177 drawCross(g2, (int) theCenterX, (int) theCenterY, lineLength, lineLength);
181 * Draw the center cross-hair.
183 * @param g the graphics context
184 * @param x the x coordinate of the center point
185 * @param y the y coordinate of the center point
186 * @param width the width in pixels of the horizontal hair
187 * @param height the width in pixels of the vertical hair
189 private void drawCross(Graphics g, int x, int y, int width, int height) {
190 g.setColor(Color.black);
191 ((Graphics2D) g).setStroke(thinStroke);
192 g.drawLine(x - width / 2, y, x + width / 2, y);
193 g.drawLine(x, y - height / 2, x, y + height / 2);