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