major optimization updates
[debian/openrocket] / src / net / sf / openrocket / gui / scalefigure / RocketFigure.java
index ea1f98c7180c4bf3d705f1c86d8c70b737a218a2..2f7556e2ab52e35f86c7b0b91f785cc575ac6c72 100644 (file)
@@ -1,20 +1,6 @@
 package net.sf.openrocket.gui.scalefigure;
 
 
-import net.sf.openrocket.gui.figureelements.FigureElement;
-import net.sf.openrocket.gui.main.ExceptionHandler;
-import net.sf.openrocket.motor.Motor;
-import net.sf.openrocket.rocketcomponent.Configuration;
-import net.sf.openrocket.rocketcomponent.MotorMount;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.util.BugException;
-import net.sf.openrocket.util.Coordinate;
-import net.sf.openrocket.util.LineStyle;
-import net.sf.openrocket.util.MathUtil;
-import net.sf.openrocket.util.Prefs;
-import net.sf.openrocket.util.Reflection;
-import net.sf.openrocket.util.Transformation;
-
 import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Dimension;
@@ -33,6 +19,20 @@ import java.util.Collection;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
 
+import net.sf.openrocket.gui.figureelements.FigureElement;
+import net.sf.openrocket.gui.main.ExceptionHandler;
+import net.sf.openrocket.motor.Motor;
+import net.sf.openrocket.rocketcomponent.Configuration;
+import net.sf.openrocket.rocketcomponent.MotorMount;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.util.BugException;
+import net.sf.openrocket.util.Coordinate;
+import net.sf.openrocket.util.LineStyle;
+import net.sf.openrocket.util.MathUtil;
+import net.sf.openrocket.util.Prefs;
+import net.sf.openrocket.util.Reflection;
+import net.sf.openrocket.util.Transformation;
+
 /**
  * A <code>ScaleFigure</code> that draws a complete rocket.  Extra information can
  * be added to the figure by the methods {@link #addRelativeExtra(FigureElement)},
@@ -40,7 +40,6 @@ import java.util.LinkedHashSet;
  * 
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
-
 public class RocketFigure extends AbstractScaleFigure {
        private static final long serialVersionUID = 1L;
        
@@ -53,31 +52,31 @@ public class RocketFigure extends AbstractScaleFigure {
        // Width for drawing normal and selected components
        public static final double NORMAL_WIDTH = 1.0;
        public static final double SELECTED_WIDTH = 2.0;
-
        
-       private final Configuration configuration;
+
+       private Configuration configuration;
        private RocketComponent[] selection = new RocketComponent[0];
        
        private int type = TYPE_SIDE;
-
+       
        private double rotation;
        private Transformation transformation;
        
        private double translateX, translateY;
        
-       
-       
+
+
        /*
         * figureComponents contains the corresponding RocketComponents of the figureShapes
         */
        private final ArrayList<Shape> figureShapes = new ArrayList<Shape>();
-       private final ArrayList<RocketComponent> figureComponents = 
-               new ArrayList<RocketComponent>();
+       private final ArrayList<RocketComponent> figureComponents =
+                       new ArrayList<RocketComponent>();
        
-       private double minX=0, maxX=0, maxR=0;
+       private double minX = 0, maxX = 0, maxR = 0;
        // Figure width and height in SI-units and pixels
-       private double figureWidth=0, figureHeight=0;
-       private int figureWidthPx=0, figureHeightPx=0;
+       private double figureWidth = 0, figureHeight = 0;
+       private int figureWidthPx = 0, figureHeightPx = 0;
        
        private AffineTransform g2transformation = null;
        
@@ -96,26 +95,36 @@ public class RocketFigure extends AbstractScaleFigure {
                this.rotation = 0.0;
                this.transformation = Transformation.rotate_x(0.0);
                
-               calculateSize();
                updateFigure();
        }
        
        
+       /**
+        * Set the configuration displayed by the figure.  It may use the same or different rocket.
+        * 
+        * @param configuration         the configuration to display.
+        */
+       public void setConfiguration(Configuration configuration) {
+               this.configuration = configuration;
+               updateFigure();
+       }
+       
        
+       @Override
        public Dimension getOrigin() {
-               return new Dimension((int)translateX, (int)translateY);
+               return new Dimension((int) translateX, (int) translateY);
        }
        
        @Override
        public double getFigureHeight() {
                return figureHeight;
        }
-
+       
        @Override
        public double getFigureWidth() {
                return figureWidth;
        }
-
+       
        
        public RocketComponent[] getSelection() {
                return selection;
@@ -154,19 +163,18 @@ public class RocketFigure extends AbstractScaleFigure {
        
        public void setType(int type) {
                if (type != TYPE_BACK && type != TYPE_SIDE) {
-                       throw new IllegalArgumentException("Illegal type: "+type);
+                       throw new IllegalArgumentException("Illegal type: " + type);
                }
                if (this.type == type)
                        return;
                this.type = type;
                updateFigure();
        }
-
-       
        
        
 
 
+
        /**
         * Updates the figure shapes and figure size.
         */
@@ -176,11 +184,11 @@ public class RocketFigure extends AbstractScaleFigure {
                figureComponents.clear();
                
                calculateSize();
-
+               
                // Get shapes for all active components
-               for (RocketComponent c: configuration) {
+               for (RocketComponent c : configuration) {
                        Shape[] s = getShapes(c);
-                       for (int i=0; i < s.length; i++) {
+                       for (int i = 0; i < s.length; i++) {
                                figureShapes.add(s[i]);
                                figureComponents.add(c);
                        }
@@ -189,7 +197,7 @@ public class RocketFigure extends AbstractScaleFigure {
                repaint();
                fireChangeEvent();
        }
-
+       
        
        public void addRelativeExtra(FigureElement p) {
                relativeExtra.add(p);
@@ -216,7 +224,7 @@ public class RocketFigure extends AbstractScaleFigure {
                absoluteExtra.clear();
        }
        
-
+       
        /**
         * Paints the rocket on to the Graphics element.
         * <p>
@@ -227,39 +235,39 @@ public class RocketFigure extends AbstractScaleFigure {
        @Override
        public void paintComponent(Graphics g) {
                super.paintComponent(g);
-               Graphics2D g2 = (Graphics2D)g;
-               
+               Graphics2D g2 = (Graphics2D) g;
                
+
                AffineTransform baseTransform = g2.getTransform();
                
                // Update figure shapes if necessary
                if (figureShapes == null)
                        updateFigure();
-
+               
 
                double tx, ty;
                // Calculate translation for figure centering
-               if (figureWidthPx + 2*BORDER_PIXELS_WIDTH < getWidth()) {
-
+               if (figureWidthPx + 2 * borderPixelsWidth < getWidth()) {
+                       
                        // Figure fits in the viewport
                        if (type == TYPE_BACK)
-                               tx = getWidth()/2;
-                       else 
-                               tx = (getWidth()-figureWidthPx)/2 - minX*scale;
-
+                               tx = getWidth() / 2;
+                       else
+                               tx = (getWidth() - figureWidthPx) / 2 - minX * scale;
+                       
                } else {
-
+                       
                        // Figure does not fit in viewport
                        if (type == TYPE_BACK)
-                               tx = BORDER_PIXELS_WIDTH + figureWidthPx/2;
-                       else 
-                               tx = BORDER_PIXELS_WIDTH - minX*scale;
+                               tx = borderPixelsWidth + figureWidthPx / 2;
+                       else
+                               tx = borderPixelsWidth - minX * scale;
                        
                }
-
-        ty = computeTy(figureHeightPx);
-
-        if (Math.abs(translateX - tx)>1 || Math.abs(translateY - ty)>1) {
+               
+               ty = computeTy(figureHeightPx);
+               
+               if (Math.abs(translateX - tx) > 1 || Math.abs(translateY - ty) > 1) {
                        // Origin has changed, fire event
                        translateX = tx;
                        translateY = ty;
@@ -272,28 +280,28 @@ public class RocketFigure extends AbstractScaleFigure {
                g2transformation = new AffineTransform();
                g2transformation.translate(translateX, translateY);
                // Mirror position Y-axis upwards
-               g2transformation.scale(scale/EXTRA_SCALE, -scale/EXTRA_SCALE);
-
+               g2transformation.scale(scale / EXTRA_SCALE, -scale / EXTRA_SCALE);
+               
                g2.transform(g2transformation);
-
+               
                // Set rendering hints appropriately
-               g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, 
+               g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
                                RenderingHints.VALUE_STROKE_NORMALIZE);
-               g2.setRenderingHint(RenderingHints.KEY_RENDERING, 
+               g2.setRenderingHint(RenderingHints.KEY_RENDERING,
                                RenderingHints.VALUE_RENDER_QUALITY);
-               g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
+               g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                RenderingHints.VALUE_ANTIALIAS_ON);
-
+               
 
                // Draw all shapes
                
-               for (int i=0; i < figureShapes.size(); i++) {
+               for (int i = 0; i < figureShapes.size(); i++) {
                        RocketComponent c = figureComponents.get(i);
                        Shape s = figureShapes.get(i);
                        boolean selected = false;
                        
                        // Check if component is in the selection
-                       for (int j=0; j < selection.length; j++) {
+                       for (int j = 0; j < selection.length; j++) {
                                if (c == selection[j]) {
                                        selected = true;
                                        break;
@@ -306,37 +314,37 @@ public class RocketFigure extends AbstractScaleFigure {
                                color = Prefs.getDefaultColor(c.getClass());
                        }
                        g2.setColor(color);
-
+                       
                        LineStyle style = c.getLineStyle();
                        if (style == null)
                                style = Prefs.getDefaultLineStyle(c.getClass());
                        
                        float[] dashes = style.getDashes();
-                       for (int j=0; j<dashes.length; j++) {
+                       for (int j = 0; j < dashes.length; j++) {
                                dashes[j] *= EXTRA_SCALE / scale;
                        }
                        
                        if (selected) {
-                               g2.setStroke(new BasicStroke((float)(SELECTED_WIDTH*EXTRA_SCALE/scale),
-                                               BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL, 0, dashes, 0));
+                               g2.setStroke(new BasicStroke((float) (SELECTED_WIDTH * EXTRA_SCALE / scale),
+                                               BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, dashes, 0));
                                g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
                                                RenderingHints.VALUE_STROKE_PURE);
                        } else {
-                               g2.setStroke(new BasicStroke((float)(NORMAL_WIDTH*EXTRA_SCALE/scale),
-                                               BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL, 0, dashes, 0));
-                               g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, 
+                               g2.setStroke(new BasicStroke((float) (NORMAL_WIDTH * EXTRA_SCALE / scale),
+                                               BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, dashes, 0));
+                               g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
                                                RenderingHints.VALUE_STROKE_NORMALIZE);
                        }
                        g2.draw(s);
                        
                }
                
-               g2.setStroke(new BasicStroke((float)(NORMAL_WIDTH*EXTRA_SCALE/scale),
-                               BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL));
-               g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, 
+               g2.setStroke(new BasicStroke((float) (NORMAL_WIDTH * EXTRA_SCALE / scale),
+                               BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
+               g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
                                RenderingHints.VALUE_STROKE_NORMALIZE);
-
                
+
                // Draw motors
                String motorID = configuration.getMotorConfigurationID();
                Color fillColor = Prefs.getMotorFillColor();
@@ -348,24 +356,24 @@ public class RocketFigure extends AbstractScaleFigure {
                        double length = motor.getLength();
                        double radius = motor.getDiameter() / 2;
                        
-                       Coordinate[] position = ((RocketComponent)mount).toAbsolute(
-                                       new Coordinate(((RocketComponent)mount).getLength() + 
+                       Coordinate[] position = ((RocketComponent) mount).toAbsolute(
+                                       new Coordinate(((RocketComponent) mount).getLength() +
                                                        mount.getMotorOverhang() - length));
                        
-                       for (int i=0; i < position.length; i++) {
+                       for (int i = 0; i < position.length; i++) {
                                position[i] = transformation.transform(position[i]);
                        }
                        
-                       for (Coordinate coord: position) {
+                       for (Coordinate coord : position) {
                                Shape s;
                                if (type == TYPE_SIDE) {
-                                       s = new Rectangle2D.Double(EXTRA_SCALE*coord.x,
-                                                       EXTRA_SCALE*(coord.y - radius), EXTRA_SCALE*length, 
-                                                       EXTRA_SCALE*2*radius);
+                                       s = new Rectangle2D.Double(EXTRA_SCALE * coord.x,
+                                                       EXTRA_SCALE * (coord.y - radius), EXTRA_SCALE * length,
+                                                       EXTRA_SCALE * 2 * radius);
                                } else {
-                                       s = new Ellipse2D.Double(EXTRA_SCALE*(coord.z-radius),
-                                                       EXTRA_SCALE*(coord.y-radius), EXTRA_SCALE*2*radius,
-                                                       EXTRA_SCALE*2*radius);
+                                       s = new Ellipse2D.Double(EXTRA_SCALE * (coord.z - radius),
+                                                       EXTRA_SCALE * (coord.y - radius), EXTRA_SCALE * 2 * radius,
+                                                       EXTRA_SCALE * 2 * radius);
                                }
                                g2.setColor(fillColor);
                                g2.fill(s);
@@ -374,46 +382,46 @@ public class RocketFigure extends AbstractScaleFigure {
                        }
                }
                
-               
-               
+
+
                // Draw relative extras
-               for (FigureElement e: relativeExtra) {
-                       e.paint(g2, scale/EXTRA_SCALE);
+               for (FigureElement e : relativeExtra) {
+                       e.paint(g2, scale / EXTRA_SCALE);
                }
-
+               
                // Draw absolute extras
                g2.setTransform(baseTransform);
                Rectangle rect = this.getVisibleRect();
                
-               for (FigureElement e: absoluteExtra) {
+               for (FigureElement e : absoluteExtra) {
                        e.paint(g2, 1.0, rect);
                }
-
+               
        }
-
-    protected double computeTy (int heightPx) {
-        final double ty;
-        if (heightPx + 2*BORDER_PIXELS_HEIGHT < getHeight()) {
-             ty = getHeight()/2;
-        } else {
-             ty = BORDER_PIXELS_HEIGHT + heightPx/2;
-        }
-        return ty;
-    }
-
-
-    public RocketComponent[] getComponentsByPoint(double x, double y) {
+       
+       protected double computeTy(int heightPx) {
+               final double ty;
+               if (heightPx + 2 * borderPixelsHeight < getHeight()) {
+                       ty = getHeight() / 2;
+               } else {
+                       ty = borderPixelsHeight + heightPx / 2;
+               }
+               return ty;
+       }
+       
+       
+       public RocketComponent[] getComponentsByPoint(double x, double y) {
                // Calculate point in shapes' coordinates
-               Point2D.Double p = new Point2D.Double(x,y);
+               Point2D.Double p = new Point2D.Double(x, y);
                try {
-                       g2transformation.inverseTransform(p,p);
+                       g2transformation.inverseTransform(p, p);
                } catch (NoninvertibleTransformException e) {
                        return new RocketComponent[0];
                }
                
                LinkedHashSet<RocketComponent> l = new LinkedHashSet<RocketComponent>();
-
-               for (int i=0; i<figureShapes.size(); i++) {
+               
+               for (int i = 0; i < figureShapes.size(); i++) {
                        if (figureShapes.get(i).contains(p))
                                l.add(figureComponents.get(i));
                }
@@ -421,7 +429,7 @@ public class RocketFigure extends AbstractScaleFigure {
        }
        
        
-       
+
        /**
         * Gets the shapes required to draw the component.
         * 
@@ -431,34 +439,34 @@ public class RocketFigure extends AbstractScaleFigure {
         */
        private Shape[] getShapes(RocketComponent component) {
                Reflection.Method m;
-
+               
                // Find the appropriate method
                switch (type) {
                case TYPE_SIDE:
-                       m = Reflection.findMethod(ROCKET_FIGURE_PACKAGE, component, ROCKET_FIGURE_SUFFIX, "getShapesSide", 
+                       m = Reflection.findMethod(ROCKET_FIGURE_PACKAGE, component, ROCKET_FIGURE_SUFFIX, "getShapesSide",
                                        RocketComponent.class, Transformation.class);
                        break;
-                       
+               
                case TYPE_BACK:
-                       m = Reflection.findMethod(ROCKET_FIGURE_PACKAGE, component, ROCKET_FIGURE_SUFFIX, "getShapesBack", 
+                       m = Reflection.findMethod(ROCKET_FIGURE_PACKAGE, component, ROCKET_FIGURE_SUFFIX, "getShapesBack",
                                        RocketComponent.class, Transformation.class);
                        break;
-                       
+               
                default:
-                       throw new BugException("Unknown figure type = "+type);
+                       throw new BugException("Unknown figure type = " + type);
                }
                
                if (m == null) {
-                       ExceptionHandler.handleErrorCondition("ERROR: Rocket figure paint method not found for " 
+                       ExceptionHandler.handleErrorCondition("ERROR: Rocket figure paint method not found for "
                                        + component);
                        return new Shape[0];
                }
-
-               return (Shape[])m.invokeStatic(component,transformation);
+               
+               return (Shape[]) m.invokeStatic(component, transformation);
        }
        
        
-       
+
        /**
         * Gets the bounds of the figure, i.e. the maximum extents in the selected dimensions.
         * The bounds are stored in the variables minX, maxX and maxR.
@@ -472,11 +480,11 @@ public class RocketFigure extends AbstractScaleFigure {
                        maxR = 0;
                        return;
                }
-
+               
                minX = Double.MAX_VALUE;
                maxX = Double.MIN_VALUE;
                maxR = 0;
-               for (Coordinate c: bounds) {
+               for (Coordinate c : bounds) {
                        double x = c.x, r = MathUtil.hypot(c.y, c.z);
                        if (x < minX)
                                minX = x;
@@ -489,15 +497,16 @@ public class RocketFigure extends AbstractScaleFigure {
        
        
        public double getBestZoom(Rectangle2D bounds) {
-               double zh=1, zv=1;
+               double zh = 1, zv = 1;
                if (bounds.getWidth() > 0.0001)
-                       zh = (getWidth()-2*BORDER_PIXELS_WIDTH)/bounds.getWidth();
+                       zh = (getWidth() - 2 * borderPixelsWidth) / bounds.getWidth();
                if (bounds.getHeight() > 0.0001)
-                       zv = (getHeight()-2*BORDER_PIXELS_HEIGHT)/bounds.getHeight();
+                       zv = (getHeight() - 2 * borderPixelsHeight) / bounds.getHeight();
                return Math.min(zh, zv);
        }
-
        
+       
+
        /**
         * Calculates the necessary size of the figure and set the PreferredSize 
         * property accordingly.
@@ -507,26 +516,26 @@ public class RocketFigure extends AbstractScaleFigure {
                
                switch (type) {
                case TYPE_SIDE:
-                       figureWidth = maxX-minX;
-                       figureHeight = 2*maxR;
+                       figureWidth = maxX - minX;
+                       figureHeight = 2 * maxR;
                        break;
-                       
+               
                case TYPE_BACK:
-                       figureWidth = 2*maxR;
-                       figureHeight = 2*maxR;
+                       figureWidth = 2 * maxR;
+                       figureHeight = 2 * maxR;
                        break;
-                       
+               
                default:
-                       assert(false): "Should not occur, type="+type;
+                       assert (false) : "Should not occur, type=" + type;
                        figureWidth = 0;
                        figureHeight = 0;
                }
                
-               figureWidthPx = (int)(figureWidth * scale);
-               figureHeightPx = (int)(figureHeight * scale);
-
-               Dimension d = new Dimension(figureWidthPx+2*BORDER_PIXELS_WIDTH,
-                               figureHeightPx+2*BORDER_PIXELS_HEIGHT);
+               figureWidthPx = (int) (figureWidth * scale);
+               figureHeightPx = (int) (figureHeight * scale);
+               
+               Dimension d = new Dimension(figureWidthPx + 2 * borderPixelsWidth,
+                               figureHeightPx + 2 * borderPixelsHeight);
                
                if (!d.equals(getPreferredSize()) || !d.equals(getMinimumSize())) {
                        setPreferredSize(d);
@@ -538,14 +547,14 @@ public class RocketFigure extends AbstractScaleFigure {
        public Rectangle2D getDimensions() {
                switch (type) {
                case TYPE_SIDE:
-                       return new Rectangle2D.Double(minX,-maxR,maxX-minX,2*maxR);
+                       return new Rectangle2D.Double(minX, -maxR, maxX - minX, 2 * maxR);
                        
                case TYPE_BACK:
-                       return new Rectangle2D.Double(-maxR,-maxR,2*maxR,2*maxR);
+                       return new Rectangle2D.Double(-maxR, -maxR, 2 * maxR, 2 * maxR);
                        
                default:
-                       throw new BugException("Illegal figure type = "+type);
+                       throw new BugException("Illegal figure type = " + type);
                }
        }
-
+       
 }