1 /************************************************************************
2 
3   Arcball rotation control.  See the original article
4 
5   	"Arcball Rotation Control"
6 	by Ken Shoemake <shoemake@graphics.cis.upenn.edu>
7 	in "Graphics Gems IV", Academic Press, 1994.
8 
9   for more details.
10 
11   $Id: arcball.cxx 427 2004-09-27 04:45:31Z garland $
12 
13  ************************************************************************/
14 
15 #include <gfx/arcball.h>
16 #include <gfx/gl.h>
17 #include <sstream>
18 
19 namespace gfx
20 {
21 
22 // Converts to points on unit sphere into a unit quaternion
quat_from_sphere(const Vec3 & from,const Vec3 & to)23 static Quat quat_from_sphere(const Vec3& from, const Vec3& to)
24 {
25     Vec3 v;
26     v[0] = from[1]*to[2] - from[2]*to[1];
27     v[1] = from[2]*to[0] - from[0]*to[2];
28     v[2] = from[0]*to[1] - from[1]*to[0];
29 
30     double s = from*to;
31 
32     return Quat(v, s);
33 }
34 
35 
proj_to_sphere(const Vec2 & mouse)36 Vec3 Arcball::proj_to_sphere(const Vec2& mouse)
37 {
38     Vec2 p = (mouse - ball_ctr) / ball_radius;
39     double mag = p*p;
40 
41     if( mag > 1.0 )
42     {
43 	double s = sqrt(mag);
44 	return Vec3(p[0]/s, p[1]/s, 0.0);
45     }
46     else
47     {
48 	return Vec3(p[0], p[1], sqrt(1-mag));
49     }
50 }
51 
update()52 void Arcball::update()
53 {
54     // constrain v_from & v_to to axes here, if necessary
55 
56     if( is_dragging )
57     {
58 	q_drag = quat_from_sphere(v_from, v_to);
59 	q_now = q_drag * q_down;
60     }
61 }
62 
Arcball()63 Arcball::Arcball()
64 {
65     ball_ctr = Vec2(0, 0);
66     ball_radius = 1.0;
67 
68     q_now = Quat::ident();
69     q_down = Quat::ident();
70     q_drag = Quat::ident();
71 
72     is_dragging = false;
73 }
74 
mouse_down(int * where,int which)75 bool Arcball::mouse_down(int *where, int which)
76 {
77     float vp[4];
78     glGetFloatv(GL_VIEWPORT, vp);
79     float W=vp[2], H=vp[3];
80 
81     if( which==1 )
82     {
83 	is_dragging = true;
84 	Vec2 v( (2.0 * where[0] - W)/W,  (H - 2.0 * where[1])/H );
85 	v_from = proj_to_sphere(v);
86 	v_to = v_from;
87     }
88 
89     return true;
90 }
91 
mouse_up(int * where,int which)92 bool Arcball::mouse_up(int *where, int which)
93 {
94     is_dragging = false;
95     q_down = q_now;
96     q_drag = Quat::ident();
97 
98     return false;
99 }
100 
mouse_drag(int * where,int * last,int which)101 bool Arcball::mouse_drag(int *where, int *last, int which)
102 {
103     float vp[4];
104     glGetFloatv(GL_VIEWPORT, vp);
105     float W=vp[2], H=vp[3];
106 
107     float diam = 2*radius;
108 
109     if( which==1 )
110     {
111 	Vec2 v( (2.0 * where[0] - W)/W,  (H - 2.0 * where[1])/H );
112 	v_to = proj_to_sphere(v);
113     }
114     else if( which==2 )
115     {
116 	trans[0] += diam * (where[0] - last[0]) / W;
117 	trans[1] += diam * (last[1] - where[1]) / H;
118     }
119     else if( which==3 )
120     {
121 	trans[2] += 0.02*diam*(where[1] - last[1]);
122     }
123     else
124 	return false;
125 
126     return true;
127 }
128 
apply_transform()129 void Arcball::apply_transform()
130 {
131     update();
132     curquat = conjugate(q_now);
133     Baseball::apply_transform();
134 }
135 
136 
update_animation()137 void Arcball::update_animation()
138 {
139 }
140 
get_transform(Vec3 & c,Vec3 & t,Quat & q)141 void Arcball::get_transform(Vec3 & c, Vec3 &t, Quat & q)
142 {
143   c = ctr;
144   t = trans;
145   q = q_now;
146 }
147 
set_transform(const Vec3 & c,const Vec3 & t,const Quat & q)148 void Arcball::set_transform(const Vec3 & c, const Vec3 &t, const Quat & q)
149 {
150   ctr = c;
151   trans = t;
152   q_now = q;
153   q_down = q;
154   q_drag = q;
155 }
156 
write(std::ostream & out)157 void Arcball::write(std::ostream& out)
158 {
159     out << "arcball ";
160     out << ball_ctr << " " << ball_radius << " ";
161     out << q_now << " " << q_down << " " << q_drag << std::endl;
162     Baseball::write(out);
163 }
164 
read(std::istream & in)165 void Arcball::read(std::istream& in)
166 {
167     std::string name;
168     in >> name;
169     in >> ball_ctr >> ball_radius;
170     in >> q_now >> q_down >> q_drag;
171     Baseball::read(in);
172 }
173 
174 } // namespace gfx
175