Graphics: Zoom rubber box general improvements 97/18197/9
Caio SOUZA [Mon, 30 May 2016 19:13:23 +0000 (16:13 -0300)]
* The zoom rubber box now can start/finish from points lying outside the axes bounds.
* The zoom rubber box now can select multiple and overlying axes at once. Changed behavior of scroll zoom, scrolling over overlying axes will zoom all of them together, using the CTRL key while scrolling will zoom all axes in the current figure.
* [Bug #11959](http://bugzilla.scilab.org/show_bug.cgi?id=11959) fixed - Allow "Zoom Area" to be clicked out of axes
* [Bug #12110](http://bugzilla.scilab.org/show_bug.cgi?id=12110) fixed - Unable to zoom multiple axes at once

Change-Id: I78bc245f67fa220c7885d259e35880c5561f6c95

scilab/CHANGES.md
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/DragPointRubberBox.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/DragZoomRotateInteraction.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/FigureInteraction.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/OnePointRubberBox.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/RubberBox.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/TwoPointsRubberBox.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/ZoomRubberBox.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/AbstractPointComputer.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/CubeFacesPointComputer.java

index f75571d..b29cb1b 100644 (file)
@@ -138,6 +138,8 @@ Feature changes and additions
 * `strange([])` now returns %nan instead of [], as all other functions for statistical dispersion
 * `stdev(x, dir>ndims(x))` now yields an error instead of returning `zeros(x)`
 * `write`: Writing string or string matrix in a file does not add blank space before each value
+* The zoom rubber box now can start/finish from points lying outside the axes bounds.
+* The zoom rubber box now can select multiple and overlying axes at once. Changed behavior of scroll zoom, scrolling over overlying axes will zoom all of them together, using the CTRL key while scrolling will zoom all axes in the current figure.
 
 
 Help pages:
@@ -227,6 +229,8 @@ Bug Fixes
 
 ### In 6.0.0:
 
+* [Bug #11959](http://bugzilla.scilab.org/show_bug.cgi?id=11959) fixed - Allow "Zoom Area" to be clicked out of axes
+* [Bug #12110](http://bugzilla.scilab.org/show_bug.cgi?id=12110) fixed - Unable to zoom multiple axes at once
 * [Bug #13597](http://bugzilla.scilab.org/show_bug.cgi?id=13597) fixed - `help format` claimed setting a number of digits instead of characters
 * [Bug #14192](http://bugzilla.scilab.org/show_bug.cgi?id=14192) fixed - `g_margin` error-ed for double integrator.
 * [Bug #14448](http://bugzilla.scilab.org/show_bug.cgi?id=14448) fixed - removed havewindow() was still documented
index f61e21c..7954e62 100644 (file)
@@ -36,6 +36,7 @@ public class DragPointRubberBox extends TwoPointsRubberBox {
     public final void mouseClicked(MouseEvent e) {
 
     }
+
     @Override
     public void mousePressed(MouseEvent e) {
         mouseButton = e.getButton();
@@ -50,7 +51,7 @@ public class DragPointRubberBox extends TwoPointsRubberBox {
                 break;
             case WAIT_POINT_B:
                 setPointB(e.getPoint());
-                if (pointBComputer.is2D()) {
+                if (!valid3D()) {
                     process();
                     setEnable(false);
                     fireRubberBoxEnd();
@@ -70,7 +71,7 @@ public class DragPointRubberBox extends TwoPointsRubberBox {
                 break;
             default:
         }
-        updateInfoMessage();
+        updateInfoMessage(e.getPoint());
     }
 
     @Override
@@ -87,7 +88,7 @@ public class DragPointRubberBox extends TwoPointsRubberBox {
                 break;
             case WAIT_POINT_B:
                 setPointB(e.getPoint());
-                if (pointBComputer.is2D()) {
+                if (!valid3D()) {
                     process();
                     setEnable(false);
                     fireRubberBoxEnd();
@@ -107,7 +108,7 @@ public class DragPointRubberBox extends TwoPointsRubberBox {
                 break;
             default:
         }
-        updateInfoMessage();
+        updateInfoMessage(e.getPoint());
     }
 
     @Override
@@ -131,7 +132,7 @@ public class DragPointRubberBox extends TwoPointsRubberBox {
                 break;
             default:
         }
-        updateInfoMessage();
+        updateInfoMessage(e.getPoint());
     }
 
 
index be72599..6bee346 100644 (file)
@@ -56,7 +56,7 @@ public class DragZoomRotateInteraction extends FigureInteraction {
      * Last important mouse event.
      */
     private MouseEvent previousEvent;
-    private Axes currentAxes;
+    private Axes[] currentAxes;
 
 
     /**
@@ -68,6 +68,7 @@ public class DragZoomRotateInteraction extends FigureInteraction {
         mouseMotionListener = new FigureMouseMotionListener();
         mouseWheelListener = new FigureMouseWheelListener();
         mouseListener = new FigureMouseListener();
+        currentAxes = new Axes[0];
     }
 
     @Override
@@ -102,9 +103,9 @@ public class DragZoomRotateInteraction extends FigureInteraction {
         public void mousePressed(MouseEvent e) {
             if (pressedButtons == 0) {
                 previousEvent = e;
-                if (currentAxes == null) {
-                    currentAxes = getUnderlyingAxes(e.getPoint());
-                    if (currentAxes != null) {
+                if (currentAxes.length == 0) {
+                    currentAxes = getAllUnderlyingAxes(e.getPoint());
+                    if (currentAxes.length > 0) {
                         getDrawerVisitor().getComponent().addMouseMotionListener(mouseMotionListener);
                         switch (e.getButton()) {
                             case MouseEvent.BUTTON1 :
@@ -129,7 +130,7 @@ public class DragZoomRotateInteraction extends FigureInteraction {
 
             if (pressedButtons == 0) {
                 getDrawerVisitor().getComponent().removeMouseMotionListener(mouseMotionListener);
-                currentAxes = null;
+                currentAxes = new Axes[0];
             }
             e.getComponent().setCursor(Cursor.getDefaultCursor());
         }
@@ -140,11 +141,8 @@ public class DragZoomRotateInteraction extends FigureInteraction {
      */
     private class FigureMouseWheelListener implements MouseWheelListener {
 
-        @Override
-        public void mouseWheelMoved(MouseWheelEvent e) {
-            Axes axes = getUnderlyingAxes(e.getPoint());
+        private void applyZoom(Axes axes, double scale) {
             if (axes != null) {
-                double scale = Math.pow(ZOOM_FACTOR, e.getUnitsToScroll());
                 Double[] bounds = axes.getDisplayedBounds();
                 double[][] factors = axes.getScaleTranslateFactors();
 
@@ -184,7 +182,19 @@ public class DragZoomRotateInteraction extends FigureInteraction {
 
                 GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_BOX__, bounds);
                 GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_ENABLED__, zoomed);
-
+            }
+        }
+        @Override
+        public void mouseWheelMoved(MouseWheelEvent e) {
+            Axes[] allAxes;
+            if (e.isControlDown()) {
+                allAxes = getAllVisibleAxes(e.getPoint());
+            } else {
+                allAxes = getAllUnderlyingAxes(e.getPoint());
+            }
+            double scale = Math.pow(ZOOM_FACTOR, e.getUnitsToScroll());
+            for (Axes axes : allAxes) {
+                applyZoom(axes, scale);
             }
         }
     }
@@ -256,11 +266,11 @@ public class DragZoomRotateInteraction extends FigureInteraction {
             int dx = e.getX() - previousEvent.getX();
             int dy = e.getY() - previousEvent.getY();
 
-            if (currentAxes != null) {
-                Double[] angles = currentAxes.getRotationAngles();
+            for (Axes axes : currentAxes) {
+                Double[] angles = axes.getRotationAngles();
                 angles[0] -= dy / 4.0;
                 angles[1] -= Math.signum(Math.sin(Math.toRadians(angles[0]))) * (dx / 4.0);
-                GraphicController.getController().setProperty(currentAxes.getIdentifier(), GraphicObjectProperties.__GO_ROTATION_ANGLES__, angles);
+                GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_ROTATION_ANGLES__, angles);
             }
         }
 
@@ -268,21 +278,21 @@ public class DragZoomRotateInteraction extends FigureInteraction {
             int dx = e.getX() - previousEvent.getX();
             int dy = e.getY() - previousEvent.getY();
 
-            if (currentAxes != null) {
-                if (currentAxes.getZoomEnabled()) {
-                    Double[] bounds = currentAxes.getDisplayedBounds();
+            for (Axes axes : currentAxes) {
+                if (axes.getZoomEnabled()) {
+                    Double[] bounds = axes.getDisplayedBounds();
 
-                    Integer[] winSize = (Integer[]) GraphicController.getController().getProperty(currentAxes.getParent(), GraphicObjectProperties.__GO_AXES_SIZE__);
+                    Integer[] winSize = (Integer[]) GraphicController.getController().getProperty(axes.getParent(), GraphicObjectProperties.__GO_AXES_SIZE__);
                     if (winSize == null) {
                         // We are in a Frame
-                        Double[] position = (Double[]) GraphicController.getController().getProperty(currentAxes.getParent(), GraphicObjectProperties.__GO_POSITION__);
+                        Double[] position = (Double[]) GraphicController.getController().getProperty(axes.getParent(), GraphicObjectProperties.__GO_POSITION__);
                         winSize = new Integer[2];
                         winSize[0] = position[2].intValue();
                         winSize[1] = position[3].intValue();
                     }
-                    Double[] axesBounds = (Double[]) GraphicController.getController().getProperty(currentAxes.getIdentifier(), GraphicObjectProperties.__GO_AXES_BOUNDS__);
-                    Double[] axesMargins = (Double[]) GraphicController.getController().getProperty(currentAxes.getIdentifier(), GraphicObjectProperties.__GO_MARGINS__);
-                    Integer view = (Integer) GraphicController.getController().getProperty(currentAxes.getIdentifier(), GraphicObjectProperties.__GO_VIEW__);
+                    Double[] axesBounds = (Double[]) GraphicController.getController().getProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_AXES_BOUNDS__);
+                    Double[] axesMargins = (Double[]) GraphicController.getController().getProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_MARGINS__);
+                    Integer view = (Integer) GraphicController.getController().getProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_VIEW__);
 
                     // Compute ratio from pixel move to user displayed data bounds
                     double xDelta = Math.abs(bounds[0] - bounds[1]) / (winSize[0] * axesBounds[2] * (1 - axesMargins[0] - axesMargins[1]));
@@ -297,8 +307,8 @@ public class DragZoomRotateInteraction extends FigureInteraction {
                         bounds[3] += yDelta * dy;
                     } else {
                         // 3D view
-                        double orientation = - Math.signum(Math.cos(Math.toRadians(currentAxes.getRotationAngles()[0])));
-                        double angle = - orientation * Math.toRadians(currentAxes.getRotationAngles()[1]);
+                        double orientation = - Math.signum(Math.cos(Math.toRadians(axes.getRotationAngles()[0])));
+                        double angle = - orientation * Math.toRadians(axes.getRotationAngles()[1]);
 
                         double rotatedDX = dx * Math.sin(angle) + dy * Math.cos(angle);
                         double rotatedDY = dx * Math.cos(angle) - dy * Math.sin(angle);
@@ -310,12 +320,12 @@ public class DragZoomRotateInteraction extends FigureInteraction {
                         bounds[3] += yDelta * rotatedDY;
                     }
 
-                    Boolean zoomed = tightZoomBoxToDataBounds(currentAxes, bounds);
-                    boolean[] logFlags = { currentAxes.getXAxisLogFlag(), currentAxes.getYAxisLogFlag(), currentAxes.getZAxisLogFlag()};
+                    Boolean zoomed = tightZoomBoxToDataBounds(axes, bounds);
+                    boolean[] logFlags = { axes.getXAxisLogFlag(), axes.getYAxisLogFlag(), axes.getZAxisLogFlag()};
                     ScaleUtils.applyInverseLogScaleToBounds(bounds, logFlags);
 
-                    GraphicController.getController().setProperty(currentAxes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_BOX__, bounds);
-                    GraphicController.getController().setProperty(currentAxes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_ENABLED__, zoomed);
+                    GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_BOX__, bounds);
+                    GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_ENABLED__, zoomed);
                 }
             }
         }
@@ -323,20 +333,20 @@ public class DragZoomRotateInteraction extends FigureInteraction {
         private void doZTranslation(MouseEvent e) {
             int dy = e.getY() - previousEvent.getY();
 
-            if (currentAxes != null) {
-                Double[] bounds = currentAxes.getDisplayedBounds();
+            for (Axes axes : currentAxes) {
+                Double[] bounds = axes.getDisplayedBounds();
 
                 double zDelta = (bounds[5] - bounds[4]) / 100;
 
                 bounds[4] += zDelta * dy;
                 bounds[5] += zDelta * dy;
 
-                Boolean zoomed = tightZoomBoxToDataBounds(currentAxes, bounds);
-                boolean[] logFlags = { currentAxes.getXAxisLogFlag(), currentAxes.getYAxisLogFlag(), currentAxes.getZAxisLogFlag()};
+                Boolean zoomed = tightZoomBoxToDataBounds(axes, bounds);
+                boolean[] logFlags = { axes.getXAxisLogFlag(), axes.getYAxisLogFlag(), axes.getZAxisLogFlag()};
                 ScaleUtils.applyInverseLogScaleToBounds(bounds, logFlags);
 
-                GraphicController.getController().setProperty(currentAxes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_BOX__, bounds);
-                GraphicController.getController().setProperty(currentAxes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_ENABLED__, zoomed);
+                GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_BOX__, bounds);
+                GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_ENABLED__, zoomed);
             }
         }
 
index 23cfc80..8cc938c 100644 (file)
@@ -21,6 +21,7 @@ import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
 
 import java.awt.Dimension;
 import java.awt.Point;
+import java.util.ArrayList;
 
 /**
  * @author Pierre Lando
@@ -28,7 +29,7 @@ import java.awt.Point;
 public abstract class FigureInteraction {
 
     /** parent figure drawer */
-    private DrawerVisitor drawerVisitor;
+    protected DrawerVisitor drawerVisitor;
 
     /** Enable status */
     private boolean isEnable;
@@ -75,6 +76,55 @@ public abstract class FigureInteraction {
         return underlyingAxes;
     }
 
+    protected Axes[] getAllUnderlyingAxes(Point point) {
+        ArrayList<Axes> underlyingAxes = new ArrayList<Axes>();
+        Dimension size = drawerVisitor.getCanvas().getDimension();
+        double x = point.getX() / size.getWidth();
+        double y = point.getY() / size.getHeight();
+        for (Integer childId : drawerVisitor.getFigure().getChildren()) {
+            GraphicObject child = GraphicController.getController().getObjectFromId(childId);
+            if (child instanceof Axes) {
+                if (child.getVisible()) {
+                    Double[] axesBounds = ((Axes) child).getAxesBounds();  // x y w h
+                    if ((x >= axesBounds[0]) && (x <= axesBounds[0] + axesBounds[2]) && (y >= axesBounds[1]) && (y <= axesBounds[1] + axesBounds[3])) {
+                        underlyingAxes.add((Axes) child);
+                    }
+                }
+            }
+        }
+        Axes [] ret;
+        if (underlyingAxes.size() > 0) {
+            ret = new Axes[underlyingAxes.size()];
+            ret = underlyingAxes.toArray(ret);
+        } else {
+            ret = new Axes[0];
+        }
+        return ret;
+    }
+
+    protected Axes[] getAllVisibleAxes(Point point) {
+        ArrayList<Axes> underlyingAxes = new ArrayList<Axes>();
+        Dimension size = drawerVisitor.getCanvas().getDimension();
+        double x = point.getX() / size.getWidth();
+        double y = point.getY() / size.getHeight();
+        for (Integer childId : drawerVisitor.getFigure().getChildren()) {
+            GraphicObject child = GraphicController.getController().getObjectFromId(childId);
+            if (child instanceof Axes) {
+                if (child.getVisible()) {
+                    underlyingAxes.add((Axes) child);
+                }
+            }
+        }
+        Axes [] ret;
+        if (underlyingAxes.size() > 0) {
+            ret = new Axes[underlyingAxes.size()];
+            ret = underlyingAxes.toArray(ret);
+        } else {
+            ret = new Axes[0];
+        }
+        return ret;
+    }
+
     /**
      * Enable status getter.
      * @return the enable status.
index f3522bd..2f31be9 100644 (file)
@@ -18,6 +18,7 @@ import java.awt.Point;
 import java.awt.event.MouseEvent;
 
 import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.axes.Axes;
 import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
 import org.scilab.modules.renderer.JoGLView.interaction.util.PointAComputer;
 
@@ -37,18 +38,22 @@ public class OnePointRubberBox extends RubberBox implements PointRubberBox {
 
     public OnePointRubberBox(DrawerVisitor drawerVisitor, double initialRect[]) {
         super(drawerVisitor);
-        double[][] factors = axes.getScaleTranslateFactors();
-        firstPoint = new Vector3d(initialRect[0] * factors[0][0] + factors[1][0],
-                                  initialRect[1] * factors[0][1] + factors[1][1],
-                                  0);
-        secondPoint = firstPoint;
         status = Status.WAIT_POINT_B;
         setEnable(true);
+
+        AxesZoom axesZoom = new AxesZoom(drawerVisitor.getAxes());
+        double[][] factors = axesZoom.axes.getScaleTranslateFactors();
+        axesZoom.firstPoint = new Vector3d(initialRect[0] * factors[0][0] + factors[1][0],
+                                           initialRect[1] * factors[0][1] + factors[1][1],
+                                           0);
+        axesZoom.secondPoint = axesZoom.firstPoint;
+        axesZoomList.add(axesZoom);
     }
 
     @Override
     public void mouseClicked(MouseEvent e) {
         mouseButton = e.getButton();
+        lastPoint = e.getPoint();
         setPointB(e.getPoint());
         process();
         setEnable(false);
@@ -61,12 +66,12 @@ public class OnePointRubberBox extends RubberBox implements PointRubberBox {
      * @return true if the first point is valid.
      */
     protected boolean setPointB(Point point) {
-        axes = getUnderlyingAxes(point);
-        if (axes != null) {
-            PointAComputer pointComputer = new PointAComputer(axes, point);
+        AxesZoom axesZoom = getClosestAxesZoom(point);
+        if (axesZoom != null) {
+            PointAComputer pointComputer = new PointAComputer(axesZoom.axes, point);
             if (pointComputer.isValid()) {
-                pointBComputer = pointComputer;
-                secondPoint = pointComputer.getPosition();
+                axesZoom.pointBComputer = pointComputer;
+                axesZoom.secondPoint = pointComputer.getPosition();
                 return true;
             }
         }
index 46838d8..26dca16 100644 (file)
@@ -16,6 +16,7 @@
 package org.scilab.modules.renderer.JoGLView.interaction;
 
 import java.awt.Component;
+import java.awt.Dimension;
 import java.awt.Point;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
@@ -24,6 +25,8 @@ import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
 import java.text.DecimalFormat;
 
+import java.util.ArrayList;
+
 import javax.swing.event.EventListenerList;
 
 import org.scilab.forge.scirenderer.DrawingTools;
@@ -55,6 +58,23 @@ import org.scilab.modules.localization.Messages;
  */
 public class RubberBox extends FigureInteraction implements PostRendered, MouseListener, MouseMotionListener, KeyListener {
 
+    protected class AxesZoom {
+
+        public final Axes axes;
+        public PointComputer pointAComputer;
+        public PointComputer pointBComputer;
+        public PointComputer pointCComputer;
+        public PointComputer pointDComputer;
+        public Vector3d firstPoint;
+        public Vector3d secondPoint;
+
+        public AxesZoom(Axes axes) {
+            this.axes = axes;
+            firstPoint = new Vector3d(0.0, 0.0, 0.0);
+            secondPoint = new Vector3d(0.0, 0.0, 0.0);
+        }
+    };
+
     /** Decimal format used to show info messages */
     private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.###E0");
 
@@ -107,17 +127,12 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
     /** Current status */
     protected Status status;
 
-    protected Axes axes;
-
-    private PointComputer pointAComputer;
-    protected PointComputer pointBComputer;
-    private PointComputer pointCComputer;
-    private PointComputer pointDComputer;
-    protected Vector3d firstPoint;
-    protected Vector3d secondPoint;
+    protected ArrayList<AxesZoom> axesZoomList;
 
     protected int mouseButton;
 
+    protected Point lastPoint;
+
     /**
      * Default constructor.
      *
@@ -125,8 +140,9 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
      */
     protected RubberBox(DrawerVisitor drawerVisitor) {
         super(drawerVisitor);
-        axes = drawerVisitor.getAxes();
         status = Status.WAIT_POINT_A;
+        axesZoomList = new ArrayList<AxesZoom>();
+        lastPoint = null;
     }
 
     /**
@@ -158,21 +174,24 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
 
     @Override
     public final void draw(DrawingTools drawingTools) throws SciRendererException {
-        if (isEnable() && (axes != null)) {
-            drawingTools.getTransformationManager().useSceneCoordinate();
-            drawingTools.getTransformationManager().getModelViewStack().push(
-                getDrawerVisitor().getAxesDrawer().getSceneProjection(axes.getIdentifier())
-            );
 
-            if (status != Status.WAIT_POINT_A) {
-                drawingTools.draw(getCubeGeometry(drawingTools), getCubeAppearance());
-            }
+        if (isEnable()) {
+            for (AxesZoom axesZoom : axesZoomList) {
+                drawingTools.getTransformationManager().useSceneCoordinate();
+                drawingTools.getTransformationManager().getModelViewStack().push(
+                    getDrawerVisitor().getAxesDrawer().getSceneProjection(axesZoom.axes.getIdentifier())
+                );
+
+                if (status != Status.WAIT_POINT_A) {
+                    drawingTools.draw(getCubeGeometry(drawingTools, axesZoom), getCubeAppearance());
+                }
 
-            if (secondPoint != null) {
-                drawingTools.draw(getHelpersGeometry(drawingTools), getHelpersAppearance());
-            }
+                if (axesZoom.secondPoint != null) {
+                    drawingTools.draw(getHelpersGeometry(drawingTools, axesZoom), getHelpersAppearance());
+                }
 
-            drawingTools.getTransformationManager().getModelViewStack().pop();
+                drawingTools.getTransformationManager().getModelViewStack().pop();
+            }
         }
     }
 
@@ -181,7 +200,7 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
         Component component = getDrawerVisitor().getComponent();
         if (isEnable) {
             //status = Status.WAIT_POINT_A;
-            pointAComputer = null;
+            axesZoomList.clear();
             component.addMouseListener(this);
             component.addMouseMotionListener(this);
             component.addKeyListener(this);
@@ -193,7 +212,7 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
             component.removeMouseMotionListener(this);
             component.removeKeyListener(this);
         }
-        updateInfoMessage();
+        updateInfoMessage(null);
         getDrawerVisitor().getCanvas().redraw();
     }
 
@@ -209,6 +228,7 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
     @Override
     public void mouseClicked(MouseEvent e) {
         mouseButton = e.getButton();
+        lastPoint = e.getPoint();
         switch (status) {
             case WAIT_POINT_A:
                 if (setPointA(e.getPoint())) {
@@ -220,7 +240,7 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
                 break;
             case WAIT_POINT_B:
                 setPointB(e.getPoint());
-                if (pointBComputer.is2D()) {
+                if (!valid3D()) {
                     process();
                     setEnable(false);
                     fireRubberBoxEnd();
@@ -240,9 +260,7 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
                 break;
             default:
         }
-        updateInfoMessage();
-
-
+        updateInfoMessage(e.getPoint());
     }
 
     @Override
@@ -266,26 +284,36 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
                 break;
             default:
         }
-        updateInfoMessage();
+        updateInfoMessage(e.getPoint());
     }
 
     /**
      * Update displayed info message.
      */
-    protected void updateInfoMessage() {
+    protected void updateInfoMessage(Point point) {
         if (isEnable()) {
+            Axes axes = null;
+            PointComputer pointAComputer = null, pointBComputer = null, pointCComputer = null, pointDComputer = null;
+            AxesZoom axesZoom = getClosestAxesZoom(point);
+            if (axesZoom != null) {
+                axes = axesZoom.axes;
+                pointAComputer = axesZoom.pointAComputer;
+                pointBComputer = axesZoom.pointBComputer;
+                pointCComputer = axesZoom.pointCComputer;
+                pointDComputer = axesZoom.pointDComputer;
+            }
             switch (status) {
                 case WAIT_POINT_A:
-                    setInfoMessage(Messages.gettext("Click to set first bounds"), pointAComputer, false);
+                    setInfoMessage(Messages.gettext("Click to set first bounds"), axes, pointAComputer, false);
                     break;
                 case WAIT_POINT_B:
-                    setInfoMessage(Messages.gettext("Click to set second bounds"), pointBComputer, false);
+                    setInfoMessage(Messages.gettext("Click to set second bounds"), axes, pointBComputer, false);
                     break;
                 case WAIT_POINT_C:
-                    setInfoMessage(Messages.gettext("Click to set first"), pointCComputer, true);
+                    setInfoMessage(Messages.gettext("Click to set first"), axes, pointCComputer, true);
                     break;
                 case WAIT_POINT_D:
-                    setInfoMessage(Messages.gettext("Click to set second"), pointDComputer, true);
+                    setInfoMessage(Messages.gettext("Click to set second"), axes, pointDComputer, true);
                     break;
                 default:
             }
@@ -301,10 +329,11 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
     /**
      * Set the info message.
      * @param baseMessage the base of the message.
+     * @param axes the axes to get data from.
      * @param pointComputer current used point computer.
      * @param oneAxis true if only one coordinate is currently set.
      */
-    private void setInfoMessage(String baseMessage, PointComputer pointComputer, boolean oneAxis) {
+    private void setInfoMessage(String baseMessage, Axes axes, PointComputer pointComputer, boolean oneAxis) {
         if ((pointComputer != null) && (pointComputer.isValid())) {
             String message = baseMessage + " ";
             double[] data = pointComputer.getSecondPosition().getData();
@@ -355,17 +384,21 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
      * @return true if the first point is valid.
      */
     protected boolean setPointA(Point point) {
-        axes = getUnderlyingAxes(point);
-        if (axes != null) {
+        axesZoomList.clear();
+        boolean status = false;
+        Axes[] allAxes = getAllVisibleAxes(point);
+        for (Axes axes : allAxes) {
+            AxesZoom axesZoom = new AxesZoom(axes);
             PointAComputer pointComputer = new PointAComputer(axes, point);
             if (pointComputer.isValid()) {
-                this.pointAComputer = pointComputer;
-                firstPoint = pointComputer.getPosition();
-                secondPoint = firstPoint;
-                return true;
+                axesZoom.pointAComputer = pointComputer;
+                axesZoom.firstPoint = pointComputer.getPosition();
+                axesZoom.secondPoint = axesZoom.firstPoint;
+                axesZoomList.add(axesZoom);
+                status = true;
             }
         }
-        return false;
+        return status;
     }
 
     /**
@@ -374,16 +407,18 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
      * @return true if the point is valid.
      */
     protected boolean setPointB(Point point) {
-        PointBComputer pointComputer = new PointBComputer(axes, pointAComputer, point);
-        if (pointComputer.isValid()) {
-            this.pointBComputer = pointComputer;
-            firstPoint = pointComputer.getFirstPosition();
-            secondPoint = pointComputer.getSecondPosition();
-            getDrawerVisitor().getCanvas().redraw();
-            return true;
-        } else {
-            return false;
+        boolean status = false;
+        for (AxesZoom axesZoom : axesZoomList) {
+            PointBComputer pointComputer = new PointBComputer(axesZoom.axes, axesZoom.pointAComputer, point);
+            if (pointComputer.isValid()) {
+                axesZoom.pointBComputer = pointComputer;
+                axesZoom.firstPoint = pointComputer.getFirstPosition();
+                axesZoom.secondPoint = pointComputer.getSecondPosition();
+                getDrawerVisitor().getCanvas().redraw();
+                status = true;
+            }
         }
+        return status;
     }
 
     /**
@@ -392,16 +427,20 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
      * @return true if the point is valid.
      */
     protected boolean setPointC(Point point) {
-        PointCComputer pointComputer = new PointCComputer(axes, pointBComputer, point);
-        if (pointComputer.isValid()) {
-            this.pointCComputer = pointComputer;
-            firstPoint = pointComputer.getFirstPosition();
-            secondPoint = pointComputer.getSecondPosition();
-            getDrawerVisitor().getCanvas().redraw();
-            return true;
-        } else {
-            return false;
+        boolean status = false;
+        for (AxesZoom axesZoom : axesZoomList) {
+            if (!axesZoom.pointBComputer.is2D()) {
+                PointCComputer pointComputer = new PointCComputer(axesZoom.axes, axesZoom.pointBComputer, point);
+                if (pointComputer.isValid()) {
+                    axesZoom.pointCComputer = pointComputer;
+                    axesZoom.firstPoint = pointComputer.getFirstPosition();
+                    axesZoom.secondPoint = pointComputer.getSecondPosition();
+                    getDrawerVisitor().getCanvas().redraw();
+                    status = true;
+                }
+            }
         }
+        return status;
     }
 
     /**
@@ -410,28 +449,33 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
      * @return true if the point is valid.
      */
     protected boolean setPointD(Point point) {
-        PointDComputer pointComputer = new PointDComputer(axes, pointCComputer, point);
-        if (pointComputer.isValid()) {
-            this.pointDComputer = pointComputer;
-            firstPoint = pointComputer.getFirstPosition();
-            secondPoint = pointComputer.getSecondPosition();
-            getDrawerVisitor().getCanvas().redraw();
-            return true;
-        } else {
-            return false;
+        boolean status = false;
+        for (AxesZoom axesZoom : axesZoomList) {
+            if (!axesZoom.pointBComputer.is2D()) {
+                PointDComputer pointComputer = new PointDComputer(axesZoom.axes, axesZoom.pointCComputer, point);
+                if (pointComputer.isValid()) {
+                    axesZoom.pointDComputer = pointComputer;
+                    axesZoom.firstPoint = pointComputer.getFirstPosition();
+                    axesZoom.secondPoint = pointComputer.getSecondPosition();
+                    getDrawerVisitor().getCanvas().redraw();
+                    status = true;
+                }
+            }
         }
+        return status;
     }
 
     /**
      * Initialise or update the helpers geometry.
      * @param drawingTools the drawing tools used to draw the helpers.
+     * @param axesZoom the structure containing the axes and points
      * @return updated helpers geometry.
      */
-    private Geometry getHelpersGeometry(DrawingTools drawingTools) {
+    private Geometry getHelpersGeometry(DrawingTools drawingTools, AxesZoom axesZoom) {
         if (helpersGeometry == null) {
             helpersGeometry = new HelpersGeometry(drawingTools);
         }
-        helpersGeometry.updateVertex(axes, pointAComputer, secondPoint, status);
+        helpersGeometry.updateVertex(axesZoom.axes, axesZoom.pointAComputer, axesZoom.secondPoint, status);
         return helpersGeometry;
     }
 
@@ -452,9 +496,10 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
     /**
      * Rubber box cube geometry getter.
      * @param drawingTools the drawing tools.
+     * @param axesZoom the structure containing the axes and points
      * @return the rubber box cubeGeometry.
      */
-    private Geometry getCubeGeometry(DrawingTools drawingTools) {
+    private Geometry getCubeGeometry(DrawingTools drawingTools, AxesZoom axesZoom) {
         if (cubeGeometry == null) {
             cubeGeometry = new DefaultGeometry();
 
@@ -470,14 +515,14 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
         }
 
         cubeGeometry.getVertices().setData(new float[] {
-                                               (float) firstPoint.getX(), (float) firstPoint.getY(), (float) firstPoint.getZ(), 1,
-                                               (float) firstPoint.getX(), (float) firstPoint.getY(), (float) secondPoint.getZ(), 1,
-                                               (float) firstPoint.getX(), (float) secondPoint.getY(), (float) secondPoint.getZ(), 1,
-                                               (float) firstPoint.getX(), (float) secondPoint.getY(), (float) firstPoint.getZ(), 1,
-                                               (float) secondPoint.getX(), (float) firstPoint.getY(), (float) firstPoint.getZ(), 1,
-                                               (float) secondPoint.getX(), (float) firstPoint.getY(), (float) secondPoint.getZ(), 1,
-                                               (float) secondPoint.getX(), (float) secondPoint.getY(), (float) secondPoint.getZ(), 1,
-                                               (float) secondPoint.getX(), (float) secondPoint.getY(), (float) firstPoint.getZ(), 1
+                                               (float) axesZoom.firstPoint.getX(), (float) axesZoom.firstPoint.getY(), (float) axesZoom.firstPoint.getZ(), 1,
+                                               (float) axesZoom.firstPoint.getX(), (float) axesZoom.firstPoint.getY(), (float) axesZoom.secondPoint.getZ(), 1,
+                                               (float) axesZoom.firstPoint.getX(), (float) axesZoom.secondPoint.getY(), (float) axesZoom.secondPoint.getZ(), 1,
+                                               (float) axesZoom.firstPoint.getX(), (float) axesZoom.secondPoint.getY(), (float) axesZoom.firstPoint.getZ(), 1,
+                                               (float) axesZoom.secondPoint.getX(), (float) axesZoom.firstPoint.getY(), (float) axesZoom.firstPoint.getZ(), 1,
+                                               (float) axesZoom.secondPoint.getX(), (float) axesZoom.firstPoint.getY(), (float) axesZoom.secondPoint.getZ(), 1,
+                                               (float) axesZoom.secondPoint.getX(), (float) axesZoom.secondPoint.getY(), (float) axesZoom.secondPoint.getZ(), 1,
+                                               (float) axesZoom.secondPoint.getX(), (float) axesZoom.secondPoint.getY(), (float) axesZoom.firstPoint.getZ(), 1
                                            }, 4);
 
         return cubeGeometry;
@@ -497,6 +542,103 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
         return cubeAppearance;
     }
 
+    /**
+     * Calculates the minimum squared distance from
+     * the given x,y to the given axes bounds.
+     *
+     * @param bounds the axes bounds [x, y, w, h]
+     * @param x the coordinate x
+     * @param y the coordinate y
+     * @return the squared distance
+     **/
+    private double calculateAxesDistance2(Double[] bounds, double x, double y) {
+
+        double x2 = bounds[0] + bounds[2];
+        double y2 = bounds[1] + bounds[3];
+        double x1 = bounds[0];
+        double y1 = bounds[1];
+        boolean xbounded = (x >= x1) && (x <= x2);
+        boolean ybounded = (y >= y1) && (y <= y2);
+
+        if (xbounded && ybounded) {
+            return 0.0;
+        }
+
+        y1 -= y;
+        y2 -= y;
+        y1 *= y1;
+        y2 *= y2;
+        if (xbounded) {
+            return Math.min(y1, y2);
+        }
+
+        x1 -= x;
+        x2 -= x;
+        x1 *= x1;
+        x2 *= x2;
+        if (ybounded) {
+            return Math.min(x1, x2);
+        }
+
+        return Math.min(Math.min(x1 + y1, x1 + y2), Math.min(x2 + y1, x2 + y2));
+    }
+
+    /**
+     * Selects the axesZoom structure containing
+     * the closest axes.
+     *
+     * @param point the point to calculate distance
+     * @return the axesZoom structure
+     **/
+    protected AxesZoom getClosestAxesZoom(Point point) {
+        AxesZoom ret = null;
+        if (point == null) {
+            point = new Point(0, 0);
+        }
+        double minDist2 = Double.MAX_VALUE;
+        Dimension size = drawerVisitor.getCanvas().getDimension();
+        double x = point.getX() / size.getWidth();
+        double y = point.getY() / size.getHeight();
+        for (AxesZoom axesZoom : axesZoomList) {
+
+            Double[] bounds = axesZoom.axes.getAxesBounds();//x, y, w, h
+            double d2 = calculateAxesDistance2(bounds, x, y);
+            if (minDist2 > d2) {
+                ret = axesZoom;
+                minDist2 = d2;
+            }
+        }
+
+        return ret;
+    }
+
+    /**
+     * Check if exists any valid 3d zoom
+     * going on the axesZoomList.
+     *
+     * @return true if exists false otherwise
+     **/
+    protected boolean valid3D() {
+        boolean valid = false;
+        for (AxesZoom axesZoom : axesZoomList) {
+            if (axesZoom.pointBComputer != null && !axesZoom.pointBComputer.is2D()) {
+                Double[] bounds = { axesZoom.firstPoint.getX(), axesZoom.secondPoint.getX(),
+                                    axesZoom.firstPoint.getY(), axesZoom.secondPoint.getY(),
+                                    axesZoom.firstPoint.getZ(), axesZoom.secondPoint.getZ(),
+                                  };
+                int count = 0;
+                count = bounds[0].compareTo(bounds[1]) != 0 ? ++count : count;
+                count = bounds[2].compareTo(bounds[3]) != 0 ? ++count : count;
+                count = bounds[4].compareTo(bounds[5]) != 0 ? ++count : count;
+                //Atleast 2 axis must be different to be a valid zoom selection
+                if (count >= 2) {
+                    valid = true;
+                }
+            }
+        }
+        return valid;
+    }
+
     @Override
     public void mousePressed(MouseEvent e) {
     }
@@ -525,18 +667,28 @@ public class RubberBox extends FigureInteraction implements PostRendered, MouseL
     public void keyReleased(KeyEvent e) {
     }
 
+    /**
+     * Computes the current selection box
+     * using the closest axes coordinates
+     *
+     * @return the selection box
+     **/
     public double[] getResults() {
-        double[][] factors = axes.getScaleTranslateFactors();
-        double result[] = {
-            mouseButton - 1,
-            (Math.min(firstPoint.getX(), secondPoint.getX()) - factors[1][0]) / factors[0][0],
-            (Math.max(firstPoint.getY(), secondPoint.getY()) - factors[1][1]) / factors[0][1],
-            (Math.max(firstPoint.getZ(), secondPoint.getZ()) - factors[1][2]) / factors[0][2],
-            (Math.abs(firstPoint.getX() - secondPoint.getX())) / factors[0][0],
-            (Math.abs(firstPoint.getY() - secondPoint.getY())) / factors[0][1],
-            (Math.abs(firstPoint.getZ() - secondPoint.getZ())) / factors[0][2]
-        };
-
-        return result;
+        AxesZoom axesZoom = getClosestAxesZoom(lastPoint);
+        if (axesZoom != null) {
+            double[][] factors = axesZoom.axes.getScaleTranslateFactors();
+            double result[] = {
+                mouseButton - 1,
+                (Math.min(axesZoom.firstPoint.getX(), axesZoom.secondPoint.getX()) - factors[1][0]) / factors[0][0],
+                (Math.max(axesZoom.firstPoint.getY(), axesZoom.secondPoint.getY()) - factors[1][1]) / factors[0][1],
+                (Math.max(axesZoom.firstPoint.getZ(), axesZoom.secondPoint.getZ()) - factors[1][2]) / factors[0][2],
+                (Math.abs(axesZoom.firstPoint.getX() - axesZoom.secondPoint.getX())) / factors[0][0],
+                (Math.abs(axesZoom.firstPoint.getY() - axesZoom.secondPoint.getY())) / factors[0][1],
+                (Math.abs(axesZoom.firstPoint.getZ() - axesZoom.secondPoint.getZ())) / factors[0][2]
+            };
+            return result;
+        } else {
+            return new double[] {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
+        }
     }
 }
index c2a1f26..4efe12b 100644 (file)
 
 package org.scilab.modules.renderer.JoGLView.interaction;
 
+import java.awt.Point;
+
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.axes.Axes;
 import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
+import org.scilab.modules.renderer.JoGLView.interaction.util.PointAComputer;
+import org.scilab.modules.renderer.JoGLView.interaction.util.PointBComputer;
 
 /**
  * @author Bruno JOFRET
@@ -30,4 +36,27 @@ public class TwoPointsRubberBox extends RubberBox implements PointRubberBox {
         super(drawerVisitor);
     }
 
+    /**
+     * Set the first point.
+     * @param point first point AWT coordinate.
+     * @return true if the first point is valid.
+     */
+    @Override
+    protected boolean setPointA(Point point) {
+        axesZoomList.clear();
+        boolean status = false;
+        Axes axes = getUnderlyingAxes(point);
+        if (axes != null) {
+            AxesZoom axesZoom = new AxesZoom(axes);
+            PointAComputer pointComputer = new PointAComputer(axes, point);
+            if (pointComputer.isValid()) {
+                axesZoom.pointAComputer = pointComputer;
+                axesZoom.firstPoint = pointComputer.getPosition();
+                axesZoom.secondPoint = axesZoom.firstPoint;
+                axesZoomList.add(axesZoom);
+                status = true;
+            }
+        }
+        return status;
+    }
 }
index 1c0df22..aae1be1 100644 (file)
@@ -51,7 +51,7 @@ public class ZoomRubberBox extends RubberBox {
                     break;
                 case WAIT_POINT_B:
                     setPointB(e.getPoint());
-                    if (pointBComputer.is2D()) {
+                    if (!valid3D()) {
                         process();
                         setEnable(false);
                         fireRubberBoxEnd();
@@ -71,7 +71,7 @@ public class ZoomRubberBox extends RubberBox {
                     break;
                 default:
             }
-            updateInfoMessage();
+            updateInfoMessage(e.getPoint());
         }
 
         if (e.getButton() == MouseEvent.BUTTON3) {
@@ -85,28 +85,30 @@ public class ZoomRubberBox extends RubberBox {
      */
     @Override
     protected void process() {
-        Double[] bounds = {
-            Math.min(firstPoint.getX(), secondPoint.getX()), Math.max(firstPoint.getX(), secondPoint.getX()),
-            Math.min(firstPoint.getY(), secondPoint.getY()), Math.max(firstPoint.getY(), secondPoint.getY()),
-            Math.min(firstPoint.getZ(), secondPoint.getZ()), Math.max(firstPoint.getZ(), secondPoint.getZ()),
-        };
+        for (AxesZoom axesZoom : axesZoomList) {
+            Double[] bounds = {
+                Math.min(axesZoom.firstPoint.getX(), axesZoom.secondPoint.getX()), Math.max(axesZoom.firstPoint.getX(), axesZoom.secondPoint.getX()),
+                Math.min(axesZoom.firstPoint.getY(), axesZoom.secondPoint.getY()), Math.max(axesZoom.firstPoint.getY(), axesZoom.secondPoint.getY()),
+                Math.min(axesZoom.firstPoint.getZ(), axesZoom.secondPoint.getZ()), Math.max(axesZoom.firstPoint.getZ(), axesZoom.secondPoint.getZ()),
+            };
 
-        if (bounds[0].compareTo(bounds[1]) != 0 && bounds[2].compareTo(bounds[3]) != 0 && bounds[4].compareTo(bounds[5]) != 0) {
-            Boolean zoomed = tightZoomBounds(axes, bounds);
-            double[][] factors = axes.getScaleTranslateFactors();
-            bounds[0] = (bounds[0] - factors[1][0]) / factors[0][0];
-            bounds[1] = (bounds[1] - factors[1][0]) / factors[0][0];
-            bounds[2] = (bounds[2] - factors[1][1]) / factors[0][1];
-            bounds[3] = (bounds[3] - factors[1][1]) / factors[0][1];
-            bounds[4] = (bounds[4] - factors[1][2]) / factors[0][2];
-            bounds[5] = (bounds[5] - factors[1][2]) / factors[0][2];
+            if (bounds[0].compareTo(bounds[1]) != 0 && bounds[2].compareTo(bounds[3]) != 0 && bounds[4].compareTo(bounds[5]) != 0) {
+                Boolean zoomed = tightZoomBounds(axesZoom.axes, bounds);
+                double[][] factors = axesZoom.axes.getScaleTranslateFactors();
+                bounds[0] = (bounds[0] - factors[1][0]) / factors[0][0];
+                bounds[1] = (bounds[1] - factors[1][0]) / factors[0][0];
+                bounds[2] = (bounds[2] - factors[1][1]) / factors[0][1];
+                bounds[3] = (bounds[3] - factors[1][1]) / factors[0][1];
+                bounds[4] = (bounds[4] - factors[1][2]) / factors[0][2];
+                bounds[5] = (bounds[5] - factors[1][2]) / factors[0][2];
 
-            boolean[] logFlags = { axes.getXAxisLogFlag(), axes.getYAxisLogFlag(), axes.getZAxisLogFlag()};
-            ScaleUtils.applyInverseLogScaleToBounds(bounds, logFlags);
+                boolean[] logFlags = { axesZoom.axes.getXAxisLogFlag(), axesZoom.axes.getYAxisLogFlag(), axesZoom.axes.getZAxisLogFlag()};
+                ScaleUtils.applyInverseLogScaleToBounds(bounds, logFlags);
 
-            GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_BOX__, bounds);
-            GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_ENABLED__, zoomed);
-            getDrawerVisitor().getCanvas().redraw();
+                GraphicController.getController().setProperty(axesZoom.axes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_BOX__, bounds);
+                GraphicController.getController().setProperty(axesZoom.axes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_ENABLED__, zoomed);
+                getDrawerVisitor().getCanvas().redraw();
+            }
         }
     }
 }
index 23d52da..1b33f33 100644 (file)
@@ -102,6 +102,24 @@ public abstract class AbstractPointComputer implements PointComputer {
     }
 
     /**
+     * Check if the given vector has valid components
+     * not NaN and not Inf.
+     *
+     * @param v the 3d vector
+     * @return true if all components are valid, false otherwise
+     */
+    protected final boolean isValid(Vector3d v) {
+        double[] data = v.getData();
+        for (int i = 0; i < AXIS_NUMBER; i++) {
+            if (Double.isNaN(data[i]) || Double.isInfinite(data[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+
+    /**
      * Check if the given position feet axes bounds.
      * @param position the given position.
      * @return true if it feet.
index 245d9c5..26b70dc 100644 (file)
@@ -30,6 +30,8 @@ public abstract class CubeFacesPointComputer extends AbstractPointComputer {
     /** First axis index */
     private final int axisIndex;
 
+    private static final double threshold = 0.05;
+
     /**
      * Constructor.
      *
@@ -43,10 +45,19 @@ public abstract class CubeFacesPointComputer extends AbstractPointComputer {
         double maxLambda = -Double.MAX_VALUE;
         Vector3d returnedValue = null;
 
+        Vector3d lastValidClamppedValue = null;
+        double lasValidMinLambda = Double.MAX_VALUE;
+        int lastValidIndex = -1;
+
         int index = -1;
 
         // axis represent X, Y and Z axis.
         for (int axis = 0; axis < AXIS_NUMBER; axis++) {
+
+            double lastBoundLambda = -Double.MAX_VALUE;
+            int lastBoundIndex = -1;
+            Vector3d lastBoundClamppedValue = null;
+
             for (int boundIndex = 0; boundIndex < 2; boundIndex++) {
                 double bound = bounds[axis * 2 + boundIndex];
                 double lambda = computeLambda(bound, axis);
@@ -56,14 +67,64 @@ public abstract class CubeFacesPointComputer extends AbstractPointComputer {
                         maxLambda = lambda;
                         returnedValue = v;
                         index = axis;
+                    } else if (isValid(v) && lambda > lastBoundLambda) {
+                        lastBoundLambda = lambda;
+                        lastBoundClamppedValue = clamp(v);
+                        lastBoundIndex = axis;
                     }
                 }
             }
+            if (lasValidMinLambda > lastBoundLambda || check2D()) {
+                lasValidMinLambda = lastBoundLambda;
+                lastValidIndex = lastBoundIndex;
+                lastValidClamppedValue = lastBoundClamppedValue;
+            }
         }
 
-        this.axisIndex = index;
+        if (returnedValue != null) {
+            this.axisIndex = index;
+            position = check2D() ? returnedValue : applyThreshold(returnedValue);
+        } else {
+            this.axisIndex = lastValidIndex;
+            position = check2D() ? lastValidClamppedValue : applyThreshold(lastValidClamppedValue);
+        }
+    }
 
-        position = returnedValue;
+    /**
+     * Checks whether the computated lambdas
+     * are from a 2d axes view or not.
+     *
+     * @return true if 2d view, false otherwise.
+     **/
+    private boolean check2D() {
+        int r = 0;
+        Double[] bounds = getAxes().getDataBounds();
+        float[] middle = new float[] {
+            (float) (bounds[0] + bounds[1]) / 2f,
+            (float) (bounds[2] + bounds[3]) / 2f,
+            (float) (bounds[4] + bounds[5]) / 2f
+        };
+
+        for (int i = 0; i < AXIS_NUMBER; i++) {
+            double lambda = computeLambda(middle[i], i);
+            r = !((lambda >= 0) && (lambda <= 1)) ? r + 1 : r;
+        }
+        return (r >= 2);
+    }
+
+    /**
+     * Checks if the components of the given vector are
+     * too close to -1.0 or 1.0 and rounds it according.
+     *
+     * @param v the 3d vector with components [-1.0 , 1.0]
+     * @return 3d vector
+     **/
+    private Vector3d applyThreshold(Vector3d v) {
+        double[] data = v.getData();
+        data[0] =  data[0] < 0.0 ? ((data[0] - threshold) < -1.0 ? -1.0 : data[0]) : ((data[0] + threshold) > 1.0 ? 1.0 : data[0]);
+        data[1] =  data[1] < 0.0 ? ((data[1] - threshold) < -1.0 ? -1.0 : data[1]) : ((data[1] + threshold) > 1.0 ? 1.0 : data[1]);
+        data[2] =  data[2] < 0.0 ? ((data[2] - threshold) < -1.0 ? -1.0 : data[2]) : ((data[2] + threshold) > 1.0 ? 1.0 : data[2]);
+        return new Vector3d(data);
     }
 
     /**