create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / gui / print / visitor / FinSetPrintStrategy.java
1 /*
2  * FinSetPrintStrategy.java
3  */
4 package net.sf.openrocket.gui.print.visitor;
5
6 import com.itextpdf.text.Document;
7 import com.itextpdf.text.DocumentException;
8 import com.itextpdf.text.Rectangle;
9 import com.itextpdf.text.pdf.PdfWriter;
10 import net.sf.openrocket.gui.print.ITextHelper;
11 import net.sf.openrocket.gui.print.PrintUnit;
12 import net.sf.openrocket.gui.print.PrintableFinSet;
13 import net.sf.openrocket.logging.LogHelper;
14 import net.sf.openrocket.rocketcomponent.FinSet;
15 import net.sf.openrocket.rocketcomponent.RocketComponent;
16 import net.sf.openrocket.startup.Application;
17
18 import java.awt.image.BufferedImage;
19 import java.util.List;
20 import java.util.Set;
21
22 /**
23  * A strategy for drawing fin templates.
24  */
25 public class FinSetPrintStrategy {
26
27     /**
28      * The logger.
29      */
30     private static final LogHelper log = Application.getLogger();
31
32     /**
33      * The iText document.
34      */
35     protected Document document;
36
37     /**
38      * The direct iText writer.
39      */
40     protected PdfWriter writer;
41
42     /**
43      * The stages selected.
44      */
45     protected Set<Integer> stages;
46
47     /**
48      * Strategy for fitting multiple components onto a page.
49      */
50         protected PageFitPrintStrategy pageFitPrint;
51
52     /**
53      * Constructor.
54      *
55      * @param doc              The iText document
56      * @param theWriter        The direct iText writer
57      * @param theStages        The stages to be printed by this strategy
58      */
59     public FinSetPrintStrategy(Document doc, PdfWriter theWriter, Set<Integer> theStages, PageFitPrintStrategy pageFit) {
60         document = doc;
61         writer = theWriter;
62         stages = theStages;
63         pageFitPrint = pageFit;
64     }
65
66     /**
67      * Recurse through the given rocket component.
68      *
69      * @param root the root component; all children will be printed recursively
70      */
71     public void writeToDocument (final RocketComponent root) {
72         List<RocketComponent> rc = root.getChildren();
73         goDeep(rc);
74     }
75
76
77     /**
78      * Recurse through the given rocket component.
79      *
80      * @param theRc an array of rocket components; all children will be printed recursively
81      */
82     protected void goDeep (final List<RocketComponent> theRc) {
83         for (RocketComponent rocketComponent : theRc) {
84             if (rocketComponent instanceof FinSet) {
85                 printFinSet((FinSet) rocketComponent);
86             }
87             else if (rocketComponent.getChildCount() > 0) {
88                 goDeep(rocketComponent.getChildren());
89             }
90         }
91     }
92
93     /**
94      * The core behavior of this strategy.
95      *
96      * @param finSet the object to extract info about; a graphical image of the fin shape is drawn to the document
97      */
98     private void printFinSet(final FinSet finSet) {
99         if (shouldPrintStage(finSet.getStageNumber())) {
100             try {
101                 PrintableFinSet pfs = new PrintableFinSet(finSet);
102
103                 java.awt.Dimension finSize = pfs.getSize();
104                 final Dimension pageSize = getPageSize();
105                 if (fitsOnOnePage(pageSize, finSize.getWidth(), finSize.getHeight())) {
106                                         pageFitPrint.addComponent(pfs);
107                 }
108                 else {
109                     int off = (int)(PrintUnit.POINTS_PER_INCH * 0.3f);
110                     pfs.setPrintOffset(off, off);
111                     BufferedImage image = (BufferedImage) pfs.createImage();
112                     ITextHelper.renderImageAcrossPages(new Rectangle(pageSize.getWidth(), pageSize.getHeight()),
113                             document, writer, image);
114                     document.newPage();
115                 }
116             }
117             catch (DocumentException e) {
118                 log.error("Could not render fin.", e);
119             }
120         }
121     }
122
123     /**
124      * Determine if the strategy's set of stage numbers (to print) contains the specified stage.
125      *
126      * @param stageNumber a stage number
127      *
128      * @return true if the strategy contains the stage number provided
129      */
130     public boolean shouldPrintStage(int stageNumber) {
131         if (stages == null || stages.isEmpty()) {
132             return false;
133         }
134
135         for (final Integer stage : stages) {
136             if (stage == stageNumber) {
137                 return true;
138             }
139         }
140
141         return false;
142     }
143
144     /**
145      * Determine if the image will fit on the given page.
146      *
147      * @param pageSize the page size
148      * @param wImage   the width of the thing to be printed
149      * @param hImage   the height of the thing to be printed
150      *
151      * @return true if the thing to be printed will fit on a single page
152      */
153     private boolean fitsOnOnePage (Dimension pageSize, double wImage, double hImage) {
154         double wPage = pageSize.getWidth();
155         double hPage = pageSize.getHeight();
156
157         int wRatio = (int) Math.ceil(wImage / wPage);
158         int hRatio = (int) Math.ceil(hImage / hPage);
159
160         return wRatio <= 1.0d && hRatio <= 1.0d;
161     }
162
163     /**
164      * Get the dimensions of the paper page.
165      *
166      * @return an internal Dimension
167      */
168     protected Dimension getPageSize () {
169         return new Dimension(document.getPageSize().getWidth(),
170                              document.getPageSize().getHeight());
171     }
172
173     /**
174      * Convenience class to model a dimension.
175      */
176     class Dimension {
177         /** Width, in points. */
178         public float width;
179         /** Height, in points. */
180         public float height;
181
182         /**
183          * Constructor.
184          * @param w width
185          * @param h height
186          */
187         public Dimension (float w, float h) {
188             width = w;
189             height = h;
190         }
191
192         /**
193          * Get the width.
194          *
195          * @return  the width
196          */
197         public float getWidth () {
198             return width;
199         }
200
201         /**
202          * Get the height.
203          *
204          * @return the height
205          */
206         public float getHeight () {
207             return height;
208         }
209     }
210 }