summaryrefslogtreecommitdiffstats
Side-by-side diff
-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.