package net.sf.openrocket.gui.print;
-import net.sf.openrocket.rocketcomponent.Transition;
-
-import java.awt.*;
+import java.awt.BasicStroke;
+import java.awt.Graphics2D;
import java.awt.geom.Arc2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
+import net.sf.openrocket.rocketcomponent.Transition;
+
/**
* This class allows for a Transition to be printable. It does so by decorating an existing transition (which will not be
* modified) and rendering it within a JPanel. The JPanel is not actually visualized on a display, but instead renders
* may be to draw a myriahedral projection that can be cut out and bent to form the shape.
*/
public class PrintableTransition extends AbstractPrintableTransition {
-
- /**
- * Dashed array value.
- */
- private final static float dash1[] = {4.0f};
- /**
- * The dashed stroke for glue tab.
- */
- private final static BasicStroke dashed = new BasicStroke(1.0f,
- BasicStroke.CAP_BUTT,
- BasicStroke.JOIN_MITER,
- 10.0f, dash1, 0.0f);
-
- /**
- * The layout is an outer arc, an inner arc, and two lines one either endpoints that connect the arcs.
- * Most of the math involves transposing geometric cartesian coordinates to the Java AWT coordinate system.
- */
- private Path2D gp;
-
- /**
- * The glue tab.
- */
- private Path2D glueTab1;
-
- /**
- * The alignment marks.
- */
- private Line2D tick1, tick2;
-
- /**
- * The x coordinates for the two ticks drawn at theta degrees.
- */
- private int tick3X, tick4X;
-
- /**
- * The angle, in degrees.
- */
- private float theta;
-
- /**
- * The x,y coordinates for where the virtual circle center is located.
- */
- private int circleCenterX, circleCenterY;
-
- /**
- * Constructor.
- *
- * @param transition the transition to print
- */
- public PrintableTransition(Transition transition) {
- super(false, transition);
- }
-
- @Override
- protected void init(Transition component) {
-
- double r1 = component.getAftRadius();
- double r2 = component.getForeRadius();
-
- //Regardless of orientation, we have the convention of R1 as the smaller radius. Flip if different.
- if (r1 > r2) {
- r1 = r2;
- r2 = component.getAftRadius();
- }
- double len = component.getLength();
- double v = r2 - r1;
- double tmp = Math.sqrt(v * v + len * len);
- double factor = tmp / v;
-
- theta = (float) (360d * v / tmp);
-
- int r1InPoints = (int) PrintUnit.METERS.toPoints(r1 * factor);
- int r2InPoints = (int) PrintUnit.METERS.toPoints(r2 * factor);
-
- int x = marginX;
- int tabOffset = 35;
- int y = tabOffset + marginY;
-
- Arc2D.Double outerArc = new Arc2D.Double();
- Arc2D.Double innerArc = new Arc2D.Double();
-
- //If the arcs are more than 3/4 of a circle, then assume the height (y) is the same as the radius of the bigger arc.
- if (theta >= 270) {
- y += r2InPoints;
- }
- //If the arc is between 1/2 and 3/4 of a circle, then compute the actual height based upon the angle and radius
- //of the bigger arc.
- else if (theta >= 180) {
- double thetaRads = Math.toRadians(theta - 180);
- y += (int) ((Math.cos(thetaRads) * r2InPoints) * Math.tan(thetaRads));
- }
-
- circleCenterY = y;
- circleCenterX = r2InPoints + x;
-
- //Create the larger arc.
- outerArc.setArcByCenter(circleCenterX, circleCenterY, r2InPoints, 180, theta, Arc2D.OPEN);
-
- //Create the smaller arc.
- innerArc.setArcByCenter(circleCenterX, circleCenterY, r1InPoints, 180, theta, Arc2D.OPEN);
-
- //Create the line between the start of the larger arc and the start of the smaller arc.
- Path2D.Double line = new Path2D.Double();
- line.setWindingRule(Path2D.WIND_NON_ZERO);
- line.moveTo(x, y);
- final int width = r2InPoints - r1InPoints;
- line.lineTo(width + x, y);
-
- //Create the line between the endpoint of the larger arc and the endpoint of the smaller arc.
- Path2D.Double closingLine = new Path2D.Double();
- closingLine.setWindingRule(Path2D.WIND_NON_ZERO);
- Point2D innerArcEndPoint = innerArc.getEndPoint();
- closingLine.moveTo(innerArcEndPoint.getX(), innerArcEndPoint.getY());
- Point2D outerArcEndPoint = outerArc.getEndPoint();
- closingLine.lineTo(outerArcEndPoint.getX(), outerArcEndPoint.getY());
-
- //Add all shapes to the polygon path.
- gp = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4);
- gp.append(line, false);
- gp.append(outerArc, false);
- gp.append(closingLine, false);
- gp.append(innerArc, false);
-
- //Create the glue tab.
- glueTab1 = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4);
- glueTab1.moveTo(x, y);
- glueTab1.lineTo(x + tabOffset, y - tabOffset);
- glueTab1.lineTo(width + x - tabOffset, y - tabOffset);
- glueTab1.lineTo(width + x, y);
-
- //Create tick marks for alignment, 1/4 of the width in from either edge
- int fromEdge = width / 4;
- final int tickLength = 8;
- //Upper left
- tick1 = new Line2D.Float(x + fromEdge, y, x + fromEdge, y + tickLength);
- //Upper right
- tick2 = new Line2D.Float(x + width - fromEdge, y, x + width - fromEdge, y + tickLength);
-
- tick3X = r2InPoints - fromEdge;
- tick4X = r1InPoints + fromEdge;
-
- setSize(gp.getBounds().width, gp.getBounds().height + tabOffset);
- }
-
- /**
- * Draw alignment marks on an angle.
- *
- * @param g2 the graphics context
- * @param x the center of the circle's x coordinate
- * @param y the center of the circle's y
- * @param line the line to draw
- * @param theta the angle
- */
- private void drawAlignmentMarks(Graphics2D g2, int x, int y, Line2D.Float line, float theta) {
- g2.translate(x, y);
- g2.rotate(Math.toRadians(-theta));
- g2.draw(line);
- g2.rotate(Math.toRadians(theta));
- g2.translate(-x, -y);
- }
-
- /**
- * Draw a transition.
- *
- * @param g2 the graphics context
- */
- protected void draw(Graphics2D g2) {
- //Render it.
- g2.draw(gp);
- g2.draw(tick1);
- g2.draw(tick2);
- drawAlignmentMarks(g2, circleCenterX,
- circleCenterY,
- new Line2D.Float(-tick3X, 0, -tick3X, -8),
- theta);
- drawAlignmentMarks(g2, circleCenterX,
- circleCenterY,
- new Line2D.Float(-tick4X, 0, -tick4X, -8),
- theta);
-
- g2.setStroke(dashed);
- g2.draw(glueTab1);
- }
-
+
+ /**
+ * Dashed array value.
+ */
+ private final static float dash1[] = { 4.0f };
+ /**
+ * The dashed stroke for glue tab.
+ */
+ private final static BasicStroke dashed = new BasicStroke(1.0f,
+ BasicStroke.CAP_BUTT,
+ BasicStroke.JOIN_MITER,
+ 10.0f, dash1, 0.0f);
+
+ /**
+ * The layout is an outer arc, an inner arc, and two lines one either endpoints that connect the arcs.
+ * Most of the math involves transposing geometric cartesian coordinates to the Java AWT coordinate system.
+ */
+ private Path2D gp;
+
+ /**
+ * The glue tab.
+ */
+ private Path2D glueTab1;
+
+ /**
+ * The alignment marks.
+ */
+ private Line2D tick1, tick2;
+
+ /**
+ * The x coordinates for the two ticks drawn at theta degrees.
+ */
+ private int tick3X, tick4X;
+
+ /**
+ * The angle, in degrees.
+ */
+ private float theta;
+
+ /**
+ * The x,y coordinates for where the virtual circle center is located.
+ */
+ private int circleCenterX, circleCenterY;
+
+ /**
+ * Constructor.
+ *
+ * @param transition the transition to print
+ */
+ public PrintableTransition(Transition transition) {
+ super(false, transition);
+ }
+
+ @Override
+ protected void init(Transition component) {
+
+ double r1 = component.getAftRadius();
+ double r2 = component.getForeRadius();
+
+ //Regardless of orientation, we have the convention of R1 as the smaller radius. Flip if different.
+ if (r1 > r2) {
+ r1 = r2;
+ r2 = component.getAftRadius();
+ }
+ double len = component.getLength();
+ double v = r2 - r1;
+ double tmp = Math.sqrt(v * v + len * len);
+ double factor = tmp / v;
+
+ theta = (float) (360d * v / tmp);
+
+ int r1InPoints = (int) PrintUnit.METERS.toPoints(r1 * factor);
+ int r2InPoints = (int) PrintUnit.METERS.toPoints(r2 * factor);
+
+ int x = marginX;
+ int tabOffset = 35;
+ int y = tabOffset + marginY;
+
+ Arc2D.Double outerArc = new Arc2D.Double();
+ Arc2D.Double innerArc = new Arc2D.Double();
+
+ //If the arcs are more than 3/4 of a circle, then assume the height (y) is the same as the radius of the bigger arc.
+ if (theta >= 270) {
+ y += r2InPoints;
+ }
+ //If the arc is between 1/2 and 3/4 of a circle, then compute the actual height based upon the angle and radius
+ //of the bigger arc.
+ else if (theta >= 180) {
+ double thetaRads = Math.toRadians(theta - 180);
+ y += (int) ((Math.cos(thetaRads) * r2InPoints) * Math.tan(thetaRads));
+ }
+
+ circleCenterY = y;
+ circleCenterX = r2InPoints + x;
+
+ //Create the larger arc.
+ outerArc.setArcByCenter(circleCenterX, circleCenterY, r2InPoints, 180, theta, Arc2D.OPEN);
+
+ //Create the smaller arc.
+ innerArc.setArcByCenter(circleCenterX, circleCenterY, r1InPoints, 180, theta, Arc2D.OPEN);
+
+ //Create the line between the start of the larger arc and the start of the smaller arc.
+ Path2D.Double line = new Path2D.Double();
+ line.setWindingRule(Path2D.WIND_NON_ZERO);
+ line.moveTo(x, y);
+ final int width = r2InPoints - r1InPoints;
+ line.lineTo(width + x, y);
+
+ //Create the line between the endpoint of the larger arc and the endpoint of the smaller arc.
+ Path2D.Double closingLine = new Path2D.Double();
+ closingLine.setWindingRule(Path2D.WIND_NON_ZERO);
+ Point2D innerArcEndPoint = innerArc.getEndPoint();
+ closingLine.moveTo(innerArcEndPoint.getX(), innerArcEndPoint.getY());
+ Point2D outerArcEndPoint = outerArc.getEndPoint();
+ closingLine.lineTo(outerArcEndPoint.getX(), outerArcEndPoint.getY());
+
+ //Add all shapes to the polygon path.
+ gp = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4);
+ gp.append(line, false);
+ gp.append(outerArc, false);
+ gp.append(closingLine, false);
+ gp.append(innerArc, false);
+
+ //Create the glue tab.
+ glueTab1 = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4);
+ glueTab1.moveTo(x, y);
+ glueTab1.lineTo(x + tabOffset, y - tabOffset);
+ glueTab1.lineTo(width + x - tabOffset, y - tabOffset);
+ glueTab1.lineTo(width + x, y);
+
+ //Create tick marks for alignment, 1/4 of the width in from either edge
+ int fromEdge = width / 4;
+ final int tickLength = 8;
+ //Upper left
+ tick1 = new Line2D.Float(x + fromEdge, y, x + fromEdge, y + tickLength);
+ //Upper right
+ tick2 = new Line2D.Float(x + width - fromEdge, y, x + width - fromEdge, y + tickLength);
+
+ tick3X = r2InPoints - fromEdge;
+ tick4X = r1InPoints + fromEdge;
+
+ setSize(gp.getBounds().width, gp.getBounds().height + tabOffset);
+ }
+
+ /**
+ * Draw alignment marks on an angle.
+ *
+ * @param g2 the graphics context
+ * @param x the center of the circle's x coordinate
+ * @param y the center of the circle's y
+ * @param line the line to draw
+ * @param theta the angle
+ */
+ private void drawAlignmentMarks(Graphics2D g2, int x, int y, Line2D.Float line, float theta) {
+ g2.translate(x, y);
+ g2.rotate(Math.toRadians(-theta));
+ g2.draw(line);
+ g2.rotate(Math.toRadians(theta));
+ g2.translate(-x, -y);
+ }
+
+ /**
+ * Draw a transition.
+ *
+ * @param g2 the graphics context
+ */
+ @Override
+ protected void draw(Graphics2D g2) {
+ //Render it.
+ g2.draw(gp);
+ g2.draw(tick1);
+ g2.draw(tick2);
+ drawAlignmentMarks(g2, circleCenterX,
+ circleCenterY,
+ new Line2D.Float(-tick3X, 0, -tick3X, -8),
+ theta);
+ drawAlignmentMarks(g2, circleCenterX,
+ circleCenterY,
+ new Line2D.Float(-tick4X, 0, -tick4X, -8),
+ theta);
+
+ g2.setStroke(dashed);
+ g2.draw(glueTab1);
+ }
+
}