]> git.gag.com Git - debian/openrocket/commitdiff
Print support for clustered centering rings.
authorrodinia814 <rodinia814@180e2498-e6e9-4542-8430-84ac67f01cd8>
Wed, 30 May 2012 22:41:01 +0000 (22:41 +0000)
committerrodinia814 <rodinia814@180e2498-e6e9-4542-8430-84ac67f01cd8>
Wed, 30 May 2012 22:41:01 +0000 (22:41 +0000)
git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@732 180e2498-e6e9-4542-8430-84ac67f01cd8

core/src/net/sf/openrocket/gui/print/PrintableCenteringRing.java
core/src/net/sf/openrocket/gui/print/visitor/CenteringRingStrategy.java

index ed0a66d22be804cfd4291e120d4f598cf565568d..502e045ab49c0937d5add741f5e42f2e78f6fa38 100644 (file)
@@ -1,16 +1,24 @@
 package net.sf.openrocket.gui.print;
 
+import net.sf.openrocket.gui.print.visitor.CenteringRingStrategy;
 import net.sf.openrocket.rocketcomponent.CenteringRing;
+import net.sf.openrocket.rocketcomponent.ClusterConfiguration;
+import net.sf.openrocket.rocketcomponent.InnerTube;
+import net.sf.openrocket.util.ArrayList;
+import net.sf.openrocket.util.Coordinate;
 
 import java.awt.Color;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.Shape;
 import java.awt.geom.Ellipse2D;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 /**
- * This class creates a renderable centering ring.  It depends only on AWT/Swing and can be called from other
- * actors (like iText handlers) to render the centering ring on different graphics contexts.
+ * This class creates a renderable centering ring.  It depends only on AWT/Swing and can be called from other actors
+ * (like iText handlers) to render the centering ring on different graphics contexts.
  */
 public class PrintableCenteringRing extends AbstractPrintable<CenteringRing> {
     /**
@@ -24,12 +32,79 @@ public class PrintableCenteringRing extends AbstractPrintable<CenteringRing> {
     private final int lineLength = 10;
 
     /**
-     * Construct a printable nose cone.
+     * A set of the inner 'holes'.  At least one, but will have many if clustered.
+     */
+    private Set<CenteringRingStrategy.Dimension> innerCenterPoints = new HashSet<CenteringRingStrategy.Dimension>();
+
+    /**
+     * Construct a simple, non-clustered, printable centering ring.
      *
-     * @param theRing the component to print
+     * @param theRing       the component to print
+     * @param theMotorMount the motor mount if clustered, else null
      */
-    public PrintableCenteringRing(CenteringRing theRing) {
+    private PrintableCenteringRing(CenteringRing theRing, InnerTube theMotorMount) {
         super(false, theRing);
+        if (theMotorMount == null || theMotorMount.getClusterConfiguration().equals(ClusterConfiguration.SINGLE)) {
+            //Single motor.
+            innerCenterPoints.add(new CenteringRingStrategy.Dimension((float) PrintUnit.METERS.toPoints(target.getOuterRadius()),
+                    (float) PrintUnit.METERS.toPoints(target.getOuterRadius())));
+        }
+        else {
+            List<Coordinate> coords = theMotorMount.getClusterPoints();
+            populateCenterPoints(coords);
+        }
+    }
+
+    /**
+     * Constructor for a clustered centering ring.
+     *
+     * @param theRing        the centering ring component
+     * @param theMotorMounts a list of the motor mount tubes that are physically supported by the centering ring
+     */
+    private PrintableCenteringRing(CenteringRing theRing, List<InnerTube> theMotorMounts) {
+        super(false, theRing);
+        List<Coordinate> points = new ArrayList<Coordinate>();
+        //Transform the radial positions of the tubes.
+        for (InnerTube it : theMotorMounts) {
+            double y = it.getRadialShiftY();
+            double z = it.getRadialShiftZ();
+            Coordinate coordinate = new Coordinate(0, y, z);
+            points.add(coordinate);
+        }
+        populateCenterPoints(points);
+    }
+
+    /**
+     * Factory method to create a printable centering ring.
+     *
+     * @param theRing        the component to print
+     * @param theMotorMounts the motor mount if clustered, else null
+     */
+    public static PrintableCenteringRing create(CenteringRing theRing, List<InnerTube> theMotorMounts) {
+        if (theMotorMounts == null) {
+            return new PrintableCenteringRing(theRing, (InnerTube) null);
+        }
+        else if (theMotorMounts.size() <= 1) {
+            return new PrintableCenteringRing(theRing, theMotorMounts.isEmpty() ? null : theMotorMounts.get(0));
+        }
+        else {
+            return new PrintableCenteringRing(theRing, theMotorMounts);
+        }
+    }
+
+    /**
+     * Initialize the set of center points for each motor mount tube, based on the tube coordinates.
+     *
+     * @param theCoords the list of tube coordinates; each coordinate is in the OR units (meters) and must be
+     *                  transformed to the printing (points) coordinate system
+     */
+    private void populateCenterPoints(final List<Coordinate> theCoords) {
+        float radius = (float) PrintUnit.METERS.toPoints(target.getOuterRadius());
+        for (Coordinate coordinate : theCoords) {
+            innerCenterPoints.add(new CenteringRingStrategy.Dimension((float) PrintUnit.METERS.toPoints
+                    (coordinate.y) + radius,
+                    (float) PrintUnit.METERS.toPoints(coordinate.z) + radius));
+        }
     }
 
     /**
@@ -55,33 +130,43 @@ public class PrintableCenteringRing extends AbstractPrintable<CenteringRing> {
         double radius = PrintUnit.METERS.toPoints(target.getOuterRadius());
 
         Color original = g2.getBackground();
-        double x = 0;
-        double y = 0;
-        Shape outerCircle = new Ellipse2D.Double(x, y, radius * 2, radius * 2);
+        Shape outerCircle = new Ellipse2D.Double(0, 0, radius * 2, radius * 2);
         g2.setColor(Color.lightGray);
         g2.fill(outerCircle);
         g2.setColor(Color.black);
         g2.draw(outerCircle);
-        x += radius;
-        y += radius;
 
-        double innerRadius = PrintUnit.METERS.toPoints(target.getInnerRadius());
-        Shape innerCircle = new Ellipse2D.Double(x - innerRadius, y - innerRadius, innerRadius * 2, innerRadius * 2);
+        for (CenteringRingStrategy.Dimension next : innerCenterPoints) {
+            drawInnerCircle(g2, next.getWidth(), next.getHeight());
+        }
         g2.setColor(original);
+    }
+
+    /**
+     * Draw one inner circle, representing the motor mount tube, with cross hairs in the center.
+     *
+     * @param g2         the graphics context
+     * @param theCenterX the center x in points
+     * @param theCenterY the center y in points
+     */
+    private void drawInnerCircle(final Graphics2D g2, final double theCenterX, final double theCenterY) {
+        double innerRadius = PrintUnit.METERS.toPoints(target.getInnerRadius());
+        Shape innerCircle = new Ellipse2D.Double(theCenterX - innerRadius, theCenterY - innerRadius, innerRadius * 2, innerRadius * 2);
+        g2.setColor(Color.white);
         g2.fill(innerCircle);
         g2.setColor(Color.black);
         g2.draw(innerCircle);
 
-        drawCross(g2, (int) x, (int) y, lineLength, lineLength);
+        drawCross(g2, (int) theCenterX, (int) theCenterY, lineLength, lineLength);
     }
 
     /**
      * Draw the center cross-hair.
      *
-     * @param g  the graphics context
-     * @param x  the x coordinate of the center point
-     * @param y  the y coordinate of the center point
-     * @param width the width in pixels of the horizontal hair
+     * @param g      the graphics context
+     * @param x      the x coordinate of the center point
+     * @param y      the y coordinate of the center point
+     * @param width  the width in pixels of the horizontal hair
      * @param height the width in pixels of the vertical hair
      */
     private void drawCross(Graphics g, int x, int y, int width, int height) {
index 3cf17cae99b4ae8d099812319b472f0c82725939..a3315aedd5f53b5d72f1fa3ada7919c7640e5980 100644 (file)
@@ -10,8 +10,10 @@ 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;
+import net.sf.openrocket.rocketcomponent.InnerTube;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.ArrayList;
 
 import java.awt.image.BufferedImage;
 import java.util.List;
@@ -88,6 +90,58 @@ public class CenteringRingStrategy {
         }
     }
 
+    /**
+     * Find the inner tubes that are physically supported by the given centering ring.  Note that this only looks for
+     * motor mount tubes that are siblings to the centering ring.
+     *
+     * @param rc the centering ring, for which all motor mount tubes that run through it are located.
+     *
+     * @return the list of tubes found
+     */
+    private List<InnerTube> findMotorMount(CenteringRing rc) {
+        RocketComponent parent = rc.getParent();
+        List<RocketComponent> siblings = parent.getChildren();
+
+        List<InnerTube> mounts = new ArrayList<InnerTube>();
+        for (RocketComponent rocketComponents : siblings) {
+            if (rocketComponents != rc) {
+                if (rocketComponents instanceof InnerTube) {
+                    InnerTube it = (InnerTube) rocketComponents;
+                    if (it.isMotorMount()) {
+                        if (overlaps(rc, it)) {
+                            mounts.add(it);
+                        }
+                    }
+                }
+            }
+        }
+
+        return mounts;
+    }
+
+    /**
+     * Determine if the centering ring physically overlaps with the inner tube.
+     *
+     * @param one the centering ring
+     * @param two the inner body tube
+     *
+     * @return true if the two physically intersect, from which we infer that the centering ring supports the tube
+     */
+    private boolean overlaps(CenteringRing one, InnerTube two) {
+        final double crTopPosition = one.asPositionValue(RocketComponent.Position.ABSOLUTE, one.getParent());
+        final double mmTopPosition = two.asPositionValue(RocketComponent.Position.ABSOLUTE, two.getParent());
+        final double crBottomPosition = one.getLength() + crTopPosition;
+        final double mmBottomPosition = two.getLength() + mmTopPosition;
+
+        if (crTopPosition >= mmTopPosition && crTopPosition <= mmBottomPosition) {
+            return true;
+        }
+        if (crBottomPosition >= mmTopPosition && crBottomPosition <= mmBottomPosition) {
+            return true;
+        }
+        return false;
+    }
+
     /**
      * The core behavior of this visitor.
      *
@@ -97,7 +151,7 @@ public class CenteringRingStrategy {
     private void render(final CenteringRing component) {
         try {
             AbstractPrintable pfs;
-            pfs = new PrintableCenteringRing(component);
+            pfs = PrintableCenteringRing.create(component, findMotorMount(component));
 
             java.awt.Dimension size = pfs.getSize();
             final Dimension pageSize = getPageSize();
@@ -150,7 +204,7 @@ public class CenteringRingStrategy {
     /**
      * Convenience class to model a dimension.
      */
-    class Dimension {
+    public static class Dimension {
         /**
          * Width, in points.
          */