package net.sf.openrocket.gui.print;
+import net.sf.openrocket.rocketcomponent.Transition;
+
import java.awt.BasicStroke;
-import java.awt.Graphics;
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 java.awt.print.PageFormat;
-import java.awt.print.Printable;
-import java.awt.print.PrinterException;
-
-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
* Note: Currently nose cones are only supported by drawing the 2D projection of the profile. A more useful approach
* may be to draw a myriahedral projection that can be cut out and bent to form the shape.
*/
-public class PrintableTransition extends AbstractPrintableTransition {
-
+public class PrintableTransition extends AbstractPrintable<Transition> {
+
/**
* Dashed array value.
*/
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.
*
public PrintableTransition(Transition transition) {
super(false, transition);
}
-
+
+ /**
+ * Compute the basic values of each arc of the transition/shroud. This is adapted from
+ * <a href="http://www.rocketshoppe.com/info/Transitions.pdf">The Properties of
+ * Model Rocket Body Tube Transitions, by J.R. Brohm</a>
+ *
+ * @param component the component
+ */
@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;
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 x = 0;
int tabOffset = 35;
- int y = tabOffset + marginY;
-
+ int y = tabOffset;
+
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;
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);
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;
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.
*
g2.rotate(Math.toRadians(theta));
g2.translate(-x, -y);
}
-
+
/**
* Draw a transition.
*
circleCenterY,
new Line2D.Float(-tick4X, 0, -tick4X, -8),
theta);
-
+
g2.setStroke(dashed);
g2.draw(glueTab1);
}
-
+
}