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 //=============================================================================
Namespace providing different geometric functions concerning angles.
Vec3d right() const
get right-vector w.r.t. camera coordinates
Definition: GLState.cc:918
VectorT< signed int, 2 > Vec2i
Definition: VectorT.hh:98
T angle(T _cos_angle, T _sin_angle)
Definition: MathDefs.hh:140
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:121
double fovy() const
get field of view in y direction
Definition: GLState.cc:868
double aspect() const
get aspect ratio
Definition: GLState.cc:877