From: rodinia814 Date: Tue, 14 Sep 2010 04:07:28 +0000 (+0000) Subject: DGP - fixes to allow printing a fin template across multiple pages X-Git-Tag: upstream/1.1.4^2~10^2~2 X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=a79421c9d8e0f8aabf9cc301395f8e392e7a9a0d;p=debian%2Fopenrocket DGP - fixes to allow printing a fin template across multiple pages git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/branches/printing@84 180e2498-e6e9-4542-8430-84ac67f01cd8 --- diff --git a/src/net/sf/openrocket/gui/print/DesignReport.java b/src/net/sf/openrocket/gui/print/DesignReport.java index 3f36e12e..36f9c200 100644 --- a/src/net/sf/openrocket/gui/print/DesignReport.java +++ b/src/net/sf/openrocket/gui/print/DesignReport.java @@ -250,25 +250,27 @@ public class DesignReport extends BaseVisitorStrategy { /** * Add the motor data for a motor configuration to the table. * - * @param motors a motor configuration's list of motors - * @param parent the parent to which the motor data will be added + * @param motors a motor configuration's list of motors + * @param parent the parent to which the motor data will be added + * @param stageWeights the stageWeights of each stage, in order */ - private void addMotorData (List motors, final PdfPTable parent, List weight) { + private void addMotorData (List motors, final PdfPTable parent, List stageWeights) { - PdfPTable motorTable = new PdfPTable(7); + PdfPTable motorTable = new PdfPTable(8); motorTable.setWidthPercentage(68); motorTable.setHorizontalAlignment(Element.ALIGN_LEFT); final PdfPCell motorCell = ITextHelper.createCell("Motor", PdfPCell.BOTTOM); - final int mPad = 12; + final int mPad = 10; motorCell.setPaddingLeft(mPad); motorTable.addCell(motorCell); motorTable.addCell(ITextHelper.createCell("Avg Thrust", PdfPCell.BOTTOM)); motorTable.addCell(ITextHelper.createCell("Burn Time", PdfPCell.BOTTOM)); motorTable.addCell(ITextHelper.createCell("Max Thrust", PdfPCell.BOTTOM)); motorTable.addCell(ITextHelper.createCell("Total Impulse", PdfPCell.BOTTOM)); - motorTable.addCell(ITextHelper.createCell("Thrust to Weight", PdfPCell.BOTTOM)); - motorTable.addCell(ITextHelper.createCell("Dimensions", PdfPCell.BOTTOM)); + motorTable.addCell(ITextHelper.createCell("Thrust to Wt", PdfPCell.BOTTOM)); + motorTable.addCell(ITextHelper.createCell("Propellant Wt", PdfPCell.BOTTOM)); + motorTable.addCell(ITextHelper.createCell("Size", PdfPCell.BOTTOM)); DecimalFormat df = new DecimalFormat("#,##0.0#"); for (int i = 0; i < motors.size(); i++) { @@ -277,6 +279,8 @@ public class DesignReport extends BaseVisitorStrategy { border = Rectangle.NO_BORDER; } Motor motor = motors.get(i); + double motorWeight = (motor.getLaunchCG().weight - motor.getEmptyCG().weight) * 1000; //convert to grams + final PdfPCell motorVCell = ITextHelper.createCell(motor.getDesignation(), border); motorVCell.setPaddingLeft(mPad); motorTable.addCell(motorVCell); @@ -292,9 +296,13 @@ public class DesignReport extends BaseVisitorStrategy { motorTable.addCell(ITextHelper.createCell(df.format(motor.getTotalImpulseEstimate()) + " " + UnitGroup .UNITS_IMPULSE .getDefaultUnit().toString(), border)); - double ttw = motor.getAverageThrustEstimate() / getStageWeight(weight, i); + double ttw = motor.getAverageThrustEstimate() / (getStageWeight(stageWeights, i) + (motor + .getLaunchCG().weight * 9.80665)); motorTable.addCell(ITextHelper.createCell(df.format(ttw) + ":1", border)); + motorTable.addCell(ITextHelper.createCell(df.format(motorWeight) + " " + UnitGroup.UNITS_MASS + .getDefaultUnit().toString(), border)); + final Unit motorUnit = UnitGroup.UNITS_MOTOR_DIMENSIONS .getDefaultUnit(); motorTable.addCell(ITextHelper.createCell(motorUnit.toString(motor.getDiameter()) + @@ -429,7 +437,6 @@ public class DesignReport extends BaseVisitorStrategy { rocket.accept(new ComponentVisitor(svs)); svs.close(); List stages = svs.getStages(); - //TODO: Add in motor mass for (int i = 0; i < stages.size(); i++) { Double stage = stages.get(i); stages.set(i, stage * 9.80665); diff --git a/src/net/sf/openrocket/gui/print/ITextHelper.java b/src/net/sf/openrocket/gui/print/ITextHelper.java index 890c76e7..47276e6a 100644 --- a/src/net/sf/openrocket/gui/print/ITextHelper.java +++ b/src/net/sf/openrocket/gui/print/ITextHelper.java @@ -4,22 +4,41 @@ package net.sf.openrocket.gui.print; import com.itextpdf.text.Chunk; +import com.itextpdf.text.Document; +import com.itextpdf.text.DocumentException; import com.itextpdf.text.Font; import com.itextpdf.text.Paragraph; import com.itextpdf.text.Phrase; import com.itextpdf.text.Rectangle; +import com.itextpdf.text.pdf.PdfContentByte; import com.itextpdf.text.pdf.PdfPCell; import com.itextpdf.text.pdf.PdfPTable; +import com.itextpdf.text.pdf.PdfWriter; + +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; /** * A bunch of helper methods for creating iText components. */ public final class ITextHelper { + /** + * Create a cell for an iText table. + * + * @return a cell with bottom border + */ public static PdfPCell createCell () { return createCell(Rectangle.BOTTOM); } + /** + * Create a cell for an iText table with the given border location. + * + * @param border the border location + * + * @return a cell with given border + */ public static PdfPCell createCell (int border) { PdfPCell result = new PdfPCell(); result.setBorder(border); @@ -27,6 +46,13 @@ public final class ITextHelper { return result; } + /** + * Create a cell whose contents are a table. No border. + * + * @param table the table to insert into the cell + * + * @return the cell containing a table + */ public static PdfPCell createCell (PdfPTable table) { PdfPCell result = new PdfPCell(); result.setBorder(PdfPCell.NO_BORDER); @@ -35,33 +61,86 @@ public final class ITextHelper { return result; } + /** + * Create a cell whose contents are the given string. No border. Standard PrintUtilities.NORMAL font. + * + * @param v the text of the cell. + * + * @return the cell containing the text + */ public static PdfPCell createCell (String v) { - return createCell(v, Rectangle.NO_BORDER); + return createCell(v, Rectangle.NO_BORDER, PrintUtilities.NORMAL); } - + + /** + * Create a cell whose contents are the given string , rendered with the given font. No border. + * + * @param v the text of the cell + * @param font the font + * + * @return the cell containing the text + */ public static PdfPCell createCell (String v, Font font) { - return createCell(v, font); + return createCell(v, Rectangle.NO_BORDER, font); } + /** + * Create a cell whose contents are the given string with specified left and right padding (spacing). + * + * @param v the text of the cell + * @param leftPad the number of points to precede the text + * @param rightPad the number of points to follow the text + * + * @return the cell containing the text + */ public static PdfPCell createCell (String v, int leftPad, int rightPad) { - PdfPCell c = createCell(v, Rectangle.NO_BORDER); + PdfPCell c = createCell(v, Rectangle.NO_BORDER, PrintUtilities.NORMAL); c.setPaddingLeft(leftPad); c.setPaddingRight(rightPad); return c; } + /** + * Create a cell whose contents are the given string with the given border. Uses NORMAL font. + * + * @param v the text of the cell + * @param border the border type + * + * @return the cell containing the text + */ public static PdfPCell createCell (String v, int border) { + return createCell(v, border, PrintUtilities.NORMAL); + } + + /** + * Complete create cell - fully qualified. Create a cell whose contents are the given string with the given border + * and font. + * + * @param v the text of the cell + * @param border the border type + * @param font the font + * + * @return the cell containing the text + */ + public static PdfPCell createCell (String v, int border, Font font) { PdfPCell result = new PdfPCell(); result.setBorder(border); Chunk c = new Chunk(); - c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE)); + c.setFont(font); c.append(v); result.addElement(c); return result; } + /** + * Create a phrase with the given text and font. + * + * @param text the text + * @param font the font + * + * @return an iText phrase + */ public static Phrase createPhrase (String text, Font font) { - Phrase p = new Phrase(); final Chunk chunk = new Chunk(text); chunk.setFont(font); @@ -69,12 +148,26 @@ public final class ITextHelper { return p; } + /** + * Create a phrase with the given text. + * + * @param text the text + * + * @return an iText phrase + */ public static Phrase createPhrase (String text) { return createPhrase(text, PrintUtilities.NORMAL); } + /** + * Create a paragraph with the given text and font. + * + * @param text the text + * @param font the font + * + * @return an iText paragraph + */ public static Paragraph createParagraph (String text, Font font) { - Paragraph p = new Paragraph(); final Chunk chunk = new Chunk(text); chunk.setFont(font); @@ -82,7 +175,69 @@ public final class ITextHelper { return p; } + /** + * Create a paragraph with the given text and using NORMAL font. + * + * @param text the text + * + * @return an iText paragraph + */ public static Paragraph createParagraph (String text) { return createParagraph(text, PrintUtilities.NORMAL); } + + /** + * Break a large image up into page-size pieces and output each page in order to an iText document. The image is + * overlayed with an matrix of pages running from left to right until the right side of the image is reached. Then + * the next 'row' of pages is output from left to right, and so on. + * + * @param pageSize a rectangle that defines the bounds of the page size + * @param doc the iText document + * @param writer the underlying content writer + * @param image the source image + * + * @throws DocumentException thrown if the document could not be written + */ + public static void renderImageAcrossPages (Rectangle pageSize, Document doc, PdfWriter writer, java.awt.Image image) + throws DocumentException { + // 4/10 of an inch margin + final int margin = (int) (PrintUnit.POINTS_PER_INCH * 0.4f); + float wPage = pageSize.getWidth() - 2 * margin; + float hPage = pageSize.getHeight() - 2 * margin; + + float wImage = image.getWidth(null); + float hImage = image.getHeight(null); + + java.awt.Rectangle crop = new java.awt.Rectangle(0, 0, (int) Math.min(wPage, wImage), (int) Math.min(hPage, + hImage)); + PdfContentByte content = writer.getDirectContent(); + + double adjust; + while (true) { + BufferedImage subImage = ((BufferedImage) image).getSubimage((int) crop.getX(), (int) crop.getY(), + (int) crop.getWidth(), (int) crop.getHeight()); + + Graphics2D g2 = content.createGraphics(wPage, hPage); + g2.drawImage(subImage, margin - 1, margin - 1, null); + g2.dispose(); + doc.newPage(); + final int newX = (int) (crop.getWidth() + crop.getX()); + if (newX < wImage) { + adjust = Math.min(wImage - newX, wPage); + crop = new java.awt.Rectangle(newX, (int) crop.getY(), (int) adjust, + (int) crop.getHeight()); + } + else { + final int newY = (int) (crop.getHeight() + crop.getY()); + if (newY < hImage) { + adjust = Math.min(hImage - newY, hPage); + crop = new java.awt.Rectangle(0, newY, (int) Math.min(wPage, wImage), (int) adjust); + } + else { + break; + } + } + } + } + } \ No newline at end of file diff --git a/src/net/sf/openrocket/gui/print/PrintableFinSet.java b/src/net/sf/openrocket/gui/print/PrintableFinSet.java index 6f82423c..56992fdc 100644 --- a/src/net/sf/openrocket/gui/print/PrintableFinSet.java +++ b/src/net/sf/openrocket/gui/print/PrintableFinSet.java @@ -24,11 +24,6 @@ import java.awt.print.PrinterException; */ public class PrintableFinSet extends JPanel implements Printable { - /** - * The actual fin set being printed. - */ - private FinSet finset; - /** * The object that represents the shape (outline) of the fin. This gets drawn onto the Swing component. */ @@ -37,29 +32,38 @@ public class PrintableFinSet extends JPanel implements Printable { /** * The margin. */ - private final int margin = 20; - + private final int margin = 10; + /** * Constructor. * * @param fs the finset to print */ public PrintableFinSet (FinSet fs) { + this(fs.getFinPointsWithTab()); + } + + /** + * Construct a fin set from a set of points. + * + * @param points an array of points. + */ + public PrintableFinSet (Coordinate[] points) { super(false); - finset = fs; - init(); + init(points); setBackground(Color.white); } /** * Initialize the fin set polygon and set the size of the component. + * + * @param points an array of points. */ - private void init () { - Coordinate[] points = finset.getFinPointsWithTab(); + private void init (Coordinate[] points) { polygon = new GeneralPath(GeneralPath.WIND_EVEN_ODD, points.length); polygon.moveTo(0, 0); - + int minX = 0; int minY = 0; int maxX = 0; @@ -75,13 +79,13 @@ public class PrintableFinSet extends JPanel implements Printable { polygon.lineTo(x, y); } polygon.closePath(); - - setSize(maxX-minX+ margin, maxY-minY+ margin); + + setSize(maxX - minX + margin, maxY - minY + margin); } /** * From the java.awt.print.Printable interface. - * + *

* Prints the page at the specified index into the specified {@link java.awt.Graphics} context in the specified * format. A PrinterJob calls the Printable interface to request that a page be rendered * into the context specified by graphics. The format of the page to be drawn is specified by @@ -90,6 +94,8 @@ public class PrintableFinSet extends JPanel implements Printable { * Graphics class or subclass implements the {@link java.awt.print.PrinterGraphics} interface to * provide additional information. If the Printable object aborts the print job then it throws a * {@link java.awt.print.PrinterException}. + *

+ * Note: This is not currently used in OpenRocket. It's only here for reference. * * @param graphics the context into which the page is drawn * @param pageFormat the size and orientation of the page being drawn @@ -114,15 +120,14 @@ public class PrintableFinSet extends JPanel implements Printable { } /** - * - * Returns a generated image of the fin set. May then be used wherever AWT images can be used, or - * converted to another image/picture format and used accordingly. - * + * Returns a generated image of the fin set. 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(); - int height = getHeight(); + int width = getWidth() + margin; + int height = getHeight() + margin; // 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 @@ -148,7 +153,7 @@ public class PrintableFinSet extends JPanel implements Printable { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; - g2d.translate(margin +5, margin +15); + g2d.translate(margin, margin); g2d.setPaint(TemplateProperties.getFillColor()); g2d.fill(polygon); g2d.setPaint(TemplateProperties.getLineColor()); diff --git a/src/net/sf/openrocket/gui/print/visitor/FinSetVisitorStrategy.java b/src/net/sf/openrocket/gui/print/visitor/FinSetVisitorStrategy.java index 8711039a..112ddb86 100644 --- a/src/net/sf/openrocket/gui/print/visitor/FinSetVisitorStrategy.java +++ b/src/net/sf/openrocket/gui/print/visitor/FinSetVisitorStrategy.java @@ -4,8 +4,11 @@ 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.PdfContentByte; import com.itextpdf.text.pdf.PdfWriter; +import net.sf.openrocket.gui.print.ITextHelper; import net.sf.openrocket.gui.print.PrintableFinSet; import net.sf.openrocket.rocketcomponent.EllipticalFinSet; import net.sf.openrocket.rocketcomponent.FinSet; @@ -13,6 +16,7 @@ import net.sf.openrocket.rocketcomponent.FreeformFinSet; import net.sf.openrocket.rocketcomponent.TrapezoidFinSet; import java.awt.Graphics2D; +import java.awt.image.BufferedImage; import java.util.Set; /** @@ -22,7 +26,7 @@ public class FinSetVisitorStrategy extends BaseVisitorStrategy { /** * Constructor. - * + * * @param doc The iText document * @param theWriter The direct iText writer * @param theStagesToVisit The stages to be visited by this strategy @@ -30,7 +34,7 @@ public class FinSetVisitorStrategy extends BaseVisitorStrategy { public FinSetVisitorStrategy (Document doc, PdfWriter theWriter, Set theStagesToVisit) { super(doc, theWriter, theStagesToVisit); } - + /** * {@inheritDoc} */ @@ -57,20 +61,62 @@ public class FinSetVisitorStrategy extends BaseVisitorStrategy { /** * The core behavior of this visitor. - * - * @param visitable the object to extract info about; a graphical image of the fin shape is drawn to the document + * + * @param visitable the object to extract info about; a graphical image of the fin shape is drawn to the document */ private void doVisit (final FinSet visitable) { if (shouldVisitStage(visitable.getStageNumber())) { - PrintableFinSet pfs = new PrintableFinSet(visitable); + try { + PrintableFinSet pfs = new PrintableFinSet(visitable); - net.sf.openrocket.gui.print.visitor.Dimension d = getPageSize(); - PdfContentByte cb = writer.getDirectContent(); - Graphics2D g2 = cb.createGraphics(d.width, d.height); - pfs.print(g2); - g2.dispose(); - document.newPage(); + java.awt.Dimension finSize = pfs.getSize(); + final Dimension pageSize = getPageSize(); + if (fitsOnOnePage(pageSize, finSize.getWidth(), finSize.getHeight())) { + printOnOnePage(pfs); + } + else { + BufferedImage image = (BufferedImage) pfs.createImage(); + ITextHelper.renderImageAcrossPages(new Rectangle(pageSize.getWidth(), pageSize.getHeight()), + document, writer, image); + } + } + catch (DocumentException e) { + e.printStackTrace(); + } } } + + /** + * 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; + } + + /** + * Print the fin set. + * + * @param thePfs the printable fin set + */ + private void printOnOnePage (final PrintableFinSet thePfs) { + Dimension d = getPageSize(); + PdfContentByte cb = writer.getDirectContent(); + Graphics2D g2 = cb.createGraphics(d.width, d.height); + thePfs.print(g2); + g2.dispose(); + document.newPage(); + } }