/**
* 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<Motor> motors, final PdfPTable parent, List<Double> weight) {
+ private void addMotorData (List<Motor> motors, final PdfPTable parent, List<Double> 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++) {
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);
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()) +
rocket.accept(new ComponentVisitor(svs));
svs.close();
List<Double> 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);
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);
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);
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);
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);
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
*/
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.
*/
/**
* 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;
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.
- *
+ * <p/>
* Prints the page at the specified index into the specified {@link java.awt.Graphics} context in the specified
* format. A <code>PrinterJob</code> calls the <code>Printable</code> interface to request that a page be rendered
* into the context specified by <code>graphics</code>. The format of the page to be drawn is specified by
* <code>Graphics</code> class or subclass implements the {@link java.awt.print.PrinterGraphics} interface to
* provide additional information. If the <code>Printable</code> object aborts the print job then it throws a
* {@link java.awt.print.PrinterException}.
+ * <p/>
+ * 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
}
/**
- *
- * 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
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());
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;
import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
import java.util.Set;
/**
/**
* Constructor.
- *
+ *
* @param doc The iText document
* @param theWriter The direct iText writer
* @param theStagesToVisit The stages to be visited by this strategy
public FinSetVisitorStrategy (Document doc, PdfWriter theWriter, Set<Integer> theStagesToVisit) {
super(doc, theWriter, theStagesToVisit);
}
-
+
/**
* {@inheritDoc}
*/
/**
* 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();
+ }
}