Add interactive zoom_rect.
Jean-baptiste Silvy [Mon, 7 Apr 2008 15:35:51 +0000 (15:35 +0000)]
15 files changed:
scilab/modules/graphics/includes/axesScale.h
scilab/modules/graphics/includes/math_graphics.h
scilab/modules/graphics/sci_gateway/c/sci_unzoom.c
scilab/modules/graphics/sci_gateway/c/sci_zoom_rect.c
scilab/modules/graphics/src/c/axesScale.c
scilab/modules/graphics/src/c/getHandleProperty/getPropertyAssignedValue.c
scilab/modules/graphics/src/c/getHandleProperty/getPropertyAssignedValue.h
scilab/modules/graphics/src/c/getHandleProperty/set_zoom_box_property.c
scilab/modules/graphics/src/c/math_graphics.c
scilab/modules/renderer/graphics_Import.def
scilab/modules/renderer/includes/SetJavaProperty.h
scilab/modules/renderer/src/cpp/SetJavaProperty.cpp
scilab/modules/renderer/src/cpp/subwinDrawing/Camera.cpp
scilab/modules/renderer/src/cpp/subwinDrawing/Camera.h
scilab/modules/renderer/src/java/org/scilab/modules/renderer/subwinDrawing/TicksDrawerGL.java

index 9b9c278..7b5c732 100644 (file)
@@ -39,8 +39,10 @@ int trans3d( sciPointObj * pobj,
 int sciZoom2D(sciPointObj * pObj, const double zoomRect[4]);
 int sciZoom3D(sciPointObj * pObj, const double zoomBox[6]);
 void sciGetZoom3D(sciPointObj * pObj, double zoomBox[6]);
-void sciZoomRect(sciPointObj * pObj, int posX, int posY, int width, int height);
-void sciUnzoom(sciPointObj * subwins[], int nbSubwins);
+void sciZoomRect(void);
+void sciUnzoom(sciPointObj * subwin);
+void sciUnzoomAll(void);
+void sciUnzoomArray(unsigned long * subwinHandles, int nbSubwin);
 /*------------------------------------------------------------------------------*/
 BOOL checkDataBounds(sciPointObj * pObj, double xMin, double xMax,
                      double yMin, double yMax, double zMin, double zMax);
index 4be83da..eac0f85 100644 (file)
@@ -186,13 +186,19 @@ void crossProduct( const double v1[3], const double v2[3], double res[3] ) ;
  * substraction of two vector
  * @param res result of v1 - v2
  */
-void vectSubstract3D( double v1[3], double v2[3], double res[3]);
+void vectSubstract3D(const double v1[3], const double v2[3], double res[3]);
+
+/**
+ * substraction of two vector
+ * @param res result of v1 + v2
+ */
+void vectAdd3D(const double v1[3], const double v2[3], double res[3]);
 
 /**
  * Multiply a vector by a scalar
  * @param res scalar.v
  */
-void scalarMult3D( double v[3], double scalar, double res[3]);
+void scalarMult3D(const double v[3], const double scalar, double res[3]);
 
 /**
  * Normalize a 3D vector
index b801b04..10ce0ac 100644 (file)
 /*--------------------------------------------------------------------------*/
 int sci_unzoom(char *fname,unsigned long fname_len)
 {
-  sciPointObj ** unzoomedSubwins = NULL;
-  int nbUnzoomedSubwins = 0;
   CheckRhs(0,1) ;
   CheckLhs(0,1) ;
   if ( Rhs == 0 )
   {
-    sciPointObj * curSubwin = sciGetCurrentSubWin();
-    unzoomedSubwins = &curSubwin;
-    nbUnzoomedSubwins = 1;
+    sciUnzoomAll();
   }
   else
   {
+    int nbUnzoomedSubwins = 0;
     int m,n,i;
     int stackPointer;
+    unsigned long * subwinHandles = NULL;
     GetRhsVar(1,GRAPHICAL_HANDLE_DATATYPE,&m,&n,&stackPointer);
     
     nbUnzoomedSubwins = m * n;
+    subwinHandles = getHandleVectorFromStack(stackPointer);
 
-    unzoomedSubwins = MALLOC( nbUnzoomedSubwins * sizeof(sciPointObj *));
-    
-    if (unzoomedSubwins == NULL)
-    {
-      sciprint(_("%s: no more memory.\n"),fname);
-      LhsVar(1)=0; 
-      return 0;
-    }
-
+    /* first pass, check that all the handles are subwindows */
     for ( i = 0 ; i < nbUnzoomedSubwins ; i++ )
     {
-      unzoomedSubwins[i] = sciGetPointerFromHandle(getHandleFromStack(stackPointer + i));
-      if (sciGetEntityType(unzoomedSubwins[i]) != SCI_SUBWIN)
+      sciPointObj * curSubwin = sciGetPointerFromHandle(subwinHandles[i]);
+      if (sciGetEntityType(curSubwin) != SCI_SUBWIN)
       {
-        sciprint(_("%s: Wrong type for input argument: vector of axes handles expected.\n"),fname);
-        FREE(unzoomedSubwins);
+        sciprint(_("%s: Wrong type for input argument: vector of Axes handles expected.\n"),fname);
         LhsVar(1)=0; 
         return 0;
       }
-      //sciSetZooming(sciGetPointerFromHandle(getHandleFromStack(stackPointer + i)), FALSE); /** Correction Bug 1476 + Warning Windows **/
     }
-    
-    
-
-  }
 
-  sciUnzoom(unzoomedSubwins, nbUnzoomedSubwins);
+    sciUnzoomArray(subwinHandles, nbUnzoomedSubwins);
 
-  if (Rhs != 0) 
-  {
-    FREE(unzoomedSubwins);
   }
   
 
index 0776bc5..18149a8 100644 (file)
@@ -27,6 +27,7 @@
 #include "DrawingBridge.h"
 #include "CurrentObjectsManagement.h"
 #include "GraphicSynchronizerInterface.h"
+#include "Interaction.h"
 
 /*--------------------------------------------------------------------------*/
 int sci_zoom_rect(char *fname,unsigned long fname_len)
@@ -37,7 +38,7 @@ int sci_zoom_rect(char *fname,unsigned long fname_len)
   CheckLhs(0,1) ;
   if (Rhs <= 0) 
   {
-    zoom();
+    sciZoomRect();
   }
   else
   {
@@ -48,15 +49,12 @@ int sci_zoom_rect(char *fname,unsigned long fname_len)
 
     GetRhsVar(1,MATRIX_OF_DOUBLE_DATATYPE,&m,&n,&stackPointer); 
     CheckLength(1,4,m*n);
-    /*sciZoom2D(sciGetCurrentSubWin(), getDoubleMatrixFromStack(stackPointer));*/
-    rectData = getDoubleMatrixFromStack(stackPointer);
-    
+
     curFigure = sciGetCurrentFigure();
     curSubWin = sciGetCurrentSubWin();
 
     startFigureDataWriting(curFigure);
-    sciZoomRect(curSubWin, (int) rectData[0], (int) rectData[1],
-                (int) rectData[2], (int) rectData[3]);
+    sciZoom2D(sciGetCurrentSubWin(), getDoubleMatrixFromStack(stackPointer));
     endFigureDataWriting(curFigure);
 
     sciDrawObj(curSubWin);
index 42befbc..cd3a17a 100644 (file)
 #include "GraphicSynchronizerInterface.h"
 #include "DrawingBridge.h"
 #include "CurrentObjectsManagement.h"
+#include "Interaction.h"
+#include "DoublyLinkedList.h"
 
 /*------------------------------------------------------------------------------*/
+void zoomSubwin(sciPointObj * pSubwin, int posX, int posY, int width, int height);
+void zoomFigure(sciPointObj * pFigure, int posX, int posY, int width, int height);
+/*------------------------------------------------------------------------------*/
 double InvAxis( double min, double max, double u )
 {
   /*return (u-min) / (max-min) * min + (u-max) / (min-max) * max ;*/
@@ -421,12 +426,74 @@ void sciGetZoom3D(sciPointObj * pObj, double zoomBox[6])
 }
 /*------------------------------------------------------------------------------*/
 /**
- *  Zoom on a subwidow using a rectangle specified by user in pixels
+ * Try to zoom on a single subwindow using a selection area
  */
-void sciZoomRect(sciPointObj * pObj, int posX, int posY, int width, int height)
+void zoomSubwin(sciPointObj * pSubwin, int posX, int posY, int width, int height)
 {
-  sciJavaZoomRect(pObj, posX, posY, width, height);
-  sciSetZooming(pObj, TRUE);
+  if (sciJavaZoomRect(pSubwin, posX, posY, width, height))
+  {
+    /* subwindow has been zoomed */
+    /* force zooming */
+    sciSetZooming(pSubwin, TRUE);
+
+    // window has changed
+    forceRedraw(pSubwin);
+  }
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * Zoom a figure using an already computed selection area
+ */
+void zoomFigure(sciPointObj * pFigure, int posX, int posY, int width, int height)
+{
+  /* try to zoom on all the subwindows */
+  sciSons * pSons = sciGetSons(pFigure);
+  while (pSons != NULL)
+  {
+    sciPointObj * curObj = pSons->pointobj;
+    if (sciGetEntityType(curObj) == SCI_SUBWIN)
+    {
+      zoomSubwin(curObj, posX, posY, width, height);
+    }
+    pSons = pSons->pnext;
+  }
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * Perform a zoom rect (rectangular selection + zoom) on the current figure
+ */
+void sciZoomRect(void)
+{
+  int selectionRectangleCorners[4];
+  int x;
+  int y;
+  int w;
+  int h;
+  int button;
+  sciPointObj * curFigure;
+  sciPointObj * curSubWin;
+
+  startGraphicDataWriting();
+  curFigure = sciGetCurrentFigure();
+  curSubWin = sciGetCurrentSubWin();
+  endGraphicDataWriting();
+
+  /* create a ruuber box to select a rectangular area */
+  pixelRubberBox(curFigure, TRUE, NULL, selectionRectangleCorners, &button);
+
+  /* convert found data to [x,y,w,h] */
+  x = Min(selectionRectangleCorners[0], selectionRectangleCorners[2]);
+  y = Min(selectionRectangleCorners[1], selectionRectangleCorners[3]);
+  w = Abs(selectionRectangleCorners[0] - selectionRectangleCorners[2]);
+  h = Abs(selectionRectangleCorners[1] - selectionRectangleCorners[3]); 
+
+  /* Zoom using the found pixels */
+  startFigureDataWriting(curFigure);
+  zoomFigure(curFigure, x, y, w, h);
+  endFigureDataWriting(curFigure);
+
+  /* redraw */
+  sciDrawObj(curFigure);
 }
 /*------------------------------------------------------------------------------*/
 /**
@@ -471,18 +538,79 @@ BOOL checkDataBounds(sciPointObj * pObj, double xMin, double xMax,
 }
 /*------------------------------------------------------------------------------*/
 /**
- * Unzoom several subwindows in the same time
+ * Unzoom a single subwindow
+ */
+void sciUnzoom(sciPointObj * subwin)
+{
+  int currentStatus;
+  sciPointObj * parentFig = sciGetParentFigure(subwin);
+  startFigureDataWriting(parentFig);
+  currentStatus = sciSetZooming(subwin, FALSE);
+  endFigureDataWriting(parentFig);
+
+  if (currentStatus == 0)
+  {
+    /* redraw only if needed */
+    forceRedraw(subwin);
+  }
+
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * Un zoom all the subwindow of a figure
  */
-void sciUnzoom(sciPointObj * subwins[], int nbSubwins)
+void sciUnzoomAll(void)
+{
+  sciPointObj * pFigure = NULL;
+  sciSons * pSons = NULL;
+
+  startGraphicDataWriting();
+  pFigure = sciGetCurrentFigure();
+  endGraphicDataWriting();
+
+  /* Copy subwins into the array */ 
+  pSons = sciGetSons(pFigure);
+  while (pSons != NULL)
+  {
+    sciPointObj * curObj = pSons->pointobj;
+    if (sciGetEntityType(curObj) == SCI_SUBWIN)
+    {
+      sciUnzoom(curObj);
+    }
+    pSons = pSons->pnext;
+  }
+
+  sciDrawObj(pFigure);
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * Unzoom a set of subwindows given by their handles
+ */
+void sciUnzoomArray(unsigned long * subwinHandles, int nbSubwin)
 {
   int i;
-  for (i = 0; i < nbSubwins; i++)
+  /* list of parent figure to redraw */
+  DoublyLinkedList * redrawnFigures = DoublyLinkedList_new();
+  for (i = 0; i < nbSubwin; i++)
   {
-    sciPointObj * parentFig = sciGetParentFigure(subwins[i]);
-    startFigureDataWriting(parentFig);
-    sciSetZooming(subwins[i], FALSE);
-    endFigureDataWriting(parentFig);
-    sciDrawObj(subwins[i]);
+    sciPointObj * curSubwin = sciGetPointerFromHandle(subwinHandles[i]);
+    sciPointObj * parentFigure = sciGetParentFigure(curSubwin);
+    sciUnzoom(curSubwin);
+    if (List_find(redrawnFigures, parentFigure) == NULL)
+    {
+      /* figure not already added for redraw */
+      redrawnFigures = List_push(redrawnFigures, parentFigure);
+    }
   }
+
+  /* redraw only needed figures */
+  while (!List_is_empty(redrawnFigures))
+  {
+    sciPointObj * curFigure = NULL;
+    redrawnFigures = List_pop(redrawnFigures, &curFigure);
+    sciDrawObj(curFigure);
+  }
+
+  List_free(redrawnFigures);
 }
 /*------------------------------------------------------------------------------*/
index f3d5eca..7107282 100644 (file)
@@ -132,6 +132,11 @@ unsigned long getHandleFromStack( int stackPointer )
   return (unsigned long) *(hstk( stackPointer )) ;
 }
 /*--------------------------------------------------------------------------*/
+unsigned long * getHandleVectorFromStack(int stackPointer)
+{
+  return (unsigned long *) hstk(stackPointer);
+}
+/*--------------------------------------------------------------------------*/
 BOOL isStringParamEqual( int stackPointer, const char * str )
 {
   if ( strcmp( getStringFromStack( stackPointer ), str ) == 0 )
index 70ded0c..d382696 100644 (file)
@@ -89,11 +89,17 @@ char ** getStringMatrixFromStack( int stackPointer ) ;
 char ** createCopyStringMatrixFromStack( int stackPointer, int nbElement ) ;
 
 /**
- * retrieve a string on from the Scilab stack
+ * retrieve a handle on from the Scilab stack
  */
 unsigned long getHandleFromStack( int stackPointer ) ;
 
 /**
+ * Retreive an array of handle from the stack
+ */
+unsigned long * getHandleVectorFromStack(int stackPointer);
+
+
+/**
  * compare the string stored in the stack with str
  * @return TRUE is the string are equal (using strcmp)
  *         FALSE otherwise
index 0448c59..0f7daf1 100644 (file)
@@ -54,7 +54,7 @@ int set_zoom_box_property( sciPointObj * pobj, int stackPointer, int valueType,
   }
   else if ( nbCol * nbRow == 0 )
   {
-    sciUnzoom(&pobj, 1);
+    sciUnzoom(pobj);
   }
   else
   {
index 1c9ae26..fa54ee9 100644 (file)
@@ -165,14 +165,21 @@ void crossProduct( const double v1[3], const double v2[3], double res[3] )
   res[2] = v10 * v21 - v11 * v20 ;
 }
 /*----------------------------------------------------------------------------*/
-void vectSubstract3D( double v1[3], double v2[3], double res[3])
+void vectSubstract3D(const double v1[3] ,const double v2[3], double res[3])
 {
   res[0] = v1[0] - v2[0];
   res[1] = v1[1] - v2[1];
   res[2] = v1[2] - v2[2];
 }
 /*----------------------------------------------------------------------------*/
-void scalarMult3D( double v[3], double scalar, double res[3])
+void vectAdd3D(const double v1[3], const double v2[3], double res[3])
+{
+  res[0] = v1[0] + v2[0];
+  res[1] = v1[1] + v2[1];
+  res[2] = v1[2] + v2[2];
+}
+/*----------------------------------------------------------------------------*/
+void scalarMult3D(const double v[3], const double scalar, double res[3])
 {
   res[0] = scalar * v[0];
   res[1] = scalar * v[1];
index b0892d6..8847bc6 100644 (file)
@@ -134,3 +134,7 @@ sciGetIsAutoDrawable
 sciSetXorMode
 getPixelModeIndex
 sciGetTextBoundingBox
+vectAdd3D
+scalarMult3D
+vectSubstract3D
+sciSetZooming
index 98ce635..17d1181 100644 (file)
@@ -63,8 +63,9 @@ void sciSetJavaRenderingEnable(sciPointObj * pFigure, BOOL isEnable);
 
 /**
  * Zoom a subwin object with the specified rectangle in pixels
+ * @return TRUE if the axes box has been zoomed, FALSE otherwise
  */
-void sciJavaZoomRect(sciPointObj * pSubwin, int posX, int posY, int width, int height);
+ BOOL sciJavaZoomRect(sciPointObj * pSubwin, int posX, int posY, int width, int height);
 
 /**
  * Set the auto_resize mode of a figure
index da2c00f..bc81460 100644 (file)
@@ -54,9 +54,16 @@ void sciSetJavaRenderingEnable(sciPointObj * pFigure, BOOL isEnable)
   getFigureDrawer(pFigure)->setRenderingEnable(isEnable == TRUE);
 }
 /*---------------------------------------------------------------------------------*/
-void sciJavaZoomRect(sciPointObj * pSubwin, int posX, int posY, int width, int height)
+BOOL sciJavaZoomRect(sciPointObj * pSubwin, int posX, int posY, int width, int height)
 {
-  getSubwinDrawer(pSubwin)->getCamera()->zoomRect(posX, posY, width, height);
+  if (getSubwinDrawer(pSubwin)->getCamera()->zoomRect(posX, posY, width, height))
+  {
+    return TRUE;
+  }
+  else
+  {
+    return FALSE;
+  }
 }
 /*---------------------------------------------------------------------------------*/
 void sciSetJavaAutoResizeMode(sciPointObj * pFigure, BOOL resizeMode)
index a6afd4f..3ed7468 100644 (file)
@@ -181,116 +181,385 @@ void Camera::show( void )
   endDrawing();
 }
 /*------------------------------------------------------------------------------------------*/
-void Camera::zoomRect(int posX, int posY, int width, int height)
+bool Camera::zoomRect(int posX, int posY, int width, int height)
 {
   double rectCorners[4][2] = {{posX        , posY + height},
                               {posX        , posY         },
                               {posX + width, posY         },
                               {posX + width, posY + height}};
 
-  zoomRect(rectCorners);
+  return zoomRect(rectCorners);
 
 }
 /*------------------------------------------------------------------------------------------*/
-void Camera::zoomRect(const double corners[4][2])
+bool Camera::zoomRect(const double corners[4][2])
 {
 
+  // the aim of thi salgorithm is to perform zomming inside a 3D axes
+  // knowing a rectangle in pixels
+  // In 3d the selection rectangle can be extended as a infinite
+  // tube with a rectangular section aligned with view
+  // Ideally, the viewing area after the zoom should be the intersection
+  // of the selection volume and the axes box.
+  // However, in Scilab the axes box always remains a box.
+  // Consequently to perform a zoom, we compute the extreme bounds of the intersection
+  // in the 3 directions and use them as new bounds for the axes box.
+
   double oldDataBounds[6];
-  double newDataBounds[6];
 
+  // get data bounds, already scaled
   sciGetRealDataBounds(m_pDrawed, oldDataBounds);
+  // first step compute the 4 lines composing the selection area
+  // in 3d coordinates
+  // the selection area is an infinite cone (tube)
+  // of rectangular section.
+  double selectionLines[4][2][3]; // contains 4 lines which are actually 2 points
+  computeZoomAreaLines(corners, selectionLines);
+
   
-  // x axis
 
-  // (xmin, ymin zmin)
-  double xAxisBound1[3] = {oldDataBounds[0], oldDataBounds[2], oldDataBounds[4]};
-  // (xmax, ymin zmin)
-  double xAxisBound2[3] = {oldDataBounds[1], oldDataBounds[2], oldDataBounds[4]};
+  // second step project lines on each of the 6 axes cube plane
+  // actually we just need the found the bounds of the intersection of
+  // the selectionArea and the axes cube. And the bounds are found on the cube.
+  // So we just need to focus on the 6 faces of the cube
+
+  // set initial bounds
+  // set the otherbound since we wants to found minima
+  // and maxima
+  double oldXmin = oldDataBounds[0];
+  double oldXmax = oldDataBounds[1];
+  double oldYmin = oldDataBounds[2];
+  double oldYmax = oldDataBounds[3];
+  double oldZmin = oldDataBounds[4];
+  double oldZmax = oldDataBounds[5];
+
+  double newXmin = oldDataBounds[1]; // oldXmax
+  double newXmax = oldDataBounds[0]; // oldXmin
+  double newYmin = oldDataBounds[3]; // oldYmax
+  double newYmax = oldDataBounds[2]; // oldYmin
+  double newZmin = oldDataBounds[5]; // oldZMax
+  double newZmax = oldDataBounds[4]; // oldZmin
+
+  // the four intersections with one plane
+  double intersections[4][3];
+
+  // intersection with x = Xmin axis
+  if (   getXaxisIntersections(selectionLines, oldXmin, intersections)
+      && checkXIntersections(intersections, oldYmin, oldYmax, oldZmin, oldZmax))
+  {
+    // ok we found points and the selection intersect the side of the cube
+    // update Y and Z coordinates
+    // don't try to update X here, it's just xMin
+    updateYCoordinate(intersections, oldYmin, oldYmax, newYmin, newYmax);
+    updateZCoordinate(intersections, oldZmin, oldZmax, newZmin, newZmax);
 
-  getNewBounds(corners, xAxisBound1, xAxisBound2, oldDataBounds[0], oldDataBounds[1],
-               &(newDataBounds[0]), &(newDataBounds[1]));
+    newXmin = oldXmin;
+  }
 
 
-  // y axis
+  // same with x = Xmax axis
+  if (   getXaxisIntersections(selectionLines, oldXmax, intersections)
+      && checkXIntersections(intersections, oldYmin, oldYmax, oldZmin, oldZmax))
+  {
+    updateYCoordinate(intersections, oldYmin, oldYmax, newYmin, newYmax);
+    updateZCoordinate(intersections, oldZmin, oldZmax, newZmin, newZmax);
 
-  // (xmin, ymin zmin)
-  double yAxisBound1[3] = {oldDataBounds[0], oldDataBounds[2], oldDataBounds[4]};
-  // (xmin, ymax zmin)
-  double yAxisBound2[3] = {oldDataBounds[0], oldDataBounds[3], oldDataBounds[4]};
+    newXmax = newXmax;
+  }
 
-  getNewBounds(corners, yAxisBound1, yAxisBound2, oldDataBounds[2], oldDataBounds[3],
-              &(newDataBounds[2]), &(newDataBounds[3]));
+  // same with y = Ymin axis
+  if (   getYaxisIntersections(selectionLines, oldYmin, intersections)
+      && checkYIntersections(intersections, oldXmin, oldXmax, oldZmin, oldZmax))
+  {
+    updateXCoordinate(intersections, oldXmin, oldXmax, newXmin, newXmax);
+    updateZCoordinate(intersections, oldZmin, oldZmax, newZmin, newZmax);
 
-  // z axis
+    newYmin = oldYmin;
+  }
+
+  // same with y = Ymax axis
+  if (   getYaxisIntersections(selectionLines, oldYmax, intersections)
+      && checkYIntersections(intersections, oldXmin, oldXmax, oldZmin, oldZmax))
+  {
+    updateXCoordinate(intersections, oldXmin, oldXmax, newXmin, newXmax);
+    updateZCoordinate(intersections, oldZmin, oldZmax, newZmin, newZmax);
 
-  // (xmin, ymin zmin)
-  double zAxisBound1[3] = {oldDataBounds[0], oldDataBounds[2], oldDataBounds[4]};
-  // (xmin, ymin zmax)
-  double zAxisBound2[3] = {oldDataBounds[0], oldDataBounds[2], oldDataBounds[5]};
+    newYmax = oldYmax;
+  }
 
-  getNewBounds(corners, zAxisBound1, zAxisBound2, oldDataBounds[4], oldDataBounds[5],
-               &(newDataBounds[4]), &(newDataBounds[5]));
+  // same with z = Zmin axis
+  if (   getZaxisIntersections(selectionLines, oldZmin, intersections)
+      && checkZIntersections(intersections, oldXmin, oldXmax, oldYmin, oldYmax))
+  {
+    updateXCoordinate(intersections, oldXmin, oldXmax, newXmin, newXmax);
+    updateYCoordinate(intersections, oldYmin, oldYmax, newYmin, newYmax);
+
+    newZmin = oldZmin;
+  }
+
+  // same with z = Zmax axis
+  if (   getZaxisIntersections(selectionLines, oldZmax, intersections)
+      && checkZIntersections(intersections, oldXmin, oldXmax, oldYmin, oldYmax))
+  {
+    updateXCoordinate(intersections, oldXmin, oldXmax, newXmin, newXmax);
+    updateYCoordinate(intersections, oldYmin, oldYmax, newYmin, newYmax);
+
+    newZmax = oldZmax;
+  }
+
+  // check that the view was not outside
+  // that would mean that the newBounds were not updated
+  if (newXmin >= newXmax && newYmin >= newYmax && newZmin >= newZmax)
+  {
+    // selection was ousite all this work for nothing
+    return false;
+  }
+
+  // some of the bounds have been updated, find which ones.
+  if (newXmin >= newXmax)
+  {
+    // no update here
+    newXmin = oldXmin;
+    newXmax = oldXmax;
+  }
+
+  if (newYmin >= newYmax)
+  {
+    // no update here
+    newYmin = oldYmin;
+    newYmax = oldYmax;
+  }
+
+  if (newZmin >= newZmax)
+  {
+    // no update here
+    newZmin = oldZmin;
+    newZmax = oldZmax;
+  }
+
+
+  // ooray we found new bounds
+  // switch back to Scilab coordinates
+  inversePointScale(newXmin, newYmin, newZmin, &newXmin, &newYmin, &newZmin);
+  inversePointScale(newXmax, newYmax, newZmax, &newXmax, &newYmax, &newZmax);
+  double newDataBounds[6] = {newXmin, newXmax, newYmin, newYmax, newZmin, newZmax};
 
   sciSetZoomBox(m_pDrawed, newDataBounds);
 
+  return true;
+
 }
 /*--------------------------------------------------------------------------*/
 void Camera::getViewingArea(int * xPos, int * yPos, int * width, int * height)
 {
   getCameraImp()->getViewingArea(xPos, yPos, width, height);
 }
-/*------------------------------------------------------------------------------------------*/
-void Camera::getNewBounds(const double corners[4][2], const double axisPoint1[3], const double axisPoint2[3],
-                          double oldMinBound, double oldMaxBound, double * newMinBound, double * newMaxBound)
+/*--------------------------------------------------------------------------*/
+void Camera::computeZoomAreaLines(const double areaPixCorners[4][2], double areaLines[4][2][3])
 {
-  // convert axis points into pixels
-  
-  int pixPoint[2];
-  getPixelCoordinates(axisPoint1, pixPoint);
-  double pixPoint1[2] = {pixPoint[0], pixPoint[1]};
-
-  getPixelCoordinates(axisPoint2, pixPoint);
-  double pixPoint2[2] = {pixPoint[0], pixPoint[1]};
-
-  // compute the distance between the two points
-  double p1p2[2];
-  vectSubstract2D(pixPoint2, pixPoint1, p1p2);
-  if (NORM_2D(p1p2) < 5.0)
+  for (int i = 0; i < 4; i++)
   {
-    // axes too short for projection
-    *newMinBound = oldMinBound;
-    *newMaxBound = oldMaxBound;
-    return;
+    // get two points along the axis line in pixel coordinates
+    // in pixel coordinates lines are along Z coordinates
+    // so we can specify everything for as Z
+    // let say 0 and 1
+    double point1[3] = {areaPixCorners[i][0], areaPixCorners[i][1], 0.0};
+    double point2[3] = {areaPixCorners[i][0], areaPixCorners[i][1], -1.0};
+
+    // retrieve scene coordinate
+    getSceneCoordinates(point1, areaLines[i][0]);
+    getSceneCoordinates(point2, areaLines[i][1]);
+    pointScale(areaLines[i][0][0], areaLines[i][0][1], areaLines[i][0][2],
+               &areaLines[i][0][0], &areaLines[i][0][1], &areaLines[i][0][2]);
+    pointScale(areaLines[i][1][0], areaLines[i][1][1], areaLines[i][1][2],
+               &areaLines[i][1][0], &areaLines[i][1][1], &areaLines[i][1][2]);
   }
-
-  getNewBoundsPix(corners, pixPoint1, pixPoint2, oldMinBound, oldMaxBound, newMinBound, newMaxBound);
-
 }
-/*------------------------------------------------------------------------------------------*/
-void Camera::getNewBoundsPix(const double corners[4][2], const double axisPoint1[2], const double axisPoint2[2],
-                             double oldMinBound, double oldMaxBound, double * newMinBound, double * newMaxBound)
+/*--------------------------------------------------------------------------*/
+bool Camera::getXaxisIntersections(const double areaLines[4][2][3], double planeXCoord, double intersections[4][3])
 {
-  double axisVector[2];
-  vectSubstract2D(axisPoint2, axisPoint1, axisVector);
-
-  // get the projection of the four pixels on the axis
-  // for each compute its abscissa along the axis
-  // get the two extreme as new bounds
-  *newMinBound = oldMaxBound;
-  *newMaxBound = oldMinBound;
   for (int i = 0; i < 4; i++)
   {
-    double point1Corner[2];
-    vectSubstract2D(corners[i], axisPoint1, point1Corner);
-    // get the projection between 0 and 1
-    double proj = DOT_PROD_2D(axisVector, point1Corner) / SQUARE_NORM_2D(axisVector);
-
-    // then find its abscissa along the axis
-    double abscissa = (oldMaxBound - oldMinBound) * proj + oldMinBound;
+    // for any plane the result of the intersection is is I = (P1 + a.P2) / (a - 1)
+    // where P1 and P2 are 2 points on the line
+    // and a = ||P1P1'|| / ||P2P2'|| where P1' and P2' are the orthogonal projections
+    // of P1 and P2 on the plane
+
+    // It's not needed to care about ||P2P2'|| being 0 with the value we choose for it
+    const double * p1 = areaLines[i][0];
+    const double * p2 = areaLines[i][1];
+    double alpha = (p1[0] - planeXCoord) / (p2[0] - planeXCoord);
+
+    if (alpha == 1.0)
+    {
+      return false;
+    }
+    
+    getIntersection(p1, p2, alpha, intersections[i]);
+  }
+  return true;
+}
+/*--------------------------------------------------------------------------*/
+bool Camera::getYaxisIntersections(const double areaLines[4][2][3], double planeYCoord, double intersections[4][3])
+{
+  for (int i = 0; i < 4; i++)
+  {
+    // for any plane the result of the intersection is is I = (P1 + a.P2) / (a - 1)
+    // where P1 and P2 are 2 points on the line
+    // and a = ||P1P1'|| / ||P2P2'|| where P1' and P2' are the orthogonal projections
+    // of P1 and P2 on the plane
+
+    // It's not needed to care about ||P2P2'|| being 0 with the value we choose for it
+    const double * p1 = areaLines[i][0];
+    const double * p2 = areaLines[i][1];
+    double alpha = (p1[1] - planeYCoord) / (p2[1] - planeYCoord);
+
+    if (alpha == 1.0)
+    {
+      return false;
+    }
     
-    if (abscissa > *newMaxBound) { *newMaxBound = abscissa ;}
-    if (abscissa < *newMinBound) { *newMinBound = abscissa ;}
+    getIntersection(p1, p2, alpha, intersections[i]);
+  }
+  return true;
+}
+/*--------------------------------------------------------------------------*/
+bool Camera::getZaxisIntersections(const double areaLines[4][2][3], double planeZCoord, double intersections[4][3])
+{
+  for (int i = 0; i < 4; i++)
+  {
+    // for any plane the result of the intersection is is I = (a.P2 - P1) / (a - 1)
+    // where P1 and P2 are 2 points on the line
+    // and a = ||P1P1'|| / ||P2P2'|| where P1' and P2' are the orthogonal projections
+    // of P1 and P2 on the plane
+
+    // It's not needed to care about ||P2P2'|| being 0 with the value we choose for it
+    const double * p1 = areaLines[i][0];
+    const double * p2 = areaLines[i][1];
+    double alpha = (p1[2] - planeZCoord) / (p2[2] - planeZCoord);
+
+    if (alpha == 1.0)
+    {
+      return false;
+    }
+    
+    getIntersection(p1, p2, alpha, intersections[i]);
+  }
+  return true;
+}
+/*--------------------------------------------------------------------------*/
+void Camera::getIntersection(const double p1[3], const double p2[3], double alpha, double intersection[3])
+{
+  scalarMult3D(p2, alpha, intersection); // I = a.P2
+  vectSubstract3D(intersection, p1, intersection); // I = a.P2 - P1
+  scalarMult3D(intersection, 1.0 / (alpha - 1.0), intersection); // I = (P1 + a.P2) / (a - 1)
+}
+/*--------------------------------------------------------------------------*/
+void Camera::updateXCoordinate(const double intersections[4][3],
+                               double oldXmin, double oldXmax,
+                               double & newXmin, double & newXmax)
+{
+  for (int i = 0; i < 4; i++)
+  {
+    if (intersections[i][0] < newXmin)
+    {
+      // it's a zoom don't set bounds outside of old ones
+      newXmin = Max(intersections[i][0], oldXmin);
+    }
+    else if (intersections[i][0] > newXmax)
+    {
+      // it's a zoom don't set bounds outside of old ones
+      newXmax = Min(intersections[i][0], oldXmax);
+    }
+  }
+}
+/*--------------------------------------------------------------------------*/
+void Camera::updateYCoordinate(const double intersections[4][3],
+                               double oldYmin, double oldYmax,
+                               double & newYmin, double & newYmax)
+{
+  for (int i = 0; i < 4; i++)
+  {
+    if (intersections[i][1] < newYmin)
+    {
+      // it's a zoom don't set bounds outside of old ones
+      newYmin = Max(intersections[i][1], oldYmin);
+    }
+    else if (intersections[i][1] > newYmax)
+    {
+      // it's a zoom don't set bounds outside of old ones
+      newYmax = Min(intersections[i][1], oldYmax);
+    }
+  }
+}
+/*--------------------------------------------------------------------------*/
+void Camera::updateZCoordinate(const double intersections[4][3],
+                               double oldZmin, double oldZmax,
+                               double & newZmin, double & newZmax)
+{
+  for (int i = 0; i < 4; i++)
+  {
+    if (intersections[i][2] < newZmin)
+    {
+      // it's a zoom don't set bounds outside of old ones
+      newZmin = Max(intersections[i][2], oldZmin);
+    }
+    else if (intersections[i][2] > newZmax)
+    {
+      // it's a zoom don't set bounds outside of old ones
+      newZmax = Min(intersections[i][2], oldZmax);
+    }
+  }
+}
+/*--------------------------------------------------------------------------*/
+bool Camera::checkXIntersections(const double intersections[4][3],
+                                 double oldYmin, double oldYmax,
+                                 double oldZmin, double oldZmax)
+{
+  for (int i = 0; i < 4; i++)
+  {
+    if (   intersections[i][1] >= oldYmin && intersections[i][1] <= oldYmax
+        && intersections[i][2] >= oldZmin && intersections[i][2] <= oldZmax)
+    {
+      // at least one point in the side
+      return true;
+    }
+  }
+  return false;
+}
+/*--------------------------------------------------------------------------*/
+bool Camera::checkYIntersections(const double intersections[4][3],
+                                 double oldXmin, double oldXmax,
+                                 double oldZmin, double oldZmax)
+{
+  for (int i = 0; i < 4; i++)
+  {
+    if (   intersections[i][0] >= oldXmin && intersections[i][0] <= oldXmax
+        && intersections[i][2] >= oldZmin && intersections[i][2] <= oldZmax)
+    {
+      // at least one point in the side
+      return true;
+    }
+  }
+  return false;
+}
+/*--------------------------------------------------------------------------*/
+bool Camera::checkZIntersections(const double intersections[4][3],
+                                 double oldXmin, double oldXmax,
+                                 double oldYmin, double oldYmax)
+{
+  for (int i = 0; i < 4; i++)
+  {
+    if (   intersections[i][0] >= oldXmin && intersections[i][0] <= oldXmax
+        && intersections[i][1] >= oldYmin && intersections[i][1] <= oldYmax)
+    {
+      // at least one point in the side
+      return true;
+    }
   }
+  return false;
 }
 /*--------------------------------------------------------------------------*/
 CameraBridge * Camera::getCameraImp( void )
index a3c85c3..a2faf59 100644 (file)
@@ -86,8 +86,9 @@ public:
    * @param posY Y coordinate of the lower left point of the zoom box in pixels.
    * @param width width of the zooming rectangle.
    * @param height height of the zooming rectangle.
+   * @return true if the axes box has been zoomed, false otherwise
    */
-  void zoomRect(int posX, int posY, int width, int height);
+  bool zoomRect(int posX, int posY, int width, int height);
 
   /**
    * Get the position and size of the rectangle in which the axes box must fit
@@ -133,34 +134,113 @@ protected:
   /**
    * Apply a zoom square on the axes box
    * @param corners the 4 corners of the zooming rectangle in pixel
+   * @return true if the axes box has been zoomed, false otherwise
    */
-  void zoomRect(const double corners[4][2]);
+  bool zoomRect(const double corners[4][2]);
 
   /**
-   * Compute new bounds for one axis.
-   * @param corners coordinates of the zooming rectangle in pixels
-   * @param axisPoint1 coordinates of a point on the axis in user coordinates.
-   * @param axisPoint2 coordinate of an other point on the axis in user coordinates.
-   * @param minBound old minimum bound on the axis
-   * @param maxNound old maximum bound on the axis
-   * @param[out] newMinBound newly computed minimum bound
-   * @param[out] newMaxBound newly computed maximum bound.
+   * Compute the lines composing the zooming selection area
+   * @param areaPixCorners corners of the selction rectangle in pixels
+   * @param areaLines 4 line composing the selection area in 3D
    */
-  void getNewBounds(const double corners[4][2], const double axisPoint1[3], const double axisPoint2[3],
-                    double oldMinBound, double oldMaxBound, double * newMinBound, double * newMaxBound);
+  void computeZoomAreaLines(const double areaPixCorners[4][2], double areaLines[4][2][3]);
 
   /**
-   * Compute new bounds for one axis.
-   * @param corners coordinates of the zooming rectangle in pixels
-   * @param axisPoint1 coordinates of a point on the axis in pixels
-   * @param axisPoint2 coordinate of an other point on the axis in pixels
-   * @param minBound old minimum bound on the axis
-   * @param maxNound old maximum bound on the axis
-   * @param[out] newMinBound newly computed minimum bound
-   * @param[out] newMaxBound newly computed maximum bound.
+   * Compute the 4 intersections of the lines with an x = planeXcoord plane
+   * @param areaLines 4 lines composing the selection area in 3D
+   * @param planeXcoord either xMin or xMax
+   * @return false if no intersections could be computed (lines and plane are parallel)
    */
-  void getNewBoundsPix(const double corners[4][2], const double axisPoint1[2], const double axisPoint2[2],
-                       double oldMinBound, double oldMaxBound, double * newMinBound, double * newMaxBound);
+  bool getXaxisIntersections(const double areaLines[4][2][3], double planeXCoord, double intersections[4][3]);
+
+  /**
+   * Compute the 4 intersections of the lines with an y = planeYcoord plane
+   * @param areaLines 4 lines composing the selection area in 3D
+   * @param planeXcoord either yMin or yMax
+   * @return false if no intersections could be computed (lines and plane are parallel)
+   */
+  bool getYaxisIntersections(const double areaLines[4][2][3], double planeYCoord, double intersections[4][3]);
+
+  /**
+   * Compute the 4 intersections of the lines with an z = planeZcoord plane
+   * @param areaLines 4 lines composing the selection area in 3D
+   * @param planeXcoord either zMin or zMax
+   * @return false if no intersections could be computed (lines and plane are parallel)
+   */
+  bool getZaxisIntersections(const double areaLines[4][2][3], double planeZCoord, double intersections[4][3]);
+
+  /**
+   * Compute the intersection of the line defined by p1 and p2 knowing the alpha value
+   * @param intersection coordinates of the intersection
+   * @param alpha shuld be different than 1
+   */
+  void getIntersection(const double p1[3], const double p2[3], double alpha, double intersection[3]);
+
+  /**
+   * Update the new X bounds with 4 new intersections
+   * @param intersections intesection of the selection volume with a plane
+   * @param oldXMin previous minimal bound along X axis
+   * @param oldXMax previous maximal bound along X axis
+   * @param[in/out] newYmin currently computed minimum X bound
+   * @param[in/out] newYmax currently computed maximum X bound
+   */
+  void updateXCoordinate(const double intersections[4][3],
+                         double oldXmin, double oldXmax,
+                         double & newXmin, double & newXmax);
+
+  /**
+   * Update the new Y bounds with 4 new intersections
+   * @param intersections intesection of the selection volume with a plane
+   * @param oldYMin previous minimal bound along Y axis
+   * @param oldYMax previous maximal bound along Y axis
+   * @param[in/out] newYmin currently computed minimum Y bound
+   * @param[in/out] newYmax currently computed maximum Y bound
+   */
+  void updateYCoordinate(const double intersections[4][3],
+                         double oldYmin, double oldYmax,
+                         double & newYmin, double & newYmax);
+
+  /**
+   * Update the new z bounds with 4 new intersections
+   * @param intersections intesection of the selection volume with a plane
+   * @param oldMin previous minimal bound along Z axis
+   * @param oldMax previous maximal bound along Z axis
+   * @param[in/out] newYmin currently computed minimum Z bound
+   * @param[in/out] newYmax currently computed maximum Z bound
+   */
+  void updateZCoordinate(const double intersections[4][3],
+                         double oldZmin, double oldZmax,
+                         double & newZmin, double & newZmax);
+
+  /**
+   * test if part of the intersections is within a cube side
+   * with equatuion x = cst
+   * @return true if the intersection are within the side and
+   *              that intersections may be used to update data bounds
+   */
+  bool checkXIntersections(const double intersections[4][3],
+                           double oldYmin, double oldYmax,
+                           double oldZmin, double oldZmax);
+
+  /**
+   * test if part of the intersections is within a cube side
+   * with equatuion x = cst
+   * @return true if the intersection are within the side and
+   *              that intersections may be used to update data bounds
+   */
+  bool checkYIntersections(const double intersections[4][3],
+                           double oldXmin, double oldXmax,
+                           double oldZmin, double oldZmax);
+
+  /**
+   * test if part of the intersections is within a cube side
+   * with equatuion x = cst
+   * @return true if the intersection are within the side and
+   *              that intersections may be used to update data bounds
+   */
+  bool checkZIntersections(const double intersections[4][3],
+                           double oldXmin, double oldXmax,
+                           double oldYmin, double oldYmax);
 
 
   /**
index 67a548b..e1f4af6 100644 (file)
@@ -506,7 +506,7 @@ public abstract class TicksDrawerGL extends BoxTrimmingObjectGL {
                int firstNonNullTicksIndex = 0;
                
                // find first non null ticks
-               while (ticksPosPix[firstNonNullTicksIndex] == null) {
+               while (firstNonNullTicksIndex < nbLabels && ticksPosPix[firstNonNullTicksIndex] == null) {
                        firstNonNullTicksIndex++;
                }