Added ruler graphic to printed output; improvements to layout and margins in printing...
authorrodinia814 <rodinia814@180e2498-e6e9-4542-8430-84ac67f01cd8>
Mon, 28 May 2012 04:28:26 +0000 (04:28 +0000)
committerrodinia814 <rodinia814@180e2498-e6e9-4542-8430-84ac67f01cd8>
Mon, 28 May 2012 04:28:26 +0000 (04:28 +0000)
minor printing related cleanup.

git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@731 180e2498-e6e9-4542-8430-84ac67f01cd8

14 files changed:
core/src/net/sf/openrocket/gui/print/AbstractPrintable.java
core/src/net/sf/openrocket/gui/print/PrintController.java
core/src/net/sf/openrocket/gui/print/PrintUnit.java
core/src/net/sf/openrocket/gui/print/PrintableCenteringRing.java
core/src/net/sf/openrocket/gui/print/PrintableComponent.java
core/src/net/sf/openrocket/gui/print/PrintableFinSet.java
core/src/net/sf/openrocket/gui/print/PrintableNoseCone.java
core/src/net/sf/openrocket/gui/print/PrintableTransition.java
core/src/net/sf/openrocket/gui/print/components/Rule.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/print/visitor/CenteringRingStrategy.java
core/src/net/sf/openrocket/gui/print/visitor/FinSetPrintStrategy.java
core/src/net/sf/openrocket/gui/print/visitor/PageFitPrintStrategy.java
core/src/net/sf/openrocket/gui/print/visitor/TransitionStrategy.java
core/test/net/sf/openrocket/gui/print/PrintUnitTest.java [new file with mode: 0644]

index 739a7d9194df327045f72837f92bdc16e77597ac..585e4975b5a420f3ca5c370999be1c0bbbcbf6ec 100644 (file)
@@ -1,6 +1,11 @@
 package net.sf.openrocket.gui.print;
 
-import java.awt.*;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.RenderingHints;
 import java.awt.image.BufferedImage;
 
 public abstract class AbstractPrintable<T> extends PrintableComponent {
@@ -14,16 +19,6 @@ public abstract class AbstractPrintable<T> extends PrintableComponent {
      */
     public final static BasicStroke thickStroke = new BasicStroke(4.0f);
 
-    /**
-     * The X margin.
-     */
-    protected int marginX = (int) PrintUnit.INCHES.toPoints(0.25f);
-
-    /**
-     * The Y margin.
-     */
-    protected int marginY = (int) PrintUnit.INCHES.toPoints(0.25f);
-
     /**
      * Constructor. Initialize this printable with the component to be printed.
      *
@@ -35,11 +30,9 @@ public abstract class AbstractPrintable<T> extends PrintableComponent {
     }
 
     /**
-     * Compute the basic values of each arc of the transition/shroud.  This is adapted from
-     * <a href="http://www.rocketshoppe.com/info/Transitions.pdf">The Properties of
-     * Model Rocket Body Tube Transitions, by J.R. Brohm</a>
+     * Initialize the printable.
      *
-     * @param component the transition component
+     * @param component the component
      */
     protected abstract void init(T component);
 
@@ -51,14 +44,14 @@ public abstract class AbstractPrintable<T> extends PrintableComponent {
     protected abstract void draw(Graphics2D g2);
 
     /**
-     * Returns a generated image of the transition.  May then be used wherever AWT images can be used, or converted to
+     * Returns a generated image of the component.  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 transition
+     * @return an awt image of the printable component
      */
     public Image createImage() {
-        int width = getWidth() + marginX;
-        int height = getHeight() + marginY;
+        int width = getWidth() + getOffsetX();
+        int height = getHeight() + getOffsetY();
         // 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
index 4088de702de62fc79969f7a86195956abf75a2e9..2e62df2a2cf403da5c85b72be9c7f3106ce3a0cf 100644 (file)
@@ -12,6 +12,7 @@ import com.itextpdf.text.pdf.PdfBoolean;
 import com.itextpdf.text.pdf.PdfName;
 import com.itextpdf.text.pdf.PdfWriter;
 import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.gui.print.components.Rule;
 import net.sf.openrocket.gui.print.visitor.CenteringRingStrategy;
 import net.sf.openrocket.gui.print.visitor.FinMarkingGuideStrategy;
 import net.sf.openrocket.gui.print.visitor.FinSetPrintStrategy;
@@ -60,6 +61,8 @@ public class PrintController {
             // Used to combine multiple components onto fewer sheets of paper
             PageFitPrintStrategy pageFitPrint = new PageFitPrintStrategy(idoc, writer);
 
+            boolean addRule = false;
+
             while (toBePrinted.hasNext()) {
                 PrintableContext printableContext = toBePrinted.next();
 
@@ -71,42 +74,55 @@ public class PrintController {
                         dp.writeToDocument(writer);
                         idoc.newPage();
                         break;
+
                     case FIN_TEMPLATE:
                         final FinSetPrintStrategy finWriter = new FinSetPrintStrategy(idoc, writer, stages, pageFitPrint);
                         finWriter.writeToDocument(doc.getRocket());
+                        addRule = true;
                         break;
+
                     case PARTS_DETAIL:
                         final PartsDetailVisitorStrategy detailVisitor = new PartsDetailVisitorStrategy(idoc, writer, stages);
                         detailVisitor.writeToDocument(doc.getRocket());
                         detailVisitor.close();
                         idoc.newPage();
                         break;
+
                     case TRANSITION_TEMPLATE:
                         final TransitionStrategy tranWriter = new TransitionStrategy(idoc, writer, stages, pageFitPrint);
-                        tranWriter.writeToDocument(doc.getRocket(), false);
-                        idoc.newPage();
+                        if (tranWriter.writeToDocument(doc.getRocket(), false)) {
+                            addRule = true;
+                        }
                         break;
 
                     case NOSE_CONE_TEMPLATE:
                         final TransitionStrategy coneWriter = new TransitionStrategy(idoc, writer, stages, pageFitPrint);
-                        coneWriter.writeToDocument(doc.getRocket(), true);
-                        idoc.newPage();
+                        if (coneWriter.writeToDocument(doc.getRocket(), true)) {
+                            addRule = true;
+                        }
                         break;
 
                     case CENTERING_RING_TEMPLATE:
                         final CenteringRingStrategy crWriter = new CenteringRingStrategy(idoc, writer, stages,
                                 pageFitPrint);
                         crWriter.writeToDocument(doc.getRocket());
-                        idoc.newPage();
+                        addRule = true;
                         break;
 
                     case FIN_MARKING_GUIDE:
                         final FinMarkingGuideStrategy fmg = new FinMarkingGuideStrategy(idoc, writer);
                         fmg.writeToDocument(doc.getRocket());
                         idoc.newPage();
+                        addRule = true;
                         break;
                 }
             }
+
+            if (addRule) {
+                //Add a ruler to the output.
+                pageFitPrint.addComponent(new Rule(Rule.Orientation.BOTTOM));
+            }
+
             // Write out parts that we are going to combine onto single sheets of paper
             pageFitPrint.writeToDocument(doc.getRocket());
             idoc.newPage();
index 310fba3206abc1948e686eb124c7759b3e4ed363..734e433bd3c6e8bfd84a6edaf90e97cc4bbe335a 100644 (file)
@@ -12,7 +12,7 @@ public enum PrintUnit {
         public double toMillis(double d) { return d/FEET_PER_MM; }
         public double toCentis(double d) { return d/(FEET_PER_MM*TEN); }
         public double toMeters(double d) { return d/(FEET_PER_MM*TEN*TEN*TEN); }
-        public long   toPoints(double d) { return (long)(d * POINTS_PER_INCH * 12); }
+        public double toPoints(double d) { return (d * POINTS_PER_INCH * 12); }
         public double convert(double d, PrintUnit u) { return u.toInches(d)/12; }
     },
     INCHES {
@@ -20,7 +20,7 @@ public enum PrintUnit {
         public double toMillis(double d) { return d/INCHES_PER_MM; }
         public double toCentis(double d) { return d/(INCHES_PER_MM*TEN); }
         public double toMeters(double d) { return d/(INCHES_PER_MM*TEN*TEN*TEN); }
-        public long   toPoints(double d) { return (long)(d * POINTS_PER_INCH); }
+        public double toPoints(double d) { return (d * POINTS_PER_INCH); }
         public double convert(double d, PrintUnit u) { return u.toInches(d); }
     },
     MILLIMETERS {
@@ -28,7 +28,7 @@ public enum PrintUnit {
         public double toMillis(double d) { return d; }
         public double toCentis(double d) { return d/TEN; }
         public double toMeters(double d) { return d/(TEN*TEN*TEN); }
-        public long   toPoints(double d) { return INCHES.toPoints(toInches(d)); }
+        public double toPoints(double d) { return INCHES.toPoints(toInches(d)); }
         public double convert(double d, PrintUnit u) { return u.toMillis(d); }
     },
     CENTIMETERS {
@@ -36,7 +36,7 @@ public enum PrintUnit {
         public double toMillis(double d) { return d * TEN; }
         public double toCentis(double d) { return d; }
         public double toMeters(double d) { return d/(TEN*TEN); }
-        public long   toPoints(double d) { return INCHES.toPoints(toInches(d)); }
+        public double toPoints(double d) { return INCHES.toPoints(toInches(d)); }
         public double convert(double d, PrintUnit u) { return u.toCentis(d); }
     },
     METERS {
@@ -44,7 +44,7 @@ public enum PrintUnit {
         public double toMillis(double d) { return d * TEN * TEN * TEN; }
         public double toCentis(double d) { return d * TEN * TEN; }
         public double toMeters(double d) { return d; }
-        public long   toPoints(double d) { return INCHES.toPoints(toInches(d)); }
+        public double toPoints(double d) { return INCHES.toPoints(toInches(d)); }
         public double convert(double d, PrintUnit u) { return u.toMeters(d); }
     },
     POINTS {
@@ -52,7 +52,7 @@ public enum PrintUnit {
         public double toMillis(double d) { return d/(POINTS_PER_INCH * INCHES_PER_MM); }
         public double toCentis(double d) { return toMillis(d)/TEN; }
         public double toMeters(double d) { return toMillis(d)/(TEN*TEN*TEN); }
-        public long   toPoints(double d) { return (long)d; }
+        public double toPoints(double d) { return d; }
         public double convert(double d, PrintUnit u) { return u.toPoints(d); }
     };
 
@@ -160,7 +160,7 @@ public enum PrintUnit {
      * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
      * @see #convert
      */
-    public long toPoints(double length) {
+    public double toPoints(double length) {
         throw new AbstractMethodError();
     }
 
index 08d3f12c3058e419a7aa945f87dd7a8eb1e6d0c8..ed0a66d22be804cfd4291e120d4f598cf565568d 100644 (file)
@@ -18,16 +18,6 @@ public class PrintableCenteringRing extends AbstractPrintable<CenteringRing> {
      */
     private CenteringRing target;
 
-    /**
-     * The X margin.
-     */
-    protected int marginX = (int) PrintUnit.INCHES.toPoints(0.25f);
-
-    /**
-     * The Y margin.
-     */
-    protected int marginY = (int) PrintUnit.INCHES.toPoints(0.25f);
-
     /**
      * The line length of the cross hairs.
      */
@@ -51,8 +41,8 @@ public class PrintableCenteringRing extends AbstractPrintable<CenteringRing> {
         target = component;
 
         double radius = target.getOuterRadius();
-        setSize((int) PrintUnit.METERS.toPoints(2 * radius) + marginX,
-                (int) PrintUnit.METERS.toPoints(2 * radius) + marginY);
+        setSize((int) PrintUnit.METERS.toPoints(2 * radius),
+                (int) PrintUnit.METERS.toPoints(2 * radius));
     }
 
     /**
@@ -65,8 +55,8 @@ public class PrintableCenteringRing extends AbstractPrintable<CenteringRing> {
         double radius = PrintUnit.METERS.toPoints(target.getOuterRadius());
 
         Color original = g2.getBackground();
-        double x = marginX;
-        double y = marginY;
+        double x = 0;
+        double y = 0;
         Shape outerCircle = new Ellipse2D.Double(x, y, radius * 2, radius * 2);
         g2.setColor(Color.lightGray);
         g2.fill(outerCircle);
index 10e5c803e37f3554fe8f4dc28bb3d3ff63621b7f..de345fb9c57beafbb61c8975c347b23bdd5fe0d9 100644 (file)
@@ -3,23 +3,22 @@
  */
 package net.sf.openrocket.gui.print;
 
+import javax.swing.JPanel;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.print.PageFormat;
 import java.awt.print.Printable;
 import java.awt.print.PrinterException;
 
-import javax.swing.JPanel;
-
 /**
  * Common interface for components we want to print. Used by PageFitPrintStrategy
  *
  * @author Jason Blood <dyster2000@gmail.com>
  */
-public class PrintableComponent extends JPanel implements Printable {
+public class PrintableComponent extends JPanel implements Printable, Comparable<PrintableComponent> {
 
     /**
-     * The printing offsets
+     * The printing offsets.
      */
     private int offsetX = 0;
     private int offsetY = 0;
@@ -68,7 +67,7 @@ public class PrintableComponent extends JPanel implements Printable {
     }
 
        /**
-        * Set the offset this component will be printed to the page
+        * Set the offset this component will be printed to the page.
         * @param x     X offset to print at.
         * @param y     Y offset to print at.
         */
@@ -78,7 +77,7 @@ public class PrintableComponent extends JPanel implements Printable {
        }
 
        /**
-        * Get the X offset this component will be printed to the page
+        * Get the X offset this component will be printed to the page.
         * @return X offset to print at.
         */
        public int getOffsetX() {
@@ -86,10 +85,38 @@ public class PrintableComponent extends JPanel implements Printable {
        }
 
        /**
-        * Get the Y offset this component will be printed to the page
+        * Get the Y offset this component will be printed to the page.
         * @return Y offset to print at.
         */
        public int getOffsetY() {
                return offsetY;
        }
+
+
+    /**
+     * Compares this object with the specified object for order.  Returns a negative integer, zero, or a positive integer
+     * as this object is less than, equal to, or greater than the specified object.
+     *
+     * Bin packing theory says that trying to fit the biggest items first may have a better outcome. So this is sorted
+     * in size descending order, with width taking precedence over height.
+     *
+     * @param other the object to be compared.
+     *
+     * @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the
+     *         specified object.
+     *
+     * @throws NullPointerException if the specified object is null
+     * @throws ClassCastException   if the specified object's type prevents it from being compared to this object.
+     */
+    @Override
+    public int compareTo(final PrintableComponent other) {
+        int widthDiff = other.getWidth() - getWidth();
+        if (widthDiff > 0) {
+            return 1;
+        }
+        else if (widthDiff < 0) {
+            return -1;
+        }
+        return other.getHeight() - getHeight();
+    }
 }
index bed1fdf9ddaeb476912cd469a50b55533a39fef8..8e5389b2bd3cf7072efc339414dcf92c56db6716 100644 (file)
@@ -6,13 +6,12 @@ package net.sf.openrocket.gui.print;
 import net.sf.openrocket.rocketcomponent.FinSet;
 import net.sf.openrocket.util.Coordinate;
 
-import javax.swing.*;
-import java.awt.*;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
 import java.awt.geom.GeneralPath;
 import java.awt.image.BufferedImage;
-import java.awt.print.PageFormat;
-import java.awt.print.Printable;
-import java.awt.print.PrinterException;
 
 /**
  * This class allows for a FinSet to be printable.  It does so by decorating an existing finset (which will not be
@@ -26,14 +25,6 @@ public class PrintableFinSet extends PrintableComponent {
      */
     protected GeneralPath polygon = null;
 
-    /**
-     * The X margin.
-     */
-    private final int marginX = (int)(PrintUnit.POINTS_PER_INCH * 0.3f);
-    /**
-     * The Y margin.
-     */
-    private final int marginY = (int)(PrintUnit.POINTS_PER_INCH * 0.3f);
     /**
      * The minimum X coordinate.
      */
@@ -58,9 +49,7 @@ public class PrintableFinSet extends PrintableComponent {
      * @param points an array of points.
      */
     public PrintableFinSet (Coordinate[] points) {
-        //super(false);
         init(points);
-        //setBackground(Color.white);
     }
 
     /**
@@ -77,8 +66,8 @@ public class PrintableFinSet extends PrintableComponent {
         int maxY = 0;
 
         for (Coordinate point : points) {
-            final long x = PrintUnit.METERS.toPoints(point.x);
-            final long y = PrintUnit.METERS.toPoints(point.y);
+            final long x = (long)PrintUnit.METERS.toPoints(point.x);
+            final long y = (long)PrintUnit.METERS.toPoints(point.y);
             minX = (int) Math.min(x, minX);
             minY = (int) Math.min(y, minY);
             maxX = (int) Math.max(x, maxX);
@@ -90,24 +79,6 @@ public class PrintableFinSet extends PrintableComponent {
         setSize(maxX - minX, maxY - minY);
     }
 
-    /**
-     * Get the X-axis margin value.
-     *
-     * @return margin, in points
-     */
-    protected double getMarginX () {
-        return marginX;
-    }
-
-    /**
-     * Get the Y-axis margin value.
-     *
-     * @return margin, in points
-     */
-    protected double getMarginY () {
-        return marginY;
-    }
-
     /**
      * 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.
@@ -115,17 +86,17 @@ public class PrintableFinSet extends PrintableComponent {
      * @return an awt image of the fin set
      */
     public Image createImage () {
-        int width = getWidth() + marginX;
-        int height = getHeight() + marginY;
-        // Create a buffered image in which to draw 
+        int width = getWidth();
+        int height = getHeight();
+        // 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 
+        // Create a graphics contents on the buffered image
         Graphics2D g2d = bufferedImage.createGraphics();
-        // Draw graphics 
+        // Draw graphics
         g2d.setBackground(Color.white);
         g2d.clearRect(0, 0, width, height);
         paintComponent(g2d);
-        // Graphics context no longer needed so dispose it 
+        // Graphics context no longer needed so dispose it
         g2d.dispose();
         return bufferedImage;
     }
@@ -144,6 +115,9 @@ public class PrintableFinSet extends PrintableComponent {
         int x = 0;
         int y = 0;
 
+        int marginX = this.getOffsetX();
+        int marginY = this.getOffsetY();
+
         // The minimum X/Y can be negative (primarily only Y due to fin tabs; rarely (never) X, but protect both anyway).
         if (minX < marginX) {
             x = marginX + Math.abs(minX);
@@ -152,7 +126,7 @@ public class PrintableFinSet extends PrintableComponent {
             y = marginY + Math.abs(minY);
         }
         // Reset the origin.
-        g2d.translate(x + getOffsetX(), y + getOffsetY());
+        g2d.translate(x, y);
         g2d.setPaint(TemplateProperties.getFillColor());
         g2d.fill(polygon);
         g2d.setPaint(TemplateProperties.getLineColor());
index 17f072308e9890215dd392adca4548c872b934ae..2cfdfa688efdb0b6a0b7422106c080983bde18b2 100644 (file)
@@ -32,12 +32,13 @@ public class PrintableNoseCone extends AbstractPrintable<NoseCone> {
                if (radius < target.getAftRadius()) {
                        radius = target.getAftRadius();
                }
-               setSize((int) PrintUnit.METERS.toPoints(2 * radius) + marginX,
-                               (int) PrintUnit.METERS.toPoints(target.getLength() + target.getAftShoulderLength()) + marginY);
+               setSize((int) PrintUnit.METERS.toPoints(2 * radius) + 4,
+                               (int) PrintUnit.METERS.toPoints(target.getLength() + target.getAftShoulderLength()) + 4);
        }
 
        /**
-        * Draw a nose cone.
+        * Draw a nose cone.  Presumes that the graphics context has already had the x/y position translated based on
+     * where it should be drawn.
         *
         * @param g2 the graphics context
         */
@@ -47,7 +48,7 @@ public class PrintableNoseCone extends AbstractPrintable<NoseCone> {
 
                if (shapes != null && shapes.length > 0) {
                        Rectangle r = shapes[0].getBounds();
-                       g2.translate(marginX + r.getHeight() / 2 + getOffsetX(), marginY + getOffsetY());
+                       g2.translate(r.getHeight() / 2, 0);
                        g2.rotate(Math.PI / 2);
                        for (Shape shape : shapes) {
                                g2.draw(shape);
index 4a2d6d8135fa0e9d0dda87338c50cf2118e99623..41a9958a1ddc079de9cc5174b749e7478b4a2602 100644 (file)
@@ -72,6 +72,13 @@ public class PrintableTransition extends AbstractPrintable<Transition> {
                super(false, transition);
        }
 
+    /**
+     * Compute the basic values of each arc of the transition/shroud.  This is adapted from
+     * <a href="http://www.rocketshoppe.com/info/Transitions.pdf">The Properties of
+     * Model Rocket Body Tube Transitions, by J.R. Brohm</a>
+     *
+     * @param component the component
+     */
        @Override
        protected void init(Transition component) {
 
@@ -93,9 +100,9 @@ public class PrintableTransition extends AbstractPrintable<Transition> {
                int r1InPoints = (int) PrintUnit.METERS.toPoints(r1 * factor);
                int r2InPoints = (int) PrintUnit.METERS.toPoints(r2 * factor);
 
-               int x = marginX;
+               int x = 0;
                int tabOffset = 35;
-               int y = tabOffset + marginY;
+               int y = tabOffset;
 
                Arc2D.Double outerArc = new Arc2D.Double();
                Arc2D.Double innerArc = new Arc2D.Double();
diff --git a/core/src/net/sf/openrocket/gui/print/components/Rule.java b/core/src/net/sf/openrocket/gui/print/components/Rule.java
new file mode 100644 (file)
index 0000000..05c890f
--- /dev/null
@@ -0,0 +1,273 @@
+package net.sf.openrocket.gui.print.components;
+
+import net.sf.openrocket.gui.print.PrintUnit;
+import net.sf.openrocket.gui.print.PrintableComponent;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+
+/**
+ * This class creates a Swing ruler.  The ruler has both vertical and horizontal rules, as well as divisions for both
+ * inches and centimeters.
+ */
+public class Rule extends PrintableComponent {
+
+    public static enum Orientation {
+        TOP,
+        BOTTOM
+    }
+
+    public static final int TINIEST_TICK_LENGTH = 3;
+    public static final int MINOR_TICK_LENGTH = 6;
+    public static final int MID_MAJOR_TICK_LENGTH = 9;
+    public static final int MAJOR_TICK_LENGTH = 14;
+
+    private Orientation orientation;
+
+    /**
+     * Constructor.
+     *
+     * @param theOrientation defines if the horizontal ruler should be on the top or bottom; the vertical is always
+     *                       left justified
+     */
+    public Rule(Orientation theOrientation) {
+        orientation = theOrientation;
+        int dim = (int) PrintUnit.INCHES.toPoints(2) + 32;
+        setSize(dim, dim);
+    }
+
+    /**
+     * Render the component onto a graphics context.
+     *
+     * @param g the opaque graphics context
+     */
+    public void paintComponent(Graphics g) {
+        Graphics2D g2 = (Graphics2D) g;
+
+        double div = PrintUnit.INCHES.toPoints(1) / 8;  //1/8 inch increment
+        final int width = (int) PrintUnit.INCHES.toPoints(2);
+        int x = 20;
+        int y = x + 20;
+        boolean inchOutSide = true;
+
+        g2.translate(getOffsetX(), getOffsetY());
+
+        if (orientation == Orientation.TOP) {
+            Font f = g.getFont();
+            g.setFont(f.deriveFont(f.getSize() - 2f));
+            g.drawString("in  cm", x - MAJOR_TICK_LENGTH, y + width + 20);
+            g.drawString("in", x + width + 4, y + 4);
+            g.drawString("cm", x + width + 4, y + 18);
+            y += 6;
+
+            drawVerticalRule(g2, true, inchOutSide, x, y, width, 0, div * 2, div * 4, div * 8);
+            drawHorizontalRule(g2, true, !inchOutSide, x, y, width, 0, div * 2, div * 4, div * 8);
+            div = PrintUnit.MILLIMETERS.toPoints(1);  //mm increment
+            drawVerticalRule(g2, true, !inchOutSide, x, y, width, 0, 0, div * 5, div * 10);
+            drawHorizontalRule(g2, true, inchOutSide, x, y, width, 0, 0, div * 5, div * 10);
+        }
+        else {
+            Font f = g.getFont();
+            g.setFont(f.deriveFont(f.getSize() - 2f));
+            g.drawString("in  cm", x - MAJOR_TICK_LENGTH, y);
+            g.drawString("cm", x + width + 6, y + width + 4);
+            g.drawString("in", x + width + 6, y + width + 18);
+            y += 6;
+
+            //Draw Inches first.
+            drawVerticalRule(g2, false, inchOutSide, x, y, width, 0, div * 2, div * 4, div * 8);
+            drawHorizontalRule(g2, true, inchOutSide, x, y + width, width, 0, div * 2, div * 4, div * 8);
+            div = PrintUnit.MILLIMETERS.toPoints(1);  //mm increment
+            drawVerticalRule(g2, false, !inchOutSide, x, y, width, 0, 0, div * 5, div * 10);
+            drawHorizontalRule(g2, true, !inchOutSide, x, y + width, width, 0, 0, div * 5, div * 10);
+        }
+    }
+
+    /**
+     * Draw a horizontal ruler.
+     *
+     * @param g              the graphics context
+     * @param vertexAtLeft   true if the horizontal/vertical vertex is oriented to the top
+     * @param drawTicksDown  true if the ruler should draw interval tick marks to the underside of the solid ruler line
+     * @param x              starting x position of the ruler
+     * @param y              starting y position of the rule
+     * @param length         the number of points in length to extend the vertical ruler
+     * @param tinyEveryX     the number of points for each tiny division tick line; if zero or negative tiny will not be
+     *                       drawn
+     * @param minorEveryX    the number of points for each minor division tick line; if zero or negative minor will not
+     *                       be drawn
+     * @param midMajorEveryX the number of points for each mid-major division tick line
+     * @param majorEveryX    the number of points for each major division tick line (this is typically the inch or cm
+     *                       distance in points).
+     */
+    private void drawHorizontalRule(Graphics2D g,
+                                   boolean vertexAtLeft,
+                                   boolean drawTicksDown,
+                                   int x, int y, int length,
+                                   double tinyEveryX,
+                                   double minorEveryX,
+                                   double midMajorEveryX,
+                                   double majorEveryX) {
+
+        //Draw solid horizontal line
+        g.setColor(Color.black);
+        g.drawLine(x, y, x + length, y);
+
+        int tiniest = drawTicksDown ? TINIEST_TICK_LENGTH : -1 * TINIEST_TICK_LENGTH;
+        int minor = drawTicksDown ? MINOR_TICK_LENGTH : -1 * MINOR_TICK_LENGTH;
+        int mid = drawTicksDown ? MID_MAJOR_TICK_LENGTH : -1 * MID_MAJOR_TICK_LENGTH;
+        int major = drawTicksDown ? MAJOR_TICK_LENGTH : -1 * MAJOR_TICK_LENGTH;
+
+        //Draw vertical rule ticks for the horizontal ruler
+        //Draw minor ticks
+        int initial = x;
+        int end = initial + length;
+        double increment = tinyEveryX;
+        boolean lessThanEqual = true;
+        if (!vertexAtLeft) {
+            initial = x + length;
+            end = x;
+            lessThanEqual = false;
+        }
+
+        if (tinyEveryX > 0) {
+            if (!vertexAtLeft) {
+                increment = -1 * increment;
+            }
+            for (double xtick = initial; lessThanEqual ? (xtick <= end) : (xtick >= end); xtick += increment) {
+                g.drawLine((int) xtick, y, (int) xtick, y + tiniest);
+            }
+        }
+        //Draw minor ticks
+        if (minorEveryX > 0) {
+            if (!vertexAtLeft) {
+                increment = -1 * minorEveryX;
+            }
+            else {
+                increment = minorEveryX;
+            }
+            for (double xtick = initial; lessThanEqual ? (xtick <= end) : (xtick >= end); xtick += increment) {
+                g.drawLine((int) xtick, y, (int) xtick, y + minor);
+            }
+        }
+
+        //Draw mid-major ticks
+        if (midMajorEveryX > 0) {
+            if (!vertexAtLeft) {
+                increment = -1 * midMajorEveryX;
+            }
+            else {
+                increment = midMajorEveryX;
+            }
+            for (double xtick = initial; lessThanEqual ? (xtick <= end) : (xtick >= end); xtick += increment) {
+                g.drawLine((int) xtick, y, (int) xtick, y + mid);
+            }
+        }
+        if (!vertexAtLeft) {
+            increment = -1 * majorEveryX;
+        }
+        else {
+            increment = majorEveryX;
+        }
+        //Draw major ticks
+        for (double xtick = initial; lessThanEqual ? (xtick <= end) : (xtick >= end); xtick += increment) {
+            g.drawLine((int) xtick, y, (int) xtick, y + major);
+        }
+
+    }
+
+    /**
+     * Draw a vertical ruler.
+     *
+     * @param g              the graphics context
+     * @param vertexAtTop    true if the horizontal/vertical vertex is oriented to the top
+     * @param drawTicksRight true if the ruler should draw interval tick marks to the right side of the solid ruler
+     *                       line
+     * @param x              starting x position of the ruler
+     * @param y              starting y position of the rule
+     * @param length         the number of points in length to extend the vertical ruler
+     * @param tinyEveryY     the number of points for each tiny division tick line; if zero or negative tiny will not be
+     *                       drawn
+     * @param minorEveryY    the number of points for each minor division tick line; if zero or negative minor will not
+     *                       be drawn
+     * @param midMajorEveryY the number of points for each mid-major division tick line
+     * @param majorEveryY    the number of points for each major division tick line (this is typically the inch or cm
+     *                       distance in points).
+     */
+    private void drawVerticalRule(Graphics2D g,
+                                 boolean vertexAtTop,
+                                 boolean drawTicksRight, int x, int y, int length,
+                                 double tinyEveryY,
+                                 double minorEveryY,
+                                 double midMajorEveryY,
+                                 double majorEveryY) {
+
+        int tiniest = drawTicksRight ? TINIEST_TICK_LENGTH : -1 * TINIEST_TICK_LENGTH;
+        int minor = drawTicksRight ? MINOR_TICK_LENGTH : -1 * MINOR_TICK_LENGTH;
+        int mid = drawTicksRight ? MID_MAJOR_TICK_LENGTH : -1 * MID_MAJOR_TICK_LENGTH;
+        int major = drawTicksRight ? MAJOR_TICK_LENGTH : -1 * MAJOR_TICK_LENGTH;
+
+        //Draw solid vertical line
+        g.setColor(Color.black);
+        g.drawLine(x, y, x, y + length);
+
+        //Draw horizontal rule ticks for the vertical ruler
+        //Draw tiny ticks
+        int initial = y;
+        int end = initial + length;
+        double increment = tinyEveryY;
+        boolean lessThanEqual = true;
+        if (!vertexAtTop) {
+            initial = y + length;
+            end = y;
+            lessThanEqual = false;
+        }
+
+        if (tinyEveryY > 0) {
+            if (!vertexAtTop) {
+                increment = -1 * increment;
+            }
+            for (double tick = initial; lessThanEqual ? (tick <= end) : (tick >= end); tick += increment) {
+                g.drawLine(x, (int) tick, x - tiniest, (int) tick);
+            }
+        }
+
+        //Draw minor ticks
+        if (minorEveryY > 0) {
+            if (!vertexAtTop) {
+                increment = -1 * minorEveryY;
+            }
+            else {
+                increment = minorEveryY;
+            }
+            for (double tick = initial; lessThanEqual ? (tick <= end) : (tick >= end); tick += increment) {
+                g.drawLine(x, (int) tick, x - minor, (int) tick);
+            }
+        }
+
+        //Draw mid-major ticks
+        if (!vertexAtTop) {
+            increment = -1 * midMajorEveryY;
+        }
+        else {
+            increment = midMajorEveryY;
+        }
+        for (double tick = initial; lessThanEqual ? (tick <= end) : (tick >= end); tick += increment) {
+            g.drawLine(x, (int) tick, x - mid, (int) tick);
+        }
+
+        //Draw major ticks
+        if (!vertexAtTop) {
+            increment = -1 * majorEveryY;
+        }
+        else {
+            increment = majorEveryY;
+        }
+        for (double tick = initial; lessThanEqual ? (tick <= end) : (tick >= end); tick += increment) {
+            g.drawLine(x, (int) tick, x - major, (int) tick);
+        }
+
+    }
+}
\ No newline at end of file
index 5241c228cb31dfa53e3600810352cbbf9b3f2cbb..3cf17cae99b4ae8d099812319b472f0c82725939 100644 (file)
@@ -6,6 +6,7 @@ import com.itextpdf.text.Rectangle;
 import com.itextpdf.text.pdf.PdfWriter;
 import net.sf.openrocket.gui.print.AbstractPrintable;
 import net.sf.openrocket.gui.print.ITextHelper;
+import net.sf.openrocket.gui.print.PrintUnit;
 import net.sf.openrocket.gui.print.PrintableCenteringRing;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.rocketcomponent.CenteringRing;
@@ -104,9 +105,12 @@ public class CenteringRingStrategy {
                 pageFitPrint.addComponent(pfs);
             }
             else {
+                int off = (int) (PrintUnit.POINTS_PER_INCH * 0.3f);
+                pfs.setPrintOffset(off, off);
                 BufferedImage image = (BufferedImage) pfs.createImage();
                 ITextHelper.renderImageAcrossPages(new Rectangle(pageSize.getWidth(), pageSize.getHeight()),
                         document, writer, image);
+                document.newPage();
             }
         }
         catch (DocumentException e) {
index eb58ba4627831b7a83aa601a4f1a32ac2d0bfccb..3870490831217061986a4c16b7d60aa70f6be8fe 100644 (file)
@@ -6,7 +6,6 @@ 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.PrintUnit;
@@ -16,11 +15,8 @@ import net.sf.openrocket.rocketcomponent.FinSet;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.startup.Application;
 
-import java.awt.*;
 import java.awt.image.BufferedImage;
-import java.util.ArrayList;
 import java.util.List;
-import java.util.ListIterator;
 import java.util.Set;
 
 /**
@@ -52,7 +48,7 @@ public class FinSetPrintStrategy {
      * Strategy for fitting multiple components onto a page.
      */
        protected PageFitPrintStrategy pageFitPrint;
-    
+
     /**
      * Constructor.
      *
@@ -110,6 +106,8 @@ public class FinSetPrintStrategy {
                                        pageFitPrint.addComponent(pfs);
                 }
                 else {
+                    int off = (int)(PrintUnit.POINTS_PER_INCH * 0.3f);
+                    pfs.setPrintOffset(off, off);
                     BufferedImage image = (BufferedImage) pfs.createImage();
                     ITextHelper.renderImageAcrossPages(new Rectangle(pageSize.getWidth(), pageSize.getHeight()),
                             document, writer, image);
index 20ef3c19f99ec9cae22b4f4f7e7bb98c6c4dd80f..10ca735160b258701136c3a4ded05e3502a11514 100644 (file)
@@ -12,14 +12,15 @@ import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.startup.Application;
 
-import java.awt.*;
+import java.awt.Graphics2D;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.ListIterator;
 import java.util.Set;
 
 /**
  * A strategy for drawing multiple rocket components onto as few pages as possible.
- * 
+ *
  * @author Jason Blood <dyster2000@gmail.com>
  */
 public class PageFitPrintStrategy {
@@ -45,20 +46,19 @@ public class PageFitPrintStrategy {
     protected Set<Integer> stages;
 
        protected ArrayList<PrintableComponent> componentToPrint;
-    
+
     /**
      * Constructor.
      *
      * @param doc              The iText document
      * @param theWriter        The direct iText writer
-     * @param theStages        The stages to be printed by this strategy
      */
     public PageFitPrintStrategy(Document doc, PdfWriter theWriter) {
         document = doc;
         writer = theWriter;
        componentToPrint = new ArrayList<PrintableComponent>();
     }
-    
+
     /**
      * Add a component we want to print.
      *
@@ -87,16 +87,18 @@ public class PageFitPrintStrategy {
         int marginX = (int)(PrintUnit.POINTS_PER_INCH * 0.3f);
         int marginY = (int)(PrintUnit.POINTS_PER_INCH * 0.3f);
         PdfContentByte cb = writer.getDirectContent();
-       
+
+        Collections.sort(componentToPrint);
+
        while (componentToPrint.size() > 0) {
-               int pageY = 0;
+               int pageY = marginY;
                Boolean anyAddedToRow;
-               
+
             Graphics2D g2 = cb.createGraphics(pageSize.width, pageSize.height);
-               
+
                do {
                        // Fill the row
-                       int rowX = 0;
+                       int rowX = marginX;
                        int rowY = pageY;
                        ListIterator<PrintableComponent> entry = componentToPrint.listIterator();
                        anyAddedToRow = false;
@@ -104,23 +106,25 @@ public class PageFitPrintStrategy {
                        while (entry.hasNext()) {
                                PrintableComponent component = entry.next();
                                java.awt.Dimension dim = component.getSize();
-                               if ((rowX + dim.width < wPage) && (rowY + dim.height < hPage)) {
+                               if ((rowX + dim.width + marginX < wPage) && (rowY + dim.height + marginY < hPage)) {
                                        component.setPrintOffset(rowX, rowY);
                                        rowX += dim.width + marginX;
-                                       if (rowY + dim.height + marginY > pageY)
+                                       if (rowY + dim.height + marginY > pageY) {
                                                pageY = rowY + dim.height + marginY;
+                        }
                                        entry.remove();
                                        component.print(g2);
                                        anyAddedToRow = true;
                                }
                        }
+                pageY += marginY;
                } while (anyAddedToRow);
-               
+
                g2.dispose();
                document.newPage();
        }
     }
-    
+
     /**
      * Get the dimensions of the paper page.
      *
index 4752b3a7782c8ba681af3072dfb9d33e166ec874..b6f1ee04265a7dc63492f79175edc21a6a100e2e 100644 (file)
@@ -6,6 +6,7 @@ import com.itextpdf.text.Rectangle;
 import com.itextpdf.text.pdf.PdfWriter;
 import net.sf.openrocket.gui.print.AbstractPrintable;
 import net.sf.openrocket.gui.print.ITextHelper;
+import net.sf.openrocket.gui.print.PrintUnit;
 import net.sf.openrocket.gui.print.PrintableNoseCone;
 import net.sf.openrocket.gui.print.PrintableTransition;
 import net.sf.openrocket.logging.LogHelper;
@@ -46,7 +47,7 @@ public class TransitionStrategy {
     /**
      * Strategy for fitting multiple components onto a page.
      */
-       protected PageFitPrintStrategy pageFitPrint;
+    protected PageFitPrintStrategy pageFitPrint;
 
     /**
      * Constructor.
@@ -67,10 +68,12 @@ public class TransitionStrategy {
      *
      * @param root      the root component; all children will be visited recursively
      * @param noseCones nose cones are a special form of a transition; if true, then print nose cones
+     *
+     * @return true if a transition/nosecone was rendered
      */
-    public void writeToDocument(final RocketComponent root, boolean noseCones) {
+    public boolean writeToDocument(final RocketComponent root, boolean noseCones) {
         List<RocketComponent> rc = root.getChildren();
-        goDeep(rc, noseCones);
+        return goDeep(rc, noseCones);
     }
 
 
@@ -79,48 +82,62 @@ public class TransitionStrategy {
      *
      * @param theRc     an array of rocket components; all children will be visited recursively
      * @param noseCones nose cones are a special form of a transition; if true, then print nose cones
+     *
+     * @return true if a transition/nosecone was rendered
      */
-    protected void goDeep(final List<RocketComponent> theRc, boolean noseCones) {
+    protected boolean goDeep(final List<RocketComponent> theRc, boolean noseCones) {
         for (RocketComponent rocketComponent : theRc) {
             if (rocketComponent instanceof NoseCone) {
                 if (noseCones) {
-                    render((Transition) rocketComponent);
+                    return render((Transition) rocketComponent);
                 }
-            } else if (rocketComponent instanceof Transition && !noseCones) {
-                render((Transition) rocketComponent);
-            } else if (rocketComponent.getChildCount() > 0) {
-                goDeep(rocketComponent.getChildren(), noseCones);
+            }
+            else if (rocketComponent instanceof Transition && !noseCones) {
+                return render((Transition) rocketComponent);
+            }
+            else if (rocketComponent.getChildCount() > 0) {
+                return goDeep(rocketComponent.getChildren(), noseCones);
             }
         }
+        return false;
     }
 
     /**
      * The core behavior of this visitor.
      *
-     * @param component the object to extract info about; a graphical image of the transition shape is drawn to the document
+     * @param component the object to extract info about; a graphical image of the transition shape is drawn to the
+     *                  document
+     *
+     * @return true, always
      */
-    private void render(final Transition component) {
+    private boolean render(final Transition component) {
         try {
             AbstractPrintable pfs;
             if (component instanceof NoseCone) {
-                pfs = new PrintableNoseCone((NoseCone)component);
-            } else {
+                pfs = new PrintableNoseCone((NoseCone) component);
+            }
+            else {
                 pfs = new PrintableTransition(component);
             }
 
             java.awt.Dimension size = pfs.getSize();
             final Dimension pageSize = getPageSize();
             if (fitsOnOnePage(pageSize, size.getWidth(), size.getHeight())) {
-                               pageFitPrint.addComponent(pfs);
-                //printOnOnePage(pfs);
-            } else {
+                pageFitPrint.addComponent(pfs);
+            }
+            else {
+                int off = (int) (PrintUnit.POINTS_PER_INCH * 0.3f);
+                pfs.setPrintOffset(off, off);
                 BufferedImage image = (BufferedImage) pfs.createImage();
                 ITextHelper.renderImageAcrossPages(new Rectangle(pageSize.getWidth(), pageSize.getHeight()),
                         document, writer, image);
+                document.newPage();
             }
-        } catch (DocumentException e) {
+        }
+        catch (DocumentException e) {
             log.error("Could not render the transition.", e);
         }
+        return true;
     }
 
     /**
@@ -129,6 +146,7 @@ public class TransitionStrategy {
      * @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) {
diff --git a/core/test/net/sf/openrocket/gui/print/PrintUnitTest.java b/core/test/net/sf/openrocket/gui/print/PrintUnitTest.java
new file mode 100644 (file)
index 0000000..f92d18b
--- /dev/null
@@ -0,0 +1,49 @@
+package net.sf.openrocket.gui.print;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+* PrintUnit Tester.
+*
+*/
+public class PrintUnitTest {
+
+    /**
+     *
+     * Method: toMillis(double length)
+     *
+     */
+    @Test
+    public void testToMillis() throws Exception {
+        Assert.assertEquals(25.400000, PrintUnit.INCHES.toMillis(1), 0.00001);
+        Assert.assertEquals(1, PrintUnit.MILLIMETERS.toInches(PrintUnit.INCHES.toMillis(1)), 0.000001);
+    }
+
+    /**
+     *
+     * Method: toCentis(double length)
+     *
+     */
+    @Test
+    public void testToCentis() throws Exception {
+        Assert.assertEquals(4, PrintUnit.CENTIMETERS.toMeters(PrintUnit.METERS.toCentis(4)), 0.000001);
+        Assert.assertEquals(4, PrintUnit.CENTIMETERS.toPoints(PrintUnit.POINTS.toCentis(4)), 0.000001);
+    }
+
+    /**
+     *
+     * Method: toPoints(double length)
+     *
+     */
+    @Test
+    public void testToPoints() throws Exception {
+        Assert.assertEquals(1, PrintUnit.POINTS.toInches(72), 0.00001);
+        Assert.assertEquals(25.4, PrintUnit.POINTS.toMillis(72), 0.00001);
+        Assert.assertEquals(1, PrintUnit.MILLIMETERS.toPoints(PrintUnit.POINTS.toMillis(1)), 0.000001);
+
+        Assert.assertEquals(28.3464567, PrintUnit.CENTIMETERS.toPoints(1), 0.000001d);
+    }
+
+
+}