Developer Documentation

GLTrackball.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41
42
43
44 //=============================================================================
45 //
46 // CLASS GLTrackball - IMPLEMENTATION
47 //
48 //=============================================================================
49
50 //== INCLUDES =================================================================
51
52
53 #include "GLTrackball.hh"
54
55
56 //== NAMESPACES ===============================================================
57
58
59 namespace ACG {
60
61
62 //== IMPLEMENTATION ==========================================================
63
64
65 GLTrackball::
66 GLTrackball(GLState& _state)
67 : glstate_(_state),
68 center_(0,0,0) ,
69 last_point_ok_(false),
70 action_(ROTATION)
71 {
72 for (int i=0; i<10; ++i)
73 button_down_[i] = false;
74 }
75
76
77 //-----------------------------------------------------------------------------
78
79
80 void
81 GLTrackball::mouse_press(int button, int x, int y)
82 {
83 last_point_2D_ = ACG::Vec2i(x, y);
84 last_point_ok_ = map_to_sphere(last_point_2D_, last_point_3D_);
85
86 button_down_[button] = true;
87 }
88
89
90 //-----------------------------------------------------------------------------
91
92
93 void
94 GLTrackball::mouse_release(int button, int /* x */ , int /* y */ )
95 {
96 last_point_ok_ = false;
97 button_down_[button] = false;
98
99 // GLUT: button 3 or 4 -> mouse wheel clicked
100 if (button == 3)
101 zoom(0, (int)(last_point_2D_[1] - 0.05*glstate_.viewport_width()));
102 else if (button == 4)
103 zoom(0, (int)(last_point_2D_[1] + 0.05*glstate_.viewport_width()));
104 }
105
106
107 //-----------------------------------------------------------------------------
108
109
110 void
111 GLTrackball::mouse_move(int x, int y)
112 {
113 if (button_down_[0] && button_down_[1])
114 action_ = ZOOM;
115 else if (button_down_[0])
116 action_ = ROTATION;
117 else if (button_down_[1])
118 action_ = TRANSLATION;
119
120 switch (action_)
121 {
122 case ROTATION: rotation(x, y); break;
123 case TRANSLATION: translation(x, y); break;
124 case ZOOM: zoom(x, y); break;
125 }
126
127 last_point_2D_ = ACG::Vec2i(x, y);
128 last_point_ok_ = map_to_sphere(last_point_2D_, last_point_3D_);
129 }
130
131
132 //-----------------------------------------------------------------------------
133
134
135 void
136 GLTrackball::rotation(int x, int y)
137 {
138 if (last_point_ok_)
139 {
140 Vec2i new_point_2D_;
141 Vec3f new_point_3D_;
142 bool new_point_ok_;
143
144 new_point_2D_ = ACG::Vec2i(x, y);
145 new_point_ok_ = map_to_sphere(new_point_2D_, new_point_3D_);
146
147 if (new_point_ok_)
148 {
149 Vec3f axis = (last_point_3D_ % new_point_3D_);
150 float cos_angle = (last_point_3D_ | new_point_3D_);
151
152 if (fabs(cos_angle) < 1.0)
153 {
154 double angle = 2.0*acos(cos_angle) * 180.0 / M_PI;
155
156 Vec3d t = glstate_.modelview().transform_point(center_);
157 glstate_.translate(-t[0], -t[1], -t[2], MULT_FROM_LEFT);
158 glstate_.rotate(angle, axis[0], axis[1], axis[2], MULT_FROM_LEFT);
159 glstate_.translate( t[0], t[1], t[2], MULT_FROM_LEFT);
160 }
161 }
162 }
163 }
164
165
166 //-----------------------------------------------------------------------------
167
168
169 void
170 GLTrackball::translation(int x, int y)
171 {
172 double dx = double(x - last_point_2D_[0]);
173 double dy = double(y - last_point_2D_[1]);
174
175 double z = glstate_.modelview().transform_point(center_)[2];
176 double w = double(glstate_.viewport_width());
177 double h = double(glstate_.viewport_height());
178 double fovy = double(glstate_.fovy());
179 double nearpl = double(glstate_.near_plane());
180
181 double aspect = w / h;
182 double top = double(tan(fovy/2.0*M_PI/180.0) * nearpl);
183 double right = aspect*top;
184
185 glstate_.translate(-2.0*dx/w*right/nearpl*z,
186 2.0*dy/h*top/nearpl*z,
187 0.0,
188 MULT_FROM_LEFT);
189 }
190
191
192 //-----------------------------------------------------------------------------
193
194
195 void
196 GLTrackball::zoom(int /* x */ , int y)
197 {
198 double dy = double(y - last_point_2D_[1]);
199 double z = glstate_.modelview().transform_point(center_)[2];
200 double h = double(glstate_.viewport_height());
201
202 glstate_.translate(0.0,
203 0.0,
204 -2.0*dy/h*z,
205 MULT_FROM_LEFT);
206 }
207
208
209 //-----------------------------------------------------------------------------
210
211
212 bool
213 GLTrackball::map_to_sphere(const Vec2i& _point, Vec3f& _result)
214 {
215 float width = float(glstate_.viewport_width());
216 float height = float(glstate_.viewport_height());
217
218 if ( (_point[0] >= 0) && (_point[0] <= width) &&
219 (_point[1] >= 0) && (_point[1] <= height) )
220 {
221 double x = (_point[0] - 0.5*width) / width;
222 double y = (0.5*height - _point[1]) / height;
223 double sinx = sin(M_PI * x * 0.5);
224 double siny = sin(M_PI * y * 0.5);
225 double sinx2siny2 = sinx * sinx + siny * siny;
226
227 _result[0] = float(sinx);
228 _result[1] = float(siny);
229 _result[2] = sinx2siny2 < 1.0 ? float( sqrt(1.0 - sinx2siny2) ) : 0.0f;
230
231 return true;
232 }
233 else return false;
234 }
235
236
237 //=============================================================================
238 } // namespace ACG
239 //=============================================================================
ACG::GLState::fovy
double fovy() const
get field of view in y direction
Definition: GLState.cc:868
ACG::Vec2i
VectorT< signed int, 2 > Vec2i
Definition: VectorT.hh:98
ACG::GLState::aspect
double aspect() const
get aspect ratio
Definition: GLState.cc:877
ACG
Namespace providing different geometric functions concerning angles.
Definition: BaseObjectData.hh:68
OpenMesh::angle
T angle(T _cos_angle, T _sin_angle)
Definition: MathDefs.hh:140
OpenMesh::VectorT< float, 3 >
ACG::GLState::right
Vec3d right() const
get right-vector w.r.t. camera coordinates
Definition: GLState.cc:918
ACG::Vec3d
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:121