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