Printable Centering Ring templates.

This commit is contained in:
Doug Pedrick 2012-05-24 23:28:58 +00:00
parent e754dab0ca
commit c89c927e0c
9 changed files with 485 additions and 199 deletions

View File

@ -1356,6 +1356,7 @@ OpenRocketPrintable.Transitiontemplates = Transition templates
OpenRocketPrintable.Noseconetemplates = Nose Cone templates OpenRocketPrintable.Noseconetemplates = Nose Cone templates
OpenRocketPrintable.Finmarkingguide = Fin marking guide OpenRocketPrintable.Finmarkingguide = Fin marking guide
OpenRocketPrintable.DesignReport = Design Report OpenRocketPrintable.DesignReport = Design Report
OpenRocketPrintable.Centeringringtemplates = Centering Ring templates
OpenRocketDocument.Redo = Redo OpenRocketDocument.Redo = Redo
OpenRocketDocument.Undo = Undo OpenRocketDocument.Undo = Undo

View File

@ -1,16 +1,18 @@
package net.sf.openrocket.gui.print; package net.sf.openrocket.gui.print;
import net.sf.openrocket.rocketcomponent.Transition;
import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
public abstract class AbstractPrintableTransition extends PrintableComponent { public abstract class AbstractPrintable<T> extends PrintableComponent {
/** /**
* The stroke of the transition arc. * A thin stroke.
*/ */
private final static BasicStroke thinStroke = new BasicStroke(1.0f); public final static BasicStroke thinStroke = new BasicStroke(1.0f);
/**
* A thick stroke.
*/
public final static BasicStroke thickStroke = new BasicStroke(4.0f);
/** /**
* The X margin. * The X margin.
@ -21,14 +23,14 @@ public abstract class AbstractPrintableTransition extends PrintableComponent {
* The Y margin. * The Y margin.
*/ */
protected int marginY = (int) PrintUnit.INCHES.toPoints(0.25f); protected int marginY = (int) PrintUnit.INCHES.toPoints(0.25f);
/** /**
* Constructor. Initialize this printable with the component to be printed. * Constructor. Initialize this printable with the component to be printed.
* *
* @param isDoubleBuffered a boolean, true for double-buffering * @param isDoubleBuffered a boolean, true for double-buffering
* @param transition the component to be printed * @param transition the component to be printed
*/ */
public AbstractPrintableTransition(boolean isDoubleBuffered, Transition transition) { public AbstractPrintable(boolean isDoubleBuffered, T transition) {
init(transition); init(transition);
} }
@ -39,7 +41,7 @@ public abstract class AbstractPrintableTransition extends PrintableComponent {
* *
* @param component the transition component * @param component the transition component
*/ */
protected abstract void init(Transition component); protected abstract void init(T component);
/** /**
* Draw the component onto the graphics context. * Draw the component onto the graphics context.
@ -47,12 +49,12 @@ public abstract class AbstractPrintableTransition extends PrintableComponent {
* @param g2 the graphics context * @param g2 the graphics context
*/ */
protected abstract void draw(Graphics2D g2); 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 * 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. * another image/picture format and used accordingly.
* *
* @return an awt image of the fin set * @return an awt image of the transition
*/ */
public Image createImage() { public Image createImage() {
int width = getWidth() + marginX; int width = getWidth() + marginX;

View File

@ -22,29 +22,31 @@ public enum OpenRocketPrintable {
NOSE_CONE_TEMPLATE("OpenRocketPrintable.Noseconetemplates", false, 3), NOSE_CONE_TEMPLATE("OpenRocketPrintable.Noseconetemplates", false, 3),
// Transition Templates // Transition Templates
TRANSITION_TEMPLATE("OpenRocketPrintable.Transitiontemplates", false, 4), TRANSITION_TEMPLATE("OpenRocketPrintable.Transitiontemplates", false, 4),
// Centering Ring Templates
CENTERING_RING_TEMPLATE("OpenRocketPrintable.Centeringringtemplates", false, 5),
// Finset shape // Finset shape
FIN_TEMPLATE("OpenRocketPrintable.Fintemplates", true, 5), FIN_TEMPLATE("OpenRocketPrintable.Fintemplates", true, 6),
// Fin marking guide. // Fin marking guide.
FIN_MARKING_GUIDE("OpenRocketPrintable.Finmarkingguide", false, 6); FIN_MARKING_GUIDE("OpenRocketPrintable.Finmarkingguide", false, 7);
private static final Translator trans = Application.getTranslator(); private static final Translator trans = Application.getTranslator();
/** /**
* The description - will be displayed in the JTree. * The description - will be displayed in the JTree.
*/ */
private String description; private String description;
/** /**
* Flag that indicates if the enum value is different depending upon stage. * Flag that indicates if the enum value is different depending upon stage.
*/ */
private boolean stageSpecific; private boolean stageSpecific;
/** /**
* The order of the item as it appears in the printed document. * The order of the item as it appears in the printed document.
*/ */
private int order; private int order;
/** /**
* Constructor. * Constructor.
* *
@ -57,7 +59,7 @@ public enum OpenRocketPrintable {
stageSpecific = staged; stageSpecific = staged;
order = idx; order = idx;
} }
/** /**
* Get the description of this printable. * Get the description of this printable.
* *
@ -66,7 +68,7 @@ public enum OpenRocketPrintable {
public String getDescription() { public String getDescription() {
return trans.get(description); return trans.get(description);
} }
/** /**
* Answers if this enum value has different meaning depending upon the stage. * Answers if this enum value has different meaning depending upon the stage.
* *
@ -75,7 +77,7 @@ public enum OpenRocketPrintable {
public boolean isStageSpecific() { public boolean isStageSpecific() {
return stageSpecific; return stageSpecific;
} }
/** /**
* Answer the print order. This is relative to other enum values. No two enum values will have the same print * Answer the print order. This is relative to other enum values. No two enum values will have the same print
* order value. * order value.
@ -85,7 +87,7 @@ public enum OpenRocketPrintable {
public int getPrintOrder() { public int getPrintOrder() {
return order; return order;
} }
/** /**
* Look up an enum value based on the description. * Look up an enum value based on the description.
* *
@ -102,7 +104,7 @@ public enum OpenRocketPrintable {
} }
return null; return null;
} }
/** /**
* Get a list of ordered enum values that do not have stage affinity. * Get a list of ordered enum values that do not have stage affinity.
* *

View File

@ -12,9 +12,10 @@ import com.itextpdf.text.pdf.PdfBoolean;
import com.itextpdf.text.pdf.PdfName; import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfWriter; import com.itextpdf.text.pdf.PdfWriter;
import net.sf.openrocket.document.OpenRocketDocument; 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.FinMarkingGuideStrategy;
import net.sf.openrocket.gui.print.visitor.FinSetPrintStrategy; 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.PartsDetailVisitorStrategy;
import net.sf.openrocket.gui.print.visitor.TransitionStrategy; import net.sf.openrocket.gui.print.visitor.TransitionStrategy;
@ -28,108 +29,121 @@ import java.util.Set;
* file. * file.
*/ */
public class PrintController { public class PrintController {
/** /**
* Print the selected components to a PDF document. * Print the selected components to a PDF document.
* *
* @param doc the OR document * @param doc the OR document
* @param toBePrinted the user chosen items to print * @param toBePrinted the user chosen items to print
* @param outputFile the file being written to * @param outputFile the file being written to
* @param settings the print settings * @param settings the print settings
* @param rotation the angle the rocket figure is rotated * @param rotation the angle the rocket figure is rotated
*/ */
public void print(OpenRocketDocument doc, Iterator<PrintableContext> toBePrinted, OutputStream outputFile, public void print(OpenRocketDocument doc, Iterator<PrintableContext> toBePrinted, OutputStream outputFile,
PrintSettings settings, double rotation) { 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: Document idoc = new Document(getSize(settings));
final TransitionStrategy coneWriter = new TransitionStrategy(idoc, writer, stages, pageFitPrint); PdfWriter writer = null;
coneWriter.writeToDocument(doc.getRocket(), true); try {
idoc.newPage(); writer = PdfWriter.getInstance(idoc, outputFile);
break; writer.setStrictImageSequence(true);
case FIN_MARKING_GUIDE: writer.addViewerPreference(PdfName.PRINTSCALING, PdfName.NONE);
final FinMarkingGuideStrategy fmg = new FinMarkingGuideStrategy(idoc, writer); writer.addViewerPreference(PdfName.PICKTRAYBYPDFSIZE, PdfBoolean.PDFTRUE);
fmg.writeToDocument(doc.getRocket()); try {
idoc.newPage(); idoc.open();
break; 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 // Write out parts that we are going to combine onto single sheets of paper
pageFitPrint.writeToDocument(doc.getRocket()); pageFitPrint.writeToDocument(doc.getRocket());
idoc.newPage(); idoc.newPage();
//Stupid iText throws a really nasty exception if there is no data when close is called. //Stupid iText throws a really nasty exception if there is no data when close is called.
if (writer.getCurrentDocumentSize() <= 140) { if (writer.getCurrentDocumentSize() <= 140) {
writer.setPageEmpty(false); writer.setPageEmpty(false);
} }
writer.close(); writer.close();
idoc.close(); idoc.close();
} catch (DocumentException e) { }
} catch (ExceptionConverter ec) { catch (DocumentException e) {
} finally { }
if (outputFile != null) { catch (ExceptionConverter ec) {
try { }
outputFile.close(); finally {
} catch (IOException e) { 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 /**
*/ * Get the correct paper size from the print settings.
private Rectangle getSize(PrintSettings settings) { *
PaperSize size = settings.getPaperSize(); * @param settings the print settings
PaperOrientation orientation = settings.getPaperOrientation(); *
return orientation.orient(size.getSize()); * @return the paper size
} */
private Rectangle getSize(PrintSettings settings) {
PaperSize size = settings.getPaperSize();
PaperOrientation orientation = settings.getPaperOrientation();
return orientation.orient(size.getSize());
}
} }

View File

@ -0,0 +1,104 @@
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);
}
}

View File

@ -1,38 +1,33 @@
package net.sf.openrocket.gui.print; package net.sf.openrocket.gui.print;
import java.awt.Graphics;
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.gui.rocketfigure.TransitionShapes;
import net.sf.openrocket.rocketcomponent.NoseCone; import net.sf.openrocket.rocketcomponent.NoseCone;
import net.sf.openrocket.rocketcomponent.Transition;
import net.sf.openrocket.util.Transformation; import net.sf.openrocket.util.Transformation;
public class PrintableNoseCone extends AbstractPrintableTransition { import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
public class PrintableNoseCone extends AbstractPrintable<NoseCone> {
/** /**
* If the component to be drawn is a nose cone, save a reference to it. * If the component to be drawn is a nose cone, save a reference to it.
*/ */
private NoseCone target; private NoseCone target;
/** /**
* Construct a printable nose cone. * Construct a printable nose cone.
* *
* @param noseCone the component to print * @param noseCone the component to print
*/ */
public PrintableNoseCone(Transition noseCone) { public PrintableNoseCone(NoseCone noseCone) {
super(false, noseCone); super(false, noseCone);
} }
@Override @Override
protected void init(Transition component) { protected void init(NoseCone component) {
target = (NoseCone) component; target = component;
double radius = target.getForeRadius(); double radius = target.getForeRadius();
if (radius < target.getAftRadius()) { if (radius < target.getAftRadius()) {
radius = target.getAftRadius(); radius = target.getAftRadius();
@ -40,7 +35,7 @@ public class PrintableNoseCone extends AbstractPrintableTransition {
setSize((int) PrintUnit.METERS.toPoints(2 * radius) + marginX, setSize((int) PrintUnit.METERS.toPoints(2 * radius) + marginX,
(int) PrintUnit.METERS.toPoints(target.getLength() + target.getAftShoulderLength()) + marginY); (int) PrintUnit.METERS.toPoints(target.getLength() + target.getAftShoulderLength()) + marginY);
} }
/** /**
* Draw a nose cone. * Draw a nose cone.
* *
@ -49,7 +44,7 @@ public class PrintableNoseCone extends AbstractPrintableTransition {
@Override @Override
protected void draw(Graphics2D g2) { protected void draw(Graphics2D g2) {
Shape[] shapes = TransitionShapes.getShapesSide(target, Transformation.rotate_x(0d), PrintUnit.METERS.toPoints(1)); Shape[] shapes = TransitionShapes.getShapesSide(target, Transformation.rotate_x(0d), PrintUnit.METERS.toPoints(1));
if (shapes != null && shapes.length > 0) { if (shapes != null && shapes.length > 0) {
Rectangle r = shapes[0].getBounds(); Rectangle r = shapes[0].getBounds();
g2.translate(marginX + r.getHeight() / 2 + getOffsetX(), marginY + getOffsetY()); g2.translate(marginX + r.getHeight() / 2 + getOffsetX(), marginY + getOffsetY());

View File

@ -1,18 +1,14 @@
package net.sf.openrocket.gui.print; package net.sf.openrocket.gui.print;
import net.sf.openrocket.rocketcomponent.Transition;
import java.awt.BasicStroke; import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Arc2D; import java.awt.geom.Arc2D;
import java.awt.geom.GeneralPath; import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D; import java.awt.geom.Line2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.awt.geom.Point2D; 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 * This class allows for a Transition to be printable. It does so by decorating an existing transition (which will not be
@ -22,8 +18,8 @@ import net.sf.openrocket.rocketcomponent.Transition;
* Note: Currently nose cones are only supported by drawing the 2D projection of the profile. A more useful approach * 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. * 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. * Dashed array value.
*/ */
@ -35,38 +31,38 @@ public class PrintableTransition extends AbstractPrintableTransition {
BasicStroke.CAP_BUTT, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER, BasicStroke.JOIN_MITER,
10.0f, dash1, 0.0f); 10.0f, dash1, 0.0f);
/** /**
* The layout is an outer arc, an inner arc, and two lines one either endpoints that connect the arcs. * 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. * Most of the math involves transposing geometric cartesian coordinates to the Java AWT coordinate system.
*/ */
private Path2D gp; private Path2D gp;
/** /**
* The glue tab. * The glue tab.
*/ */
private Path2D glueTab1; private Path2D glueTab1;
/** /**
* The alignment marks. * The alignment marks.
*/ */
private Line2D tick1, tick2; private Line2D tick1, tick2;
/** /**
* The x coordinates for the two ticks drawn at theta degrees. * The x coordinates for the two ticks drawn at theta degrees.
*/ */
private int tick3X, tick4X; private int tick3X, tick4X;
/** /**
* The angle, in degrees. * The angle, in degrees.
*/ */
private float theta; private float theta;
/** /**
* The x,y coordinates for where the virtual circle center is located. * The x,y coordinates for where the virtual circle center is located.
*/ */
private int circleCenterX, circleCenterY; private int circleCenterX, circleCenterY;
/** /**
* Constructor. * Constructor.
* *
@ -75,13 +71,13 @@ public class PrintableTransition extends AbstractPrintableTransition {
public PrintableTransition(Transition transition) { public PrintableTransition(Transition transition) {
super(false, transition); super(false, transition);
} }
@Override @Override
protected void init(Transition component) { protected void init(Transition component) {
double r1 = component.getAftRadius(); double r1 = component.getAftRadius();
double r2 = component.getForeRadius(); double r2 = component.getForeRadius();
//Regardless of orientation, we have the convention of R1 as the smaller radius. Flip if different. //Regardless of orientation, we have the convention of R1 as the smaller radius. Flip if different.
if (r1 > r2) { if (r1 > r2) {
r1 = r2; r1 = r2;
@ -91,19 +87,19 @@ public class PrintableTransition extends AbstractPrintableTransition {
double v = r2 - r1; double v = r2 - r1;
double tmp = Math.sqrt(v * v + len * len); double tmp = Math.sqrt(v * v + len * len);
double factor = tmp / v; double factor = tmp / v;
theta = (float) (360d * v / tmp); theta = (float) (360d * v / tmp);
int r1InPoints = (int) PrintUnit.METERS.toPoints(r1 * factor); int r1InPoints = (int) PrintUnit.METERS.toPoints(r1 * factor);
int r2InPoints = (int) PrintUnit.METERS.toPoints(r2 * factor); int r2InPoints = (int) PrintUnit.METERS.toPoints(r2 * factor);
int x = marginX; int x = marginX;
int tabOffset = 35; int tabOffset = 35;
int y = tabOffset + marginY; int y = tabOffset + marginY;
Arc2D.Double outerArc = new Arc2D.Double(); Arc2D.Double outerArc = new Arc2D.Double();
Arc2D.Double innerArc = 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 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) { if (theta >= 270) {
y += r2InPoints; y += r2InPoints;
@ -114,23 +110,23 @@ public class PrintableTransition extends AbstractPrintableTransition {
double thetaRads = Math.toRadians(theta - 180); double thetaRads = Math.toRadians(theta - 180);
y += (int) ((Math.cos(thetaRads) * r2InPoints) * Math.tan(thetaRads)); y += (int) ((Math.cos(thetaRads) * r2InPoints) * Math.tan(thetaRads));
} }
circleCenterY = y; circleCenterY = y;
circleCenterX = r2InPoints + x; circleCenterX = r2InPoints + x;
//Create the larger arc. //Create the larger arc.
outerArc.setArcByCenter(circleCenterX, circleCenterY, r2InPoints, 180, theta, Arc2D.OPEN); outerArc.setArcByCenter(circleCenterX, circleCenterY, r2InPoints, 180, theta, Arc2D.OPEN);
//Create the smaller arc. //Create the smaller arc.
innerArc.setArcByCenter(circleCenterX, circleCenterY, r1InPoints, 180, theta, Arc2D.OPEN); 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. //Create the line between the start of the larger arc and the start of the smaller arc.
Path2D.Double line = new Path2D.Double(); Path2D.Double line = new Path2D.Double();
line.setWindingRule(Path2D.WIND_NON_ZERO); line.setWindingRule(Path2D.WIND_NON_ZERO);
line.moveTo(x, y); line.moveTo(x, y);
final int width = r2InPoints - r1InPoints; final int width = r2InPoints - r1InPoints;
line.lineTo(width + x, y); line.lineTo(width + x, y);
//Create the line between the endpoint of the larger arc and the endpoint of the smaller arc. //Create the line between the endpoint of the larger arc and the endpoint of the smaller arc.
Path2D.Double closingLine = new Path2D.Double(); Path2D.Double closingLine = new Path2D.Double();
closingLine.setWindingRule(Path2D.WIND_NON_ZERO); closingLine.setWindingRule(Path2D.WIND_NON_ZERO);
@ -138,21 +134,21 @@ public class PrintableTransition extends AbstractPrintableTransition {
closingLine.moveTo(innerArcEndPoint.getX(), innerArcEndPoint.getY()); closingLine.moveTo(innerArcEndPoint.getX(), innerArcEndPoint.getY());
Point2D outerArcEndPoint = outerArc.getEndPoint(); Point2D outerArcEndPoint = outerArc.getEndPoint();
closingLine.lineTo(outerArcEndPoint.getX(), outerArcEndPoint.getY()); closingLine.lineTo(outerArcEndPoint.getX(), outerArcEndPoint.getY());
//Add all shapes to the polygon path. //Add all shapes to the polygon path.
gp = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4); gp = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4);
gp.append(line, false); gp.append(line, false);
gp.append(outerArc, false); gp.append(outerArc, false);
gp.append(closingLine, false); gp.append(closingLine, false);
gp.append(innerArc, false); gp.append(innerArc, false);
//Create the glue tab. //Create the glue tab.
glueTab1 = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4); glueTab1 = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4);
glueTab1.moveTo(x, y); glueTab1.moveTo(x, y);
glueTab1.lineTo(x + tabOffset, y - tabOffset); glueTab1.lineTo(x + tabOffset, y - tabOffset);
glueTab1.lineTo(width + x - tabOffset, y - tabOffset); glueTab1.lineTo(width + x - tabOffset, y - tabOffset);
glueTab1.lineTo(width + x, y); glueTab1.lineTo(width + x, y);
//Create tick marks for alignment, 1/4 of the width in from either edge //Create tick marks for alignment, 1/4 of the width in from either edge
int fromEdge = width / 4; int fromEdge = width / 4;
final int tickLength = 8; final int tickLength = 8;
@ -160,13 +156,13 @@ public class PrintableTransition extends AbstractPrintableTransition {
tick1 = new Line2D.Float(x + fromEdge, y, x + fromEdge, y + tickLength); tick1 = new Line2D.Float(x + fromEdge, y, x + fromEdge, y + tickLength);
//Upper right //Upper right
tick2 = new Line2D.Float(x + width - fromEdge, y, x + width - fromEdge, y + tickLength); tick2 = new Line2D.Float(x + width - fromEdge, y, x + width - fromEdge, y + tickLength);
tick3X = r2InPoints - fromEdge; tick3X = r2InPoints - fromEdge;
tick4X = r1InPoints + fromEdge; tick4X = r1InPoints + fromEdge;
setSize(gp.getBounds().width, gp.getBounds().height + tabOffset); setSize(gp.getBounds().width, gp.getBounds().height + tabOffset);
} }
/** /**
* Draw alignment marks on an angle. * Draw alignment marks on an angle.
* *
@ -183,7 +179,7 @@ public class PrintableTransition extends AbstractPrintableTransition {
g2.rotate(Math.toRadians(theta)); g2.rotate(Math.toRadians(theta));
g2.translate(-x, -y); g2.translate(-x, -y);
} }
/** /**
* Draw a transition. * Draw a transition.
* *
@ -203,9 +199,9 @@ public class PrintableTransition extends AbstractPrintableTransition {
circleCenterY, circleCenterY,
new Line2D.Float(-tick4X, 0, -tick4X, -8), new Line2D.Float(-tick4X, 0, -tick4X, -8),
theta); theta);
g2.setStroke(dashed); g2.setStroke(dashed);
g2.draw(glueTab1); g2.draw(glueTab1);
} }
} }

View File

@ -0,0 +1,188 @@
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;
}
}
}

View File

@ -3,9 +3,8 @@ package net.sf.openrocket.gui.print.visitor;
import com.itextpdf.text.Document; import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException; import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle; import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter; 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.ITextHelper;
import net.sf.openrocket.gui.print.PrintableNoseCone; import net.sf.openrocket.gui.print.PrintableNoseCone;
import net.sf.openrocket.gui.print.PrintableTransition; import net.sf.openrocket.gui.print.PrintableTransition;
@ -15,7 +14,6 @@ import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.Transition; import net.sf.openrocket.rocketcomponent.Transition;
import net.sf.openrocket.startup.Application; import net.sf.openrocket.startup.Application;
import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -103,9 +101,9 @@ public class TransitionStrategy {
*/ */
private void render(final Transition component) { private void render(final Transition component) {
try { try {
AbstractPrintableTransition pfs; AbstractPrintable pfs;
if (component instanceof NoseCone) { if (component instanceof NoseCone) {
pfs = new PrintableNoseCone(component); pfs = new PrintableNoseCone((NoseCone)component);
} else { } else {
pfs = new PrintableTransition(component); pfs = new PrintableTransition(component);
} }
@ -143,20 +141,6 @@ public class TransitionStrategy {
return wRatio <= 1.0d && hRatio <= 1.0d; 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. * Get the dimensions of the paper page.
* *