OpenRocketPrintable.Noseconetemplates = Nose Cone templates
OpenRocketPrintable.Finmarkingguide = Fin marking guide
OpenRocketPrintable.DesignReport = Design Report
+OpenRocketPrintable.Centeringringtemplates = Centering Ring templates
OpenRocketDocument.Redo = Redo
OpenRocketDocument.Undo = Undo
--- /dev/null
+package net.sf.openrocket.gui.print;
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+
+public abstract class AbstractPrintable<T> extends PrintableComponent {
+ /**
+ * A thin stroke.
+ */
+ public final static BasicStroke thinStroke = new BasicStroke(1.0f);
+
+ /**
+ * A thick stroke.
+ */
+ public final static BasicStroke thickStroke = new BasicStroke(4.0f);
+
+ /**
+ * The X margin.
+ */
+ protected int marginX = (int) PrintUnit.INCHES.toPoints(0.25f);
+
+ /**
+ * The Y margin.
+ */
+ protected int marginY = (int) PrintUnit.INCHES.toPoints(0.25f);
+
+ /**
+ * Constructor. Initialize this printable with the component to be printed.
+ *
+ * @param isDoubleBuffered a boolean, true for double-buffering
+ * @param transition the component to be printed
+ */
+ public AbstractPrintable(boolean isDoubleBuffered, T transition) {
+ init(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 transition component
+ */
+ protected abstract void init(T component);
+
+ /**
+ * Draw the component onto the graphics context.
+ *
+ * @param g2 the graphics context
+ */
+ protected abstract void draw(Graphics2D g2);
+
+ /**
+ * Returns a generated image of the transition. May then be used wherever AWT images can be used, or converted to
+ * another image/picture format and used accordingly.
+ *
+ * @return an awt image of the transition
+ */
+ public Image createImage() {
+ int width = getWidth() + marginX;
+ int height = getHeight() + marginY;
+ // Create a buffered image in which to draw
+ BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ // Create a graphics contents on the buffered image
+ Graphics2D g2d = bufferedImage.createGraphics();
+ // Draw graphics
+ g2d.setBackground(Color.white);
+ g2d.clearRect(0, 0, width, height);
+ paintComponent(g2d);
+ // Graphics context no longer needed so dispose it
+ g2d.dispose();
+ return bufferedImage;
+ }
+
+ @Override
+ public void paintComponent(Graphics g) {
+ Graphics2D g2 = (Graphics2D) g;
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+
+ g2.setColor(Color.BLACK);
+ g2.setStroke(thinStroke);
+ g2.translate(getOffsetX(), getOffsetY());
+
+ draw(g2);
+ }
+}
+++ /dev/null
-package net.sf.openrocket.gui.print;
-
-import net.sf.openrocket.rocketcomponent.Transition;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.image.BufferedImage;
-
-public abstract class AbstractPrintableTransition extends PrintableComponent {
- /**
- * The stroke of the transition arc.
- */
- private final static BasicStroke thinStroke = new BasicStroke(1.0f);
-
- /**
- * The X margin.
- */
- protected int marginX = (int) PrintUnit.INCHES.toPoints(0.25f);
-
- /**
- * The Y margin.
- */
- protected int marginY = (int) PrintUnit.INCHES.toPoints(0.25f);
-
- /**
- * Constructor. Initialize this printable with the component to be printed.
- *
- * @param isDoubleBuffered a boolean, true for double-buffering
- * @param transition the component to be printed
- */
- public AbstractPrintableTransition(boolean isDoubleBuffered, Transition transition) {
- init(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 transition component
- */
- protected abstract void init(Transition component);
-
- /**
- * Draw the component onto the graphics context.
- *
- * @param g2 the graphics context
- */
- protected abstract void draw(Graphics2D g2);
-
- /**
- * Returns a generated image of the transition. May then be used wherever AWT images can be used, or converted to
- * another image/picture format and used accordingly.
- *
- * @return an awt image of the fin set
- */
- public Image createImage() {
- int width = getWidth() + marginX;
- int height = getHeight() + marginY;
- // Create a buffered image in which to draw
- BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
- // Create a graphics contents on the buffered image
- Graphics2D g2d = bufferedImage.createGraphics();
- // Draw graphics
- g2d.setBackground(Color.white);
- g2d.clearRect(0, 0, width, height);
- paintComponent(g2d);
- // Graphics context no longer needed so dispose it
- g2d.dispose();
- return bufferedImage;
- }
-
- @Override
- public void paintComponent(Graphics g) {
- Graphics2D g2 = (Graphics2D) g;
- g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
- RenderingHints.VALUE_ANTIALIAS_ON);
-
- g2.setColor(Color.BLACK);
- g2.setStroke(thinStroke);
- g2.translate(getOffsetX(), getOffsetY());
-
- draw(g2);
- }
-}
NOSE_CONE_TEMPLATE("OpenRocketPrintable.Noseconetemplates", false, 3),
// Transition Templates
TRANSITION_TEMPLATE("OpenRocketPrintable.Transitiontemplates", false, 4),
+ // Centering Ring Templates
+ CENTERING_RING_TEMPLATE("OpenRocketPrintable.Centeringringtemplates", false, 5),
// Finset shape
- FIN_TEMPLATE("OpenRocketPrintable.Fintemplates", true, 5),
+ FIN_TEMPLATE("OpenRocketPrintable.Fintemplates", true, 6),
// Fin marking guide.
- FIN_MARKING_GUIDE("OpenRocketPrintable.Finmarkingguide", false, 6);
-
+ FIN_MARKING_GUIDE("OpenRocketPrintable.Finmarkingguide", false, 7);
+
private static final Translator trans = Application.getTranslator();
-
+
/**
* The description - will be displayed in the JTree.
*/
private String description;
-
+
/**
* Flag that indicates if the enum value is different depending upon stage.
*/
private boolean stageSpecific;
-
+
/**
* The order of the item as it appears in the printed document.
*/
private int order;
-
+
/**
* Constructor.
*
stageSpecific = staged;
order = idx;
}
-
+
/**
* Get the description of this printable.
*
public String getDescription() {
return trans.get(description);
}
-
+
/**
* Answers if this enum value has different meaning depending upon the stage.
*
public boolean isStageSpecific() {
return stageSpecific;
}
-
+
/**
* Answer the print order. This is relative to other enum values. No two enum values will have the same print
* order value.
public int getPrintOrder() {
return order;
}
-
+
/**
* Look up an enum value based on the description.
*
}
return null;
}
-
+
/**
* Get a list of ordered enum values that do not have stage affinity.
*
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfWriter;
import net.sf.openrocket.document.OpenRocketDocument;
-import net.sf.openrocket.gui.print.visitor.PageFitPrintStrategy;
+import net.sf.openrocket.gui.print.visitor.CenteringRingStrategy;
import net.sf.openrocket.gui.print.visitor.FinMarkingGuideStrategy;
import net.sf.openrocket.gui.print.visitor.FinSetPrintStrategy;
+import net.sf.openrocket.gui.print.visitor.PageFitPrintStrategy;
import net.sf.openrocket.gui.print.visitor.PartsDetailVisitorStrategy;
import net.sf.openrocket.gui.print.visitor.TransitionStrategy;
* file.
*/
public class PrintController {
-
- /**
- * Print the selected components to a PDF document.
- *
- * @param doc the OR document
- * @param toBePrinted the user chosen items to print
- * @param outputFile the file being written to
- * @param settings the print settings
+
+ /**
+ * Print the selected components to a PDF document.
+ *
+ * @param doc the OR document
+ * @param toBePrinted the user chosen items to print
+ * @param outputFile the file being written to
+ * @param settings the print settings
* @param rotation the angle the rocket figure is rotated
- */
- public void print(OpenRocketDocument doc, Iterator<PrintableContext> toBePrinted, OutputStream outputFile,
- PrintSettings settings, double rotation) {
-
- Document idoc = new Document(getSize(settings));
- PdfWriter writer = null;
- try {
- writer = PdfWriter.getInstance(idoc, outputFile);
- writer.setStrictImageSequence(true);
-
- writer.addViewerPreference(PdfName.PRINTSCALING, PdfName.NONE);
- writer.addViewerPreference(PdfName.PICKTRAYBYPDFSIZE, PdfBoolean.PDFTRUE);
- try {
- idoc.open();
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- }
-
- // Used to combine multiple components onto fewer sheets of paper
- PageFitPrintStrategy pageFitPrint = new PageFitPrintStrategy(idoc, writer);
-
- while (toBePrinted.hasNext()) {
- PrintableContext printableContext = toBePrinted.next();
-
- Set<Integer> stages = printableContext.getStageNumber();
-
- switch (printableContext.getPrintable()) {
- case DESIGN_REPORT:
- DesignReport dp = new DesignReport(doc, idoc, rotation);
- dp.writeToDocument(writer);
- idoc.newPage();
- break;
- case FIN_TEMPLATE:
- final FinSetPrintStrategy finWriter = new FinSetPrintStrategy(idoc, writer, stages, pageFitPrint);
- finWriter.writeToDocument(doc.getRocket());
- break;
- case PARTS_DETAIL:
- final PartsDetailVisitorStrategy detailVisitor = new PartsDetailVisitorStrategy(idoc, writer, stages);
- detailVisitor.writeToDocument(doc.getRocket());
- detailVisitor.close();
- idoc.newPage();
- break;
- case TRANSITION_TEMPLATE:
- final TransitionStrategy tranWriter = new TransitionStrategy(idoc, writer, stages, pageFitPrint);
- tranWriter.writeToDocument(doc.getRocket(), false);
- idoc.newPage();
- break;
-
- case NOSE_CONE_TEMPLATE:
- final TransitionStrategy coneWriter = new TransitionStrategy(idoc, writer, stages, pageFitPrint);
- coneWriter.writeToDocument(doc.getRocket(), true);
- idoc.newPage();
- break;
-
- case FIN_MARKING_GUIDE:
- final FinMarkingGuideStrategy fmg = new FinMarkingGuideStrategy(idoc, writer);
- fmg.writeToDocument(doc.getRocket());
- idoc.newPage();
- break;
+ */
+ public void print(OpenRocketDocument doc, Iterator<PrintableContext> toBePrinted, OutputStream outputFile,
+ PrintSettings settings, double rotation) {
+
+ Document idoc = new Document(getSize(settings));
+ PdfWriter writer = null;
+ try {
+ writer = PdfWriter.getInstance(idoc, outputFile);
+ writer.setStrictImageSequence(true);
+
+ writer.addViewerPreference(PdfName.PRINTSCALING, PdfName.NONE);
+ writer.addViewerPreference(PdfName.PICKTRAYBYPDFSIZE, PdfBoolean.PDFTRUE);
+ try {
+ idoc.open();
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e) {
+ }
+
+ // Used to combine multiple components onto fewer sheets of paper
+ PageFitPrintStrategy pageFitPrint = new PageFitPrintStrategy(idoc, writer);
+
+ while (toBePrinted.hasNext()) {
+ PrintableContext printableContext = toBePrinted.next();
+
+ Set<Integer> stages = printableContext.getStageNumber();
+
+ switch (printableContext.getPrintable()) {
+ case DESIGN_REPORT:
+ DesignReport dp = new DesignReport(doc, idoc, rotation);
+ dp.writeToDocument(writer);
+ idoc.newPage();
+ break;
+ case FIN_TEMPLATE:
+ final FinSetPrintStrategy finWriter = new FinSetPrintStrategy(idoc, writer, stages, pageFitPrint);
+ finWriter.writeToDocument(doc.getRocket());
+ break;
+ case PARTS_DETAIL:
+ final PartsDetailVisitorStrategy detailVisitor = new PartsDetailVisitorStrategy(idoc, writer, stages);
+ detailVisitor.writeToDocument(doc.getRocket());
+ detailVisitor.close();
+ idoc.newPage();
+ break;
+ case TRANSITION_TEMPLATE:
+ final TransitionStrategy tranWriter = new TransitionStrategy(idoc, writer, stages, pageFitPrint);
+ tranWriter.writeToDocument(doc.getRocket(), false);
+ idoc.newPage();
+ break;
+
+ case NOSE_CONE_TEMPLATE:
+ final TransitionStrategy coneWriter = new TransitionStrategy(idoc, writer, stages, pageFitPrint);
+ coneWriter.writeToDocument(doc.getRocket(), true);
+ idoc.newPage();
+ break;
+
+ case CENTERING_RING_TEMPLATE:
+ final CenteringRingStrategy crWriter = new CenteringRingStrategy(idoc, writer, stages,
+ pageFitPrint);
+ crWriter.writeToDocument(doc.getRocket());
+ idoc.newPage();
+ break;
+
+ case FIN_MARKING_GUIDE:
+ final FinMarkingGuideStrategy fmg = new FinMarkingGuideStrategy(idoc, writer);
+ fmg.writeToDocument(doc.getRocket());
+ idoc.newPage();
+ break;
+ }
+ }
+ // Write out parts that we are going to combine onto single sheets of paper
+ pageFitPrint.writeToDocument(doc.getRocket());
+ idoc.newPage();
+
+ //Stupid iText throws a really nasty exception if there is no data when close is called.
+ if (writer.getCurrentDocumentSize() <= 140) {
+ writer.setPageEmpty(false);
+ }
+ writer.close();
+ idoc.close();
+ }
+ catch (DocumentException e) {
+ }
+ catch (ExceptionConverter ec) {
+ }
+ finally {
+ if (outputFile != null) {
+ try {
+ outputFile.close();
+ }
+ catch (IOException e) {
}
- }
- // Write out parts that we are going to combine onto single sheets of paper
- pageFitPrint.writeToDocument(doc.getRocket());
- idoc.newPage();
-
- //Stupid iText throws a really nasty exception if there is no data when close is called.
- if (writer.getCurrentDocumentSize() <= 140) {
- writer.setPageEmpty(false);
- }
- writer.close();
- idoc.close();
- } catch (DocumentException e) {
- } catch (ExceptionConverter ec) {
- } finally {
- if (outputFile != null) {
- try {
- outputFile.close();
- } catch (IOException e) {
- }
- }
- }
- }
-
- /**
- * Get the correct paper size from the print settings.
- *
- * @param settings the print settings
- * @return the paper size
- */
- private Rectangle getSize(PrintSettings settings) {
- PaperSize size = settings.getPaperSize();
- PaperOrientation orientation = settings.getPaperOrientation();
- return orientation.orient(size.getSize());
- }
-
+ }
+ }
+ }
+
+ /**
+ * Get the correct paper size from the print settings.
+ *
+ * @param settings the print settings
+ *
+ * @return the paper size
+ */
+ private Rectangle getSize(PrintSettings settings) {
+ PaperSize size = settings.getPaperSize();
+ PaperOrientation orientation = settings.getPaperOrientation();
+ return orientation.orient(size.getSize());
+ }
+
}
--- /dev/null
+package net.sf.openrocket.gui.print;
+
+import net.sf.openrocket.rocketcomponent.CenteringRing;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.geom.Ellipse2D;
+
+/**
+ * This class creates a renderable centering ring. It depends only on AWT/Swing and can be called from other
+ * actors (like iText handlers) to render the centering ring on different graphics contexts.
+ */
+public class PrintableCenteringRing extends AbstractPrintable<CenteringRing> {
+ /**
+ * If the component to be drawn is a centering ring, save a reference to it.
+ */
+ private CenteringRing target;
+
+ /**
+ * The X margin.
+ */
+ protected int marginX = (int) PrintUnit.INCHES.toPoints(0.25f);
+
+ /**
+ * The Y margin.
+ */
+ protected int marginY = (int) PrintUnit.INCHES.toPoints(0.25f);
+
+ /**
+ * The line length of the cross hairs.
+ */
+ private final int lineLength = 10;
+
+ /**
+ * Construct a printable nose cone.
+ *
+ * @param theRing the component to print
+ */
+ public PrintableCenteringRing(CenteringRing theRing) {
+ super(false, theRing);
+ }
+
+ /**
+ * @param component the centering ring component
+ */
+ @Override
+ protected void init(final CenteringRing component) {
+
+ target = component;
+
+ double radius = target.getOuterRadius();
+ setSize((int) PrintUnit.METERS.toPoints(2 * radius) + marginX,
+ (int) PrintUnit.METERS.toPoints(2 * radius) + marginY);
+ }
+
+ /**
+ * Draw a centering ring.
+ *
+ * @param g2 the graphics context
+ */
+ @Override
+ protected void draw(Graphics2D g2) {
+ double radius = PrintUnit.METERS.toPoints(target.getOuterRadius());
+
+ Color original = g2.getBackground();
+ double x = marginX;
+ double y = marginY;
+ Shape outerCircle = new Ellipse2D.Double(x, y, radius * 2, radius * 2);
+ g2.setColor(Color.lightGray);
+ g2.fill(outerCircle);
+ g2.setColor(Color.black);
+ g2.draw(outerCircle);
+ x += radius;
+ y += radius;
+
+ double innerRadius = PrintUnit.METERS.toPoints(target.getInnerRadius());
+ Shape innerCircle = new Ellipse2D.Double(x - innerRadius, y - innerRadius, innerRadius * 2, innerRadius * 2);
+ g2.setColor(original);
+ g2.fill(innerCircle);
+ g2.setColor(Color.black);
+ g2.draw(innerCircle);
+
+ drawCross(g2, (int) x, (int) y, lineLength, lineLength);
+ }
+
+ /**
+ * Draw the center cross-hair.
+ *
+ * @param g the graphics context
+ * @param x the x coordinate of the center point
+ * @param y the y coordinate of the center point
+ * @param width the width in pixels of the horizontal hair
+ * @param height the width in pixels of the vertical hair
+ */
+ private void drawCross(Graphics g, int x, int y, int width, int height) {
+ g.setColor(Color.black);
+ ((Graphics2D) g).setStroke(thinStroke);
+ g.drawLine(x - width / 2, y, x + width / 2, y);
+ g.drawLine(x, y - height / 2, x, y + height / 2);
+ }
+
+}
package net.sf.openrocket.gui.print;
-import java.awt.Graphics;
+import net.sf.openrocket.gui.rocketfigure.TransitionShapes;
+import net.sf.openrocket.rocketcomponent.NoseCone;
+import net.sf.openrocket.util.Transformation;
+
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
-import java.awt.print.PageFormat;
-import java.awt.print.Printable;
-import java.awt.print.PrinterException;
-import net.sf.openrocket.gui.rocketfigure.TransitionShapes;
-import net.sf.openrocket.rocketcomponent.NoseCone;
-import net.sf.openrocket.rocketcomponent.Transition;
-import net.sf.openrocket.util.Transformation;
+public class PrintableNoseCone extends AbstractPrintable<NoseCone> {
-public class PrintableNoseCone extends AbstractPrintableTransition {
-
/**
* If the component to be drawn is a nose cone, save a reference to it.
*/
private NoseCone target;
-
+
/**
* Construct a printable nose cone.
*
* @param noseCone the component to print
*/
- public PrintableNoseCone(Transition noseCone) {
+ public PrintableNoseCone(NoseCone noseCone) {
super(false, noseCone);
}
-
+
@Override
- protected void init(Transition component) {
-
- target = (NoseCone) component;
+ protected void init(NoseCone component) {
+
+ target = component;
double radius = target.getForeRadius();
if (radius < target.getAftRadius()) {
radius = target.getAftRadius();
setSize((int) PrintUnit.METERS.toPoints(2 * radius) + marginX,
(int) PrintUnit.METERS.toPoints(target.getLength() + target.getAftShoulderLength()) + marginY);
}
-
+
/**
* Draw a nose cone.
*
@Override
protected void draw(Graphics2D g2) {
Shape[] shapes = TransitionShapes.getShapesSide(target, Transformation.rotate_x(0d), PrintUnit.METERS.toPoints(1));
-
+
if (shapes != null && shapes.length > 0) {
Rectangle r = shapes[0].getBounds();
g2.translate(marginX + r.getHeight() / 2 + getOffsetX(), marginY + getOffsetY());
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);
}
-
+
@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 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;
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);
}
-
+
}
--- /dev/null
+package net.sf.openrocket.gui.print.visitor;
+
+import com.itextpdf.text.Document;
+import com.itextpdf.text.DocumentException;
+import com.itextpdf.text.Rectangle;
+import com.itextpdf.text.pdf.PdfWriter;
+import net.sf.openrocket.gui.print.AbstractPrintable;
+import net.sf.openrocket.gui.print.ITextHelper;
+import net.sf.openrocket.gui.print.PrintableCenteringRing;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.rocketcomponent.CenteringRing;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.startup.Application;
+
+import java.awt.image.BufferedImage;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A strategy for printing a centering ring to iText.
+ */
+public class CenteringRingStrategy {
+
+ /**
+ * The logger.
+ */
+ private static final LogHelper log = Application.getLogger();
+
+ /**
+ * The iText document.
+ */
+ protected Document document;
+
+ /**
+ * The direct iText writer.
+ */
+ protected PdfWriter writer;
+
+ /**
+ * The stages selected.
+ */
+ protected Set<Integer> stages;
+
+ /**
+ * Strategy for fitting multiple components onto a page.
+ */
+ protected PageFitPrintStrategy pageFitPrint;
+
+ /**
+ * Constructor.
+ *
+ * @param doc The iText document
+ * @param theWriter The direct iText writer
+ * @param theStagesToVisit The stages to be visited by this strategy
+ */
+ public CenteringRingStrategy(Document doc, PdfWriter theWriter, Set<Integer> theStagesToVisit, PageFitPrintStrategy pageFit) {
+ document = doc;
+ writer = theWriter;
+ stages = theStagesToVisit;
+ pageFitPrint = pageFit;
+ }
+
+ /**
+ * Recurse through the given rocket component.
+ *
+ * @param root the root component; all children will be visited recursively
+ */
+ public void writeToDocument(final RocketComponent root) {
+ List<RocketComponent> rc = root.getChildren();
+ goDeep(rc);
+ }
+
+
+ /**
+ * Recurse through the given rocket component.
+ *
+ * @param theRc an array of rocket components; all children will be visited recursively
+ */
+ protected void goDeep(final List<RocketComponent> theRc) {
+ for (RocketComponent rocketComponent : theRc) {
+ if (rocketComponent instanceof CenteringRing) {
+ render((CenteringRing) rocketComponent);
+ }
+ else if (rocketComponent.getChildCount() > 0) {
+ goDeep(rocketComponent.getChildren());
+ }
+ }
+ }
+
+ /**
+ * The core behavior of this visitor.
+ *
+ * @param component the object to extract info about; a graphical image of the centering ring shape is drawn to the
+ * document
+ */
+ private void render(final CenteringRing component) {
+ try {
+ AbstractPrintable pfs;
+ pfs = new PrintableCenteringRing(component);
+
+ java.awt.Dimension size = pfs.getSize();
+ final Dimension pageSize = getPageSize();
+ if (fitsOnOnePage(pageSize, size.getWidth(), size.getHeight())) {
+ pageFitPrint.addComponent(pfs);
+ }
+ else {
+ BufferedImage image = (BufferedImage) pfs.createImage();
+ ITextHelper.renderImageAcrossPages(new Rectangle(pageSize.getWidth(), pageSize.getHeight()),
+ document, writer, image);
+ }
+ }
+ catch (DocumentException e) {
+ log.error("Could not render the centering ring.", e);
+ }
+ }
+
+ /**
+ * Determine if the image will fit on the given page.
+ *
+ * @param pageSize the page size
+ * @param wImage the width of the thing to be printed
+ * @param hImage the height of the thing to be printed
+ *
+ * @return true if the thing to be printed will fit on a single page
+ */
+ private boolean fitsOnOnePage(Dimension pageSize, double wImage, double hImage) {
+ double wPage = pageSize.getWidth();
+ double hPage = pageSize.getHeight();
+
+ int wRatio = (int) Math.ceil(wImage / wPage);
+ int hRatio = (int) Math.ceil(hImage / hPage);
+
+ return wRatio <= 1.0d && hRatio <= 1.0d;
+ }
+
+ /**
+ * Get the dimensions of the paper page.
+ *
+ * @return an internal Dimension
+ */
+ protected Dimension getPageSize() {
+ return new Dimension(document.getPageSize().getWidth(),
+ document.getPageSize().getHeight());
+ }
+
+ /**
+ * Convenience class to model a dimension.
+ */
+ class Dimension {
+ /**
+ * Width, in points.
+ */
+ public float width;
+ /**
+ * Height, in points.
+ */
+ public float height;
+
+ /**
+ * Constructor.
+ *
+ * @param w width
+ * @param h height
+ */
+ public Dimension(float w, float h) {
+ width = w;
+ height = h;
+ }
+
+ /**
+ * Get the width.
+ *
+ * @return the width
+ */
+ public float getWidth() {
+ return width;
+ }
+
+ /**
+ * Get the height.
+ *
+ * @return the height
+ */
+ public float getHeight() {
+ return height;
+ }
+ }
+}
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
-import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;
-import net.sf.openrocket.gui.print.AbstractPrintableTransition;
+import net.sf.openrocket.gui.print.AbstractPrintable;
import net.sf.openrocket.gui.print.ITextHelper;
import net.sf.openrocket.gui.print.PrintableNoseCone;
import net.sf.openrocket.gui.print.PrintableTransition;
import net.sf.openrocket.rocketcomponent.Transition;
import net.sf.openrocket.startup.Application;
-import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.Set;
*/
private void render(final Transition component) {
try {
- AbstractPrintableTransition pfs;
+ AbstractPrintable pfs;
if (component instanceof NoseCone) {
- pfs = new PrintableNoseCone(component);
+ pfs = new PrintableNoseCone((NoseCone)component);
} else {
pfs = new PrintableTransition(component);
}
return wRatio <= 1.0d && hRatio <= 1.0d;
}
- /**
- * Print the transition.
- *
- * @param theTransition the printable transition
- */
- /*private void printOnOnePage(final AbstractPrintableTransition theTransition) {
- Dimension d = getPageSize();
- PdfContentByte cb = writer.getDirectContent();
- Graphics2D g2 = cb.createGraphics(d.width, d.height);
- theTransition.print(g2);
- g2.dispose();
- document.newPage();
- }*/
-
/**
* Get the dimensions of the paper page.
*