summaryrefslogtreecommitdiffstats
authorDon Pellegrino <don@coffee.donpellegrino.com>2009-08-18 06:10:41 (GMT)
committer Don Pellegrino <don@coffee.donpellegrino.com>2009-08-18 06:10:41 (GMT)
commit9b11713580664fea7f3f80d89b9acd42195ca8c3 (patch) (side-by-side diff)
tree90659481e877e4060ade36986ee09e3c7e51e95e
parentd7aa70eaad644f2892c60ce85539d5439e0804b2 (diff)
downloadexp005-9b11713580664fea7f3f80d89b9acd42195ca8c3.zip
exp005-9b11713580664fea7f3f80d89b9acd42195ca8c3.tar.gz
exp005-9b11713580664fea7f3f80d89b9acd42195ca8c3.tar.bz2
Fixed bug in zooming and panning. Interactive testing of zooming by
rubber band, zooming with the mouse wheel and panning all work with the window at any size, square or non-square.
-rw-r--r--src/controller/actions/set_ortho.c13
-rw-r--r--src/controller/actions/zoom.c70
-rw-r--r--src/controller/actions/zoom.h4
-rw-r--r--src/controller/callbacks/display.c6
-rw-r--r--src/controller/callbacks/keyboard.c7
-rw-r--r--src/controller/callbacks/mouse.c49
-rw-r--r--src/controller/callbacks/mouse_wheel.c66
-rw-r--r--src/controller/callbacks/reshape.c68
-rw-r--r--src/model/geometry/density_legend_geometry.c18
-rw-r--r--src/model/state/zoom_info.h1
-rw-r--r--src/model/state/zoom_info_init.c6
11 files changed, 197 insertions, 111 deletions
diff --git a/src/controller/actions/set_ortho.c b/src/controller/actions/set_ortho.c
index 4309c76..ce66f60 100644
--- a/src/controller/actions/set_ortho.c
+++ b/src/controller/actions/set_ortho.c
@@ -7,15 +7,10 @@
void
set_ortho (void)
{
- if (S.zoom.active)
- {
- gluOrtho2D (S.zoom.coords[0],
- S.zoom.coords[1], S.zoom.coords[2], S.zoom.coords[3]);
- }
- else
- {
- gluOrtho2D (S.ortho.min_x, S.ortho.max_x, S.ortho.min_y, S.ortho.max_y);
- }
+ gluOrtho2D (S.ortho.min_x,
+ S.ortho.max_x,
+ S.ortho.min_y,
+ S.ortho.max_y);
return;
}
diff --git a/src/controller/actions/zoom.c b/src/controller/actions/zoom.c
index b8e54cc..7209e85 100644
--- a/src/controller/actions/zoom.c
+++ b/src/controller/actions/zoom.c
@@ -11,52 +11,40 @@
#define S state0
void
-zoom (int x1, int y1, int x2, int y2)
+zoom (double x1, double y1, double x2, double y2)
{
+ S.zoom.active = true;
+
+ S.zoom.coords[0] = x1;
+ S.zoom.coords[1] = x2;
+ S.zoom.coords[2] = y1;
+ S.zoom.coords[3] = y2;
+
/*
- * Convert the selection boundary from window coordinates to
- * world coordinates.
+ * Preserve the aspect ratio. First convert the selection to the
+ * aspect ratio of the original geometry. The world is a square so
+ * convert the zoom region to a square. The reshape callback
+ * performs step two of converting the squarified zoom region to the
+ * aspect ratio of the window. This is done in reshape as the window
+ * may change while the zoom region is held the same.
*/
- glMatrixMode (GL_MODELVIEW);
- glLoadIdentity ();
- GLdouble model[16];
- glGetDoublev (GL_MODELVIEW_MATRIX, model);
- GLdouble projection[16];
- glGetDoublev (GL_PROJECTION_MATRIX, projection);
+ double width = S.zoom.coords[1] - S.zoom.coords[0];
+ double height = S.zoom.coords[3] - S.zoom.coords[2];
+ double difference = fabs(width - height);
+
+ if (width > height)
+ {
+ S.zoom.coords[2] -= 0.5 * difference;
+ S.zoom.coords[3] += 0.5 * difference;
+ }
+ else
+ {
+ S.zoom.coords[0] -= 0.5 * difference;
+ S.zoom.coords[1] += 0.5 * difference;
+ }
+
GLint viewport[4];
glGetIntegerv (GL_VIEWPORT, viewport);
-
- check_error (__FILE__, __LINE__);
-
- GLdouble start_position[3];
- gluUnProject (x1,
- y1,
- 0,
- model,
- projection,
- viewport,
- &start_position[0],
- &start_position[1], &start_position[2]);
-
- check_error (__FILE__, __LINE__);
-
- GLdouble end_position[3];
- gluUnProject (x2,
- y2,
- 0,
- model,
- projection,
- viewport,
- &end_position[0], &end_position[1], &end_position[2]);
-
- check_error (__FILE__, __LINE__);
-
- S.zoom.active = true;
- S.zoom.coords[0] = fmin (start_position[0], end_position[0]);
- S.zoom.coords[1] = fmax (start_position[0], end_position[0]);
- S.zoom.coords[2] = fmin (start_position[1], end_position[1]);
- S.zoom.coords[3] = fmax (start_position[1], end_position[1]);
-
reshape (viewport[2], viewport[3]);
glutPostRedisplay ();
diff --git a/src/controller/actions/zoom.h b/src/controller/actions/zoom.h
index bd5b852..4dc1769 100644
--- a/src/controller/actions/zoom.h
+++ b/src/controller/actions/zoom.h
@@ -2,8 +2,8 @@
#define ZOOM_H
/*
- * Perform a zoom operation.
+ * Perform a zoom operation. Inputs are in world coordinates.
*/
-void zoom (int x1, int y1, int x2, int y2);
+void zoom (double x1, double y1, double x2, double y2);
#endif // ZOOM_H
diff --git a/src/controller/callbacks/display.c b/src/controller/callbacks/display.c
index b9a76a6..bee3286 100644
--- a/src/controller/callbacks/display.c
+++ b/src/controller/callbacks/display.c
@@ -1,10 +1,16 @@
#include "display.h"
#include "../../view/geometry.h"
+#include "../actions/set_ortho.h"
#include <GL/glut.h>
void
display (void)
{
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+ set_ortho ();
+
+ glMatrixMode (GL_MODELVIEW);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
geometry (GL_RENDER);
glutSwapBuffers ();
diff --git a/src/controller/callbacks/keyboard.c b/src/controller/callbacks/keyboard.c
index 9967ad3..9e667d8 100644
--- a/src/controller/callbacks/keyboard.c
+++ b/src/controller/callbacks/keyboard.c
@@ -4,6 +4,7 @@
#include "reshape.h"
#include "../../view/state0.h"
#include "../../model/state/pan_info_init.h"
+#include "../../model/state/zoom_info_init.h"
#include <GL/glut.h>
#define S state0
@@ -41,11 +42,11 @@ keyboard (unsigned char key, int x, int y)
case 'r':
/*
- * Reset the view (unzoom).
+ * Reset the view (unzoom, recenter).
*/
pan_info_init (&S.pan);
- S.zoom.active = false;
-
+ zoom_info_init (&S.zoom);
+
GLint viewport[4];
glGetIntegerv (GL_VIEWPORT, viewport);
reshape (viewport[2], viewport[3]);
diff --git a/src/controller/callbacks/mouse.c b/src/controller/callbacks/mouse.c
index f901476..34ff290 100644
--- a/src/controller/callbacks/mouse.c
+++ b/src/controller/callbacks/mouse.c
@@ -25,7 +25,7 @@ mouse (int button, int state, int x, int y)
{
// Deactive a panning event if one was happening.
S.pan.active = false;
-
+
if (S.selection.active &&
S.selection.purpose == ZOOM &&
glutGetModifiers () == GLUT_ACTIVE_CTRL)
@@ -35,14 +35,49 @@ mouse (int button, int state, int x, int y)
*/
if (x == S.selection.x || y == S.selection.y)
return;
-
+
+ /*
+ * Convert the selection boundary from window coordinates to
+ * world coordinates.
+ */
+ glMatrixMode (GL_MODELVIEW);
+ glLoadIdentity ();
+ GLdouble model[16];
+ glGetDoublev (GL_MODELVIEW_MATRIX, model);
+ GLdouble projection[16];
+ glGetDoublev (GL_PROJECTION_MATRIX, projection);
GLint viewport[4];
glGetIntegerv (GL_VIEWPORT, viewport);
-
- zoom (S.selection.x,
- viewport[3] - S.selection.y,
- x,
- viewport[3] - y);
+
+ check_error (__FILE__, __LINE__);
+
+ GLdouble start_position[3];
+ gluUnProject (x,
+ viewport[3] -y,
+ 0,
+ model,
+ projection,
+ viewport,
+ &start_position[0],
+ &start_position[1], &start_position[2]);
+
+ check_error (__FILE__, __LINE__);
+
+ GLdouble end_position[3];
+ gluUnProject (S.selection.x,
+ viewport[3] - S.selection.y,
+ 0,
+ model,
+ projection,
+ viewport,
+ &end_position[0], &end_position[1], &end_position[2]);
+
+ check_error (__FILE__, __LINE__);
+
+ zoom (fmin (start_position[0], end_position[0]),
+ fmin (start_position[1], end_position[1]),
+ fmax (start_position[0], end_position[0]),
+ fmax (start_position[1], end_position[1]));
}
/*
diff --git a/src/controller/callbacks/mouse_wheel.c b/src/controller/callbacks/mouse_wheel.c
index 52d3c8b..9ca73bc 100644
--- a/src/controller/callbacks/mouse_wheel.c
+++ b/src/controller/callbacks/mouse_wheel.c
@@ -1,44 +1,74 @@
#include "mouse_wheel.h"
#include "../actions/zoom.h"
+#include "../../view/state0.h"
#include <GL/glut.h>
+#include <math.h>
+
+#define S state0
void
mouse_wheel (int button, int dir, int x, int y)
{
/*
- * Get the current coordinates, substract some fixed amount and
- * then perform the zoom.
+ * Start at the origin of the window. An alternative would be to
+ * start at the position of the mouse. Calculate a bounding box
+ * that will be the selection and zoom to it.
*/
- GLint viewport[4];
- glGetIntegerv (GL_VIEWPORT, viewport);
+ double width = fabs(S.ortho.max_x - S.ortho.min_x);
+ double height = fabs(S.ortho.max_y - S.ortho.min_y);
/*
- * The step size could be either a fixed number of pixels or a percentage.
+ * Box the smaller of the two dimensions.
*/
- // int step = 5;
- int step = (viewport[3] - viewport[1]) * 0.10;
+ double box = 0.0;
+ if (width <= height)
+ box = width;
+ else
+ box = height;
/*
- * Not that the focus of the zoom is currently the center of the
- * window but could alternatively be the mouse pointer's position.
+ * The step size could be either a fixed number of pixels or a
+ * percentage. Here we take 10% of the size of the box.
*/
+ double step = box * 0.10;
+
+ double x1 = 0.0;
+ double y1 = 0.0;
+ double x2 = 0.0;
+ double y2 = 0.0;
+
+ if (width < height)
+ {
+ x1 = S.ortho.min_x;
+ x2 = S.ortho.max_x;
+ y1 = ((S.ortho.max_y + S.ortho.min_y) / 2.0) - (0.5 * width);
+ y2 = ((S.ortho.max_y + S.ortho.min_y) / 2.0) + (0.5 * width);
+ }
+ else if (width > height)
+ {
+ x1 = ((S.ortho.max_x + S.ortho.min_x) / 2.0) - (0.5 * height);
+ x2 = ((S.ortho.max_x + S.ortho.min_x) / 2.0) + (0.5 * height);
+ y1 = S.ortho.min_y;
+ y2 = S.ortho.max_y;
+ }
+ else
+ {
+ x1 = S.ortho.min_x;
+ x2 = S.ortho.max_x;
+ y1 = S.ortho.min_y;
+ y2 = S.ortho.max_y;
+ }
// Zoom in
- if (dir > 0)
+ if (dir > 0)
{
- zoom (step,
- step,
- viewport[3] - step,
- viewport[3] - step);
+ zoom (x1 + step, y1 + step, x2 - step, y2 - step);
}
// Zoom out
else
{
- zoom (-step,
- -step,
- viewport[3] + step,
- viewport[3] + step);
+ zoom (x1 - step, y1 - step, x2 + step, y2 + step);
}
return;
diff --git a/src/controller/callbacks/reshape.c b/src/controller/callbacks/reshape.c
index 2455ea3..fec5443 100644
--- a/src/controller/callbacks/reshape.c
+++ b/src/controller/callbacks/reshape.c
@@ -3,6 +3,8 @@
#include "../actions/set_ortho.h"
#include "reshape.h"
#include <GL/glut.h>
+#include <math.h>
+#include <stdio.h>
#define S state0
@@ -13,26 +15,60 @@ reshape (int w, int h)
glLoadIdentity ();
/*
- * This scaling produces an odd effect when the coordinates are not
- * centered at 0,0. When 0,0 is the lower left rather than the
- * center this reshape is a bit unnatural since the image is not
- * centered in the middle of the window.
+ * Scale the zoom region to the aspect ratio of the window.
*/
-
- if (w <= h)
+ if (S.zoom.active)
{
- S.ortho.min_x = S.ortho_min;
- S.ortho.max_x = S.ortho_max;
- S.ortho.min_y = S.ortho_min * (double) h / (double) w;
- S.ortho.max_y = S.ortho_max * (double) h / (double) w;
+ if (w >= h)
+ {
+ double scale
+ = ( ( (S.zoom.coords[1] - S.zoom.coords[0]) * ((double) w / (double) h) )
+ - (S.zoom.coords[1] - S.zoom.coords[0]) )
+ * 0.5;
+
+ S.ortho.min_x = S.zoom.coords[0] - scale;
+ S.ortho.max_x = S.zoom.coords[1] + scale;
+ S.ortho.min_y = S.zoom.coords[2];
+ S.ortho.max_y = S.zoom.coords[3];
+ }
+ else
+ {
+ double scale
+ = ( ( (S.zoom.coords[3] - S.zoom.coords[2]) * ((double) h / (double) w) )
+ - (S.zoom.coords[3] - S.zoom.coords[2]) )
+ * 0.5;
+
+ S.ortho.min_x = S.zoom.coords[0];
+ S.ortho.max_x = S.zoom.coords[1];
+ S.ortho.min_y = S.zoom.coords[2] - scale;
+ S.ortho.max_y = S.zoom.coords[3] + scale;
+ }
}
- else
+
+ else
{
- S.ortho.min_x = S.ortho_min * (double) w / (double) h;
- S.ortho.max_x = S.ortho_max * (double) w / (double) h;
- S.ortho.min_y = S.ortho_min;
- S.ortho.max_y = S.ortho_max;
- }
+ /*
+ * This scaling produces an odd effect when the coordinates are
+ * not centered at 0,0. When 0,0 is the lower left rather than
+ * the center this reshape is a bit unnatural since the image is
+ * not centered in the middle of the window. Try chaning this
+ * to use the method used above for the zoom region scaling.
+ */
+ if (w <= h)
+ {
+ S.ortho.min_x = S.ortho_min;
+ S.ortho.max_x = S.ortho_max;
+ S.ortho.min_y = S.ortho_min * (double) h / (double) w;
+ S.ortho.max_y = S.ortho_max * (double) h / (double) w;
+ }
+ else
+ {
+ S.ortho.min_x = S.ortho_min * (double) w / (double) h;
+ S.ortho.max_x = S.ortho_max * (double) w / (double) h;
+ S.ortho.min_y = S.ortho_min;
+ S.ortho.max_y = S.ortho_max;
+ }
+ }
set_ortho ();
diff --git a/src/model/geometry/density_legend_geometry.c b/src/model/geometry/density_legend_geometry.c
index e5baa08..ac3280c 100644
--- a/src/model/geometry/density_legend_geometry.c
+++ b/src/model/geometry/density_legend_geometry.c
@@ -27,20 +27,10 @@ density_legend_geometry (void)
const double *top;
const double *bottom;
- if (S.zoom.active)
- {
- left = &S.zoom.coords[0];
- right = &S.zoom.coords[1];
- bottom = &S.zoom.coords[2];
- top = &S.zoom.coords[3];
- }
- else
- {
- left = &S.ortho.min_x;
- right = &S.ortho.max_x;
- bottom = &S.ortho.min_y;
- top = &S.ortho.max_y;
- }
+ left = &S.ortho.min_x;
+ right = &S.ortho.max_x;
+ bottom = &S.ortho.min_y;
+ top = &S.ortho.max_y;
/*
* This value should be a percentage of the world height so that it
diff --git a/src/model/state/zoom_info.h b/src/model/state/zoom_info.h
index 5916b3c..83fab2c 100644
--- a/src/model/state/zoom_info.h
+++ b/src/model/state/zoom_info.h
@@ -15,6 +15,7 @@ typedef struct
/*
* Left, right, bottom and top of zoom region in world coordinates.
+ * Rubber-band zoom.
*/
double coords[4];
} ZOOM_INFO;
diff --git a/src/model/state/zoom_info_init.c b/src/model/state/zoom_info_init.c
index f49dd59..aa230d8 100644
--- a/src/model/state/zoom_info_init.c
+++ b/src/model/state/zoom_info_init.c
@@ -4,6 +4,10 @@ void
zoom_info_init (ZOOM_INFO * z)
{
z->active = false;
-
+ z->coords[0] = 0.0;
+ z->coords[1] = 0.0;
+ z->coords[2] = 0.0;
+ z->coords[3] = 0.0;
+
return;
}

Valid XHTML 1.0 Strict

Copyright © 2009 Don Pellegrino All Rights Reserved.