-rw-r--r-- | src/controller/actions/set_ortho.c | 13 | ||||
-rw-r--r-- | src/controller/actions/zoom.c | 70 | ||||
-rw-r--r-- | src/controller/actions/zoom.h | 4 | ||||
-rw-r--r-- | src/controller/callbacks/display.c | 6 | ||||
-rw-r--r-- | src/controller/callbacks/keyboard.c | 7 | ||||
-rw-r--r-- | src/controller/callbacks/mouse.c | 49 | ||||
-rw-r--r-- | src/controller/callbacks/mouse_wheel.c | 66 | ||||
-rw-r--r-- | src/controller/callbacks/reshape.c | 68 | ||||
-rw-r--r-- | src/model/geometry/density_legend_geometry.c | 18 | ||||
-rw-r--r-- | src/model/state/zoom_info.h | 1 | ||||
-rw-r--r-- | src/model/state/zoom_info_init.c | 6 |
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 @@ | |||
7 | void | 7 | void |
8 | set_ortho (void) | 8 | set_ortho (void) |
9 | { | 9 | { |
10 | if (S.zoom.active) | 10 | gluOrtho2D (S.ortho.min_x, |
11 | { | 11 | S.ortho.max_x, |
12 | gluOrtho2D (S.zoom.coords[0], | 12 | S.ortho.min_y, |
13 | S.zoom.coords[1], S.zoom.coords[2], S.zoom.coords[3]); | 13 | S.ortho.max_y); |
14 | } | ||
15 | else | ||
16 | { | ||
17 | gluOrtho2D (S.ortho.min_x, S.ortho.max_x, S.ortho.min_y, S.ortho.max_y); | ||
18 | } | ||
19 | 14 | ||
20 | return; | 15 | return; |
21 | } | 16 | } |
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 @@ | |||
11 | #define S state0 | 11 | #define S state0 |
12 | 12 | ||
13 | void | 13 | void |
14 | zoom (int x1, int y1, int x2, int y2) | 14 | zoom (double x1, double y1, double x2, double y2) |
15 | { | 15 | { |
16 | S.zoom.active = true; | ||
17 | |||
18 | S.zoom.coords[0] = x1; | ||
19 | S.zoom.coords[1] = x2; | ||
20 | S.zoom.coords[2] = y1; | ||
21 | S.zoom.coords[3] = y2; | ||
22 | |||
16 | /* | 23 | /* |
17 | * Convert the selection boundary from window coordinates to | 24 | * Preserve the aspect ratio. First convert the selection to the |
18 | * world coordinates. | 25 | * aspect ratio of the original geometry. The world is a square so |
26 | * convert the zoom region to a square. The reshape callback | ||
27 | * performs step two of converting the squarified zoom region to the | ||
28 | * aspect ratio of the window. This is done in reshape as the window | ||
29 | * may change while the zoom region is held the same. | ||
19 | */ | 30 | */ |
20 | glMatrixMode (GL_MODELVIEW); | 31 | double width = S.zoom.coords[1] - S.zoom.coords[0]; |
21 | glLoadIdentity (); | 32 | double height = S.zoom.coords[3] - S.zoom.coords[2]; |
22 | GLdouble model[16]; | 33 | double difference = fabs(width - height); |
23 | glGetDoublev (GL_MODELVIEW_MATRIX, model); | 34 | |
24 | GLdouble projection[16]; | 35 | if (width > height) |
25 | glGetDoublev (GL_PROJECTION_MATRIX, projection); | 36 | { |
37 | S.zoom.coords[2] -= 0.5 * difference; | ||
38 | S.zoom.coords[3] += 0.5 * difference; | ||
39 | } | ||
40 | else | ||
41 | { | ||
42 | S.zoom.coords[0] -= 0.5 * difference; | ||
43 | S.zoom.coords[1] += 0.5 * difference; | ||
44 | } | ||
45 | |||
26 | GLint viewport[4]; | 46 | GLint viewport[4]; |
27 | glGetIntegerv (GL_VIEWPORT, viewport); | 47 | glGetIntegerv (GL_VIEWPORT, viewport); |
28 | |||
29 | check_error (__FILE__, __LINE__); | ||
30 | |||
31 | GLdouble start_position[3]; | ||
32 | gluUnProject (x1, | ||
33 | y1, | ||
34 | 0, | ||
35 | model, | ||
36 | projection, | ||
37 | viewport, | ||
38 | &start_position[0], | ||
39 | &start_position[1], &start_position[2]); | ||
40 | |||
41 | check_error (__FILE__, __LINE__); | ||
42 | |||
43 | GLdouble end_position[3]; | ||
44 | gluUnProject (x2, | ||
45 | y2, | ||
46 | 0, | ||
47 | model, | ||
48 | projection, | ||
49 | viewport, | ||
50 | &end_position[0], &end_position[1], &end_position[2]); | ||
51 | |||
52 | check_error (__FILE__, __LINE__); | ||
53 | |||
54 | S.zoom.active = true; | ||
55 | S.zoom.coords[0] = fmin (start_position[0], end_position[0]); | ||
56 | S.zoom.coords[1] = fmax (start_position[0], end_position[0]); | ||
57 | S.zoom.coords[2] = fmin (start_position[1], end_position[1]); | ||
58 | S.zoom.coords[3] = fmax (start_position[1], end_position[1]); | ||
59 | |||
60 | reshape (viewport[2], viewport[3]); | 48 | reshape (viewport[2], viewport[3]); |
61 | 49 | ||
62 | glutPostRedisplay (); | 50 | 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 @@ | |||
2 | #define ZOOM_H | 2 | #define ZOOM_H |
3 | 3 | ||
4 | /* | 4 | /* |
5 | * Perform a zoom operation. | 5 | * Perform a zoom operation. Inputs are in world coordinates. |
6 | */ | 6 | */ |
7 | void zoom (int x1, int y1, int x2, int y2); | 7 | void zoom (double x1, double y1, double x2, double y2); |
8 | 8 | ||
9 | #endif // ZOOM_H | 9 | #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 @@ | |||
1 | #include "display.h" | 1 | #include "display.h" |
2 | #include "../../view/geometry.h" | 2 | #include "../../view/geometry.h" |
3 | #include "../actions/set_ortho.h" | ||
3 | #include <GL/glut.h> | 4 | #include <GL/glut.h> |
4 | 5 | ||
5 | void | 6 | void |
6 | display (void) | 7 | display (void) |
7 | { | 8 | { |
9 | glMatrixMode (GL_PROJECTION); | ||
10 | glLoadIdentity (); | ||
11 | set_ortho (); | ||
12 | |||
13 | glMatrixMode (GL_MODELVIEW); | ||
8 | glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | 14 | glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
9 | geometry (GL_RENDER); | 15 | geometry (GL_RENDER); |
10 | glutSwapBuffers (); | 16 | 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 @@ | |||
4 | #include "reshape.h" | 4 | #include "reshape.h" |
5 | #include "../../view/state0.h" | 5 | #include "../../view/state0.h" |
6 | #include "../../model/state/pan_info_init.h" | 6 | #include "../../model/state/pan_info_init.h" |
7 | #include "../../model/state/zoom_info_init.h" | ||
7 | #include <GL/glut.h> | 8 | #include <GL/glut.h> |
8 | 9 | ||
9 | #define S state0 | 10 | #define S state0 |
@@ -41,11 +42,11 @@ keyboard (unsigned char key, int x, int y) | |||
41 | 42 | ||
42 | case 'r': | 43 | case 'r': |
43 | /* | 44 | /* |
44 | * Reset the view (unzoom). | 45 | * Reset the view (unzoom, recenter). |
45 | */ | 46 | */ |
46 | pan_info_init (&S.pan); | 47 | pan_info_init (&S.pan); |
47 | S.zoom.active = false; | 48 | zoom_info_init (&S.zoom); |
48 | 49 | ||
49 | GLint viewport[4]; | 50 | GLint viewport[4]; |
50 | glGetIntegerv (GL_VIEWPORT, viewport); | 51 | glGetIntegerv (GL_VIEWPORT, viewport); |
51 | reshape (viewport[2], viewport[3]); | 52 | 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) | |||
25 | { | 25 | { |
26 | // Deactive a panning event if one was happening. | 26 | // Deactive a panning event if one was happening. |
27 | S.pan.active = false; | 27 | S.pan.active = false; |
28 | 28 | ||
29 | if (S.selection.active && | 29 | if (S.selection.active && |
30 | S.selection.purpose == ZOOM && | 30 | S.selection.purpose == ZOOM && |
31 | glutGetModifiers () == GLUT_ACTIVE_CTRL) | 31 | glutGetModifiers () == GLUT_ACTIVE_CTRL) |
@@ -35,14 +35,49 @@ mouse (int button, int state, int x, int y) | |||
35 | */ | 35 | */ |
36 | if (x == S.selection.x || y == S.selection.y) | 36 | if (x == S.selection.x || y == S.selection.y) |
37 | return; | 37 | return; |
38 | 38 | ||
39 | /* | ||
40 | * Convert the selection boundary from window coordinates to | ||
41 | * world coordinates. | ||
42 | */ | ||
43 | glMatrixMode (GL_MODELVIEW); | ||
44 | glLoadIdentity (); | ||
45 | GLdouble model[16]; | ||
46 | glGetDoublev (GL_MODELVIEW_MATRIX, model); | ||
47 | GLdouble projection[16]; | ||
48 | glGetDoublev (GL_PROJECTION_MATRIX, projection); | ||
39 | GLint viewport[4]; | 49 | GLint viewport[4]; |
40 | glGetIntegerv (GL_VIEWPORT, viewport); | 50 | glGetIntegerv (GL_VIEWPORT, viewport); |
41 | 51 | ||
42 | zoom (S.selection.x, | 52 | check_error (__FILE__, __LINE__); |
43 | viewport[3] - S.selection.y, | 53 | |
44 | x, | 54 | GLdouble start_position[3]; |
45 | viewport[3] - y); | 55 | gluUnProject (x, |
56 | viewport[3] -y, | ||
57 | 0, | ||
58 | model, | ||
59 | projection, | ||
60 | viewport, | ||
61 | &start_position[0], | ||
62 | &start_position[1], &start_position[2]); | ||
63 | |||
64 | check_error (__FILE__, __LINE__); | ||
65 | |||
66 | GLdouble end_position[3]; | ||
67 | gluUnProject (S.selection.x, | ||
68 | viewport[3] - S.selection.y, | ||
69 | 0, | ||
70 | model, | ||
71 | projection, | ||
72 | viewport, | ||
73 | &end_position[0], &end_position[1], &end_position[2]); | ||
74 | |||
75 | check_error (__FILE__, __LINE__); | ||
76 | |||
77 | zoom (fmin (start_position[0], end_position[0]), | ||
78 | fmin (start_position[1], end_position[1]), | ||
79 | fmax (start_position[0], end_position[0]), | ||
80 | fmax (start_position[1], end_position[1])); | ||
46 | } | 81 | } |
47 | 82 | ||
48 | /* | 83 | /* |
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 @@ | |||
1 | #include "mouse_wheel.h" | 1 | #include "mouse_wheel.h" |
2 | #include "../actions/zoom.h" | 2 | #include "../actions/zoom.h" |
3 | #include "../../view/state0.h" | ||
3 | #include <GL/glut.h> | 4 | #include <GL/glut.h> |
5 | #include <math.h> | ||
6 | |||
7 | #define S state0 | ||
4 | 8 | ||
5 | void | 9 | void |
6 | mouse_wheel (int button, int dir, int x, int y) | 10 | mouse_wheel (int button, int dir, int x, int y) |
7 | { | 11 | { |
8 | /* | 12 | /* |
9 | * Get the current coordinates, substract some fixed amount and | 13 | * Start at the origin of the window. An alternative would be to |
10 | * then perform the zoom. | 14 | * start at the position of the mouse. Calculate a bounding box |
15 | * that will be the selection and zoom to it. | ||
11 | */ | 16 | */ |
12 | GLint viewport[4]; | 17 | double width = fabs(S.ortho.max_x - S.ortho.min_x); |
13 | glGetIntegerv (GL_VIEWPORT, viewport); | 18 | double height = fabs(S.ortho.max_y - S.ortho.min_y); |
14 | 19 | ||
15 | /* | 20 | /* |
16 | * The step size could be either a fixed number of pixels or a percentage. | 21 | * Box the smaller of the two dimensions. |
17 | */ | 22 | */ |
18 | // int step = 5; | 23 | double box = 0.0; |
19 | int step = (viewport[3] - viewport[1]) * 0.10; | 24 | if (width <= height) |
25 | box = width; | ||
26 | else | ||
27 | box = height; | ||
20 | 28 | ||
21 | /* | 29 | /* |
22 | * Not that the focus of the zoom is currently the center of the | 30 | * The step size could be either a fixed number of pixels or a |
23 | * window but could alternatively be the mouse pointer's position. | 31 | * percentage. Here we take 10% of the size of the box. |
24 | */ | 32 | */ |
33 | double step = box * 0.10; | ||
34 | |||
35 | double x1 = 0.0; | ||
36 | double y1 = 0.0; | ||
37 | double x2 = 0.0; | ||
38 | double y2 = 0.0; | ||
39 | |||
40 | if (width < height) | ||
41 | { | ||
42 | x1 = S.ortho.min_x; | ||
43 | x2 = S.ortho.max_x; | ||
44 | y1 = ((S.ortho.max_y + S.ortho.min_y) / 2.0) - (0.5 * width); | ||
45 | y2 = ((S.ortho.max_y + S.ortho.min_y) / 2.0) + (0.5 * width); | ||
46 | } | ||
47 | else if (width > height) | ||
48 | { | ||
49 | x1 = ((S.ortho.max_x + S.ortho.min_x) / 2.0) - (0.5 * height); | ||
50 | x2 = ((S.ortho.max_x + S.ortho.min_x) / 2.0) + (0.5 * height); | ||
51 | y1 = S.ortho.min_y; | ||
52 | y2 = S.ortho.max_y; | ||
53 | } | ||
54 | else | ||
55 | { | ||
56 | x1 = S.ortho.min_x; | ||
57 | x2 = S.ortho.max_x; | ||
58 | y1 = S.ortho.min_y; | ||
59 | y2 = S.ortho.max_y; | ||
60 | } | ||
25 | 61 | ||
26 | // Zoom in | 62 | // Zoom in |
27 | if (dir > 0) | 63 | if (dir > 0) |
28 | { | 64 | { |
29 | zoom (step, | 65 | zoom (x1 + step, y1 + step, x2 - step, y2 - step); |
30 | step, | ||
31 | viewport[3] - step, | ||
32 | viewport[3] - step); | ||
33 | } | 66 | } |
34 | 67 | ||
35 | // Zoom out | 68 | // Zoom out |
36 | else | 69 | else |
37 | { | 70 | { |
38 | zoom (-step, | 71 | zoom (x1 - step, y1 - step, x2 + step, y2 + step); |
39 | -step, | ||
40 | viewport[3] + step, | ||
41 | viewport[3] + step); | ||
42 | } | 72 | } |
43 | 73 | ||
44 | return; | 74 | 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 @@ | |||
3 | #include "../actions/set_ortho.h" | 3 | #include "../actions/set_ortho.h" |
4 | #include "reshape.h" | 4 | #include "reshape.h" |
5 | #include <GL/glut.h> | 5 | #include <GL/glut.h> |
6 | #include <math.h> | ||
7 | #include <stdio.h> | ||
6 | 8 | ||
7 | #define S state0 | 9 | #define S state0 |
8 | 10 | ||
@@ -13,26 +15,60 @@ reshape (int w, int h) | |||
13 | glLoadIdentity (); | 15 | glLoadIdentity (); |
14 | 16 | ||
15 | /* | 17 | /* |
16 | * This scaling produces an odd effect when the coordinates are not | 18 | * Scale the zoom region to the aspect ratio of the window. |
17 | * centered at 0,0. When 0,0 is the lower left rather than the | ||
18 | * center this reshape is a bit unnatural since the image is not | ||
19 | * centered in the middle of the window. | ||
20 | */ | 19 | */ |
21 | 20 | if (S.zoom.active) | |
22 | if (w <= h) | ||
23 | { | 21 | { |
24 | S.ortho.min_x = S.ortho_min; | 22 | if (w >= h) |
25 | S.ortho.max_x = S.ortho_max; | 23 | { |
26 | S.ortho.min_y = S.ortho_min * (double) h / (double) w; | 24 | double scale |
27 | S.ortho.max_y = S.ortho_max * (double) h / (double) w; | 25 | = ( ( (S.zoom.coords[1] - S.zoom.coords[0]) * ((double) w / (double) h) ) |
26 | - (S.zoom.coords[1] - S.zoom.coords[0]) ) | ||
27 | * 0.5; | ||
28 | |||
29 | S.ortho.min_x = S.zoom.coords[0] - scale; | ||
30 | S.ortho.max_x = S.zoom.coords[1] + scale; | ||
31 | S.ortho.min_y = S.zoom.coords[2]; | ||
32 | S.ortho.max_y = S.zoom.coords[3]; | ||
33 | } | ||
34 | else | ||
35 | { | ||
36 | double scale | ||
37 | = ( ( (S.zoom.coords[3] - S.zoom.coords[2]) * ((double) h / (double) w) ) | ||
38 | - (S.zoom.coords[3] - S.zoom.coords[2]) ) | ||
39 | * 0.5; | ||
40 | |||
41 | S.ortho.min_x = S.zoom.coords[0]; | ||
42 | S.ortho.max_x = S.zoom.coords[1]; | ||
43 | S.ortho.min_y = S.zoom.coords[2] - scale; | ||
44 | S.ortho.max_y = S.zoom.coords[3] + scale; | ||
45 | } | ||
28 | } | 46 | } |
29 | else | 47 | |
48 | else | ||
30 | { | 49 | { |
31 | S.ortho.min_x = S.ortho_min * (double) w / (double) h; | 50 | /* |
32 | S.ortho.max_x = S.ortho_max * (double) w / (double) h; | 51 | * This scaling produces an odd effect when the coordinates are |
33 | S.ortho.min_y = S.ortho_min; | 52 | * not centered at 0,0. When 0,0 is the lower left rather than |
34 | S.ortho.max_y = S.ortho_max; | 53 | * the center this reshape is a bit unnatural since the image is |
35 | } | 54 | * not centered in the middle of the window. Try chaning this |
55 | * to use the method used above for the zoom region scaling. | ||
56 | */ | ||
57 | if (w <= h) | ||
58 | { | ||
59 | S.ortho.min_x = S.ortho_min; | ||
60 | S.ortho.max_x = S.ortho_max; | ||
61 | S.ortho.min_y = S.ortho_min * (double) h / (double) w; | ||
62 | S.ortho.max_y = S.ortho_max * (double) h / (double) w; | ||
63 | } | ||
64 | else | ||
65 | { | ||
66 | S.ortho.min_x = S.ortho_min * (double) w / (double) h; | ||
67 | S.ortho.max_x = S.ortho_max * (double) w / (double) h; | ||
68 | S.ortho.min_y = S.ortho_min; | ||
69 | S.ortho.max_y = S.ortho_max; | ||
70 | } | ||
71 | } | ||
36 | 72 | ||
37 | set_ortho (); | 73 | set_ortho (); |
38 | 74 | ||
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) | |||
27 | const double *top; | 27 | const double *top; |
28 | const double *bottom; | 28 | const double *bottom; |
29 | 29 | ||
30 | if (S.zoom.active) | 30 | left = &S.ortho.min_x; |
31 | { | 31 | right = &S.ortho.max_x; |
32 | left = &S.zoom.coords[0]; | 32 | bottom = &S.ortho.min_y; |
33 | right = &S.zoom.coords[1]; | 33 | top = &S.ortho.max_y; |
34 | bottom = &S.zoom.coords[2]; | ||
35 | top = &S.zoom.coords[3]; | ||
36 | } | ||
37 | else | ||
38 | { | ||
39 | left = &S.ortho.min_x; | ||
40 | right = &S.ortho.max_x; | ||
41 | bottom = &S.ortho.min_y; | ||
42 | top = &S.ortho.max_y; | ||
43 | } | ||
44 | 34 | ||
45 | /* | 35 | /* |
46 | * This value should be a percentage of the world height so that it | 36 | * 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 | |||
15 | 15 | ||
16 | /* | 16 | /* |
17 | * Left, right, bottom and top of zoom region in world coordinates. | 17 | * Left, right, bottom and top of zoom region in world coordinates. |
18 | * Rubber-band zoom. | ||
18 | */ | 19 | */ |
19 | double coords[4]; | 20 | double coords[4]; |
20 | } ZOOM_INFO; | 21 | } 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 | |||
4 | zoom_info_init (ZOOM_INFO * z) | 4 | zoom_info_init (ZOOM_INFO * z) |
5 | { | 5 | { |
6 | z->active = false; | 6 | z->active = false; |
7 | 7 | z->coords[0] = 0.0; | |
8 | z->coords[1] = 0.0; | ||
9 | z->coords[2] = 0.0; | ||
10 | z->coords[3] = 0.0; | ||
11 | |||
8 | return; | 12 | return; |
9 | } | 13 | } |