Subversion Repositories gelsvn

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
660 khor 1
/* ----------------------------------------------------------------------- *
2
 * This file is part of GEL, http://www.imm.dtu.dk/GEL
3
 * Copyright (C) the authors and DTU Informatics
4
 * For license and list of authors, see ../../doc/intro.pdf
5
 * ----------------------------------------------------------------------- */
6
 
7
#include <iostream>
8
#include "../GL/glew.h"
9
#include "../CGLA/CGLA.h"
10
#include "QuatTrackBall.h"
11
#include "GLViewController.h"
12
 
13
 
14
using namespace std;
15
using namespace CGLA;
16
 
17
namespace GLGraphics
18
{
19
 
20
    QuatTrackBall::QuatTrackBall(const Vec3f& _centre,
21
                                 float _eye_dist,
22
                                 unsigned _width,
23
                                 unsigned _height):
24
	centre(_centre), width(_width), height(_height),
25
	eye_dist(_eye_dist)
26
	{
27
        // This size should really be based on the distance from the center of
28
        // rotation to the point on the object underneath the mouse.  That
29
        // point would then track the mouse as closely as possible.  This is a
30
        // simple example, though, so that is left as an exercise.
31
        ballsize = 2.0f;
32
        screen_centre = Vec2i(width/2, height/2);
33
        qrot = Quatf(0.0, 0.0, 0.0, 1.0);
34
        qinc = Quatf(0.0, 0.0, 0.0, 1.0);
35
        trans = Vec2f(0.0, 0.0);
36
    }
37
 
38
    void QuatTrackBall::grab_ball(TrackBallAction act, const Vec2i& v)
39
    {
40
        if(v[0] < 0 || v[0] >= static_cast<int>(width)
41
           || v[1] < 0 || v[1] >= static_cast<int>(height))
42
            return;
43
 
44
        set_position(scalePoint(v));
45
        current_action = act;
46
    }
47
 
48
    void QuatTrackBall::roll_ball(const Vec2i& v)
49
    {
50
        if(v[0] < 0 || v[0] >= static_cast<int>(width)
51
           || v[1] < 0 || v[1] >= static_cast<int>(height))
52
            return;
53
 
54
        Vec2f w = scalePoint(v);
55
 
56
        switch (current_action)
57
        {
58
			case ROTATE_ACTION:
59
                rotate(w);
60
                break;
61
 
62
			case PAN_ACTION:
63
                pan(w);
64
                break;
65
 
66
			case ZOOM_ACTION:
67
                zoom(w);
68
                break;
69
            case NO_ACTION:
70
            default:
71
                break;
72
        }
73
        last_pos = w;
74
    }
75
 
76
    // Call this when the user does a mouse down.
77
    // Stop the trackball glide, then remember the mouse
78
    // down point (for a future rotate, pan or zoom).
79
    void QuatTrackBall::set_position(const Vec2f& _last_pos)
80
    {
81
        stop_spin();
82
        last_pos = _last_pos;
83
    }
84
 
85
    // Rotationaly spin the trackball by the current increment.
86
    // Use this to implement rotational glide.
87
    void QuatTrackBall::do_spin()
88
    {
89
        qrot = qrot*qinc;
90
    }
91
 
92
    // Cease any rotational glide by zeroing the increment.
93
    void QuatTrackBall::stop_spin()
94
    {
95
        qinc.set(0.0, 0.0, 0.0, 1.0);
96
    }
97
 
98
    void QuatTrackBall::rotate(const Vec2f& new_v)
99
    {
100
        calcRotation(new_v);
101
        do_spin();
102
    }
103
 
104
    void QuatTrackBall::pan(const Vec2f& new_v)
105
    {
106
        trans += (new_v - last_pos) * Vec2f(eye_dist);
107
    }
108
 
109
    void QuatTrackBall::zoom(const Vec2f& new_v)
110
    {
111
        eye_dist += (new_v[1] - last_pos[1]) * eye_dist;
112
        eye_dist = max(eye_dist, 0.01f);
113
    }
114
 
115
    void QuatTrackBall::calcRotation(const Vec2f& new_pos)
116
    {
117
        // Check for zero rotation
118
        if (new_pos == last_pos)
119
            qinc = Quatf(0.0f, 0.0f, 0.0f, 1.0f);
120
        else
121
        {
122
            // Form two vectors based on input points, find rotation axis
123
            Vec3f p1 = Vec3f(new_pos[0], new_pos[1], projectToSphere(new_pos));
124
            Vec3f p2 = Vec3f(last_pos[0], last_pos[1], projectToSphere(last_pos));
125
            qinc.make_rot(normalize(p1), normalize(p2));
126
            /*
127
             Vec3f q = cross(p1, p2);		// axis of rotation from p1 and p2
128
             float L = sqrt(1.0f-dot(q,q) / (dot(p1,p1) * dot(p2,p2)));
129
 
130
             q.normalize();				// q' = axis of rotation
131
             q *= sqrt((1 - L)/2);	// q' = q' * sin(phi)
132
 
133
             qinc.set(q[0],q[1],q[2],sqrt((1 + L)/2));
134
             */
135
        }
136
    }
137
 
138
    // Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
139
    // if we are away from the center of the sphere.
140
    float QuatTrackBall::projectToSphere(const Vec2f& v)
141
    {
142
#ifndef M_SQRT_2
143
        const double M_SQRT_2 = 0.707106781187;
144
#endif
145
 
146
        float d = v.length();
147
        float t = ballsize*M_SQRT_2;
148
        float z;
149
 
150
        // Inside sphere
151
        if(d < ballsize)
152
            z = sqrt(ballsize*ballsize - d*d);
153
        else if(d < t)
154
            z = 0.0;
155
        // On hyperbola
156
        else
157
            z = t*t/d;
158
 
159
        return z;
160
    }
161
 
162
    // Scales integer point to the range [-1, 1]
163
    Vec2f QuatTrackBall::scalePoint(const Vec2i& v) const
164
    {
165
        Vec2f w(v[0], v[1]);
166
        w -= Vec2f(screen_centre);
167
        w /= Vec2f(width,height);
168
        w = CGLA::v_min(Vec2f(1.0f), CGLA::v_max(Vec2f(-1), 2*w));
169
        return w;
170
    }
171
 
172
    void QuatTrackBall::get_view_param(Vec3f& eye, Vec3f& _centre, Vec3f& up) const
173
    {
174
        up  = qrot.apply_unit(Vec3f(0,1,0));
175
        Vec3f right = qrot.apply_unit(Vec3f(1,0,0));
176
        _centre = centre - up * trans[1] - right * trans[0];
177
        eye = qrot.apply_unit(Vec3f(0,0,1)*eye_dist) + _centre;
178
    }
179
 
180
 
181
    // Modify the current gl matrix by the trackball rotation and translation.
182
    void QuatTrackBall::set_gl_modelview() const
183
    {
184
        glMatrixMode(GL_MODELVIEW);
185
        glLoadIdentity();
186
        Vec3f eye;
187
        Vec3f _centre;
188
        Vec3f up;
189
        get_view_param(eye, _centre, up);
190
        gluLookAt(eye[0], eye[1], eye[2],
191
                  _centre[0], _centre[1], _centre[2], 
192
                  up[0],up[1],up[2]);
193
    }
194
 
195
    bool QuatTrackBall::is_spinning() const
196
    {
197
        static const Quatf null_quat(0,0,0,1);
198
        if(!(qinc == null_quat))
199
            return true;
200
        return false;
201
    }
202
}