Developer Documentation
QtExaminerViewer.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 //=============================================================================
47 //
48 // CLASS QtExaminerViewer - IMPLEMENTATION
49 //
50 //=============================================================================
51 
52 
53 //== INCLUDES =================================================================
54 #include <ACG/GL/acg_glew.hh>
55 #include "QtExaminerViewer.hh"
56 
57 #include <QTimer>
58 #include <QApplication>
59 #include <QInputDialog>
60 #include <QStatusBar>
61 
62 #include "../GL/GLState.hh"
63 
64 #ifdef max
65 # undef max
66 #endif
67 
68 
69 //== NAMESPACES ===============================================================
70 
71 
72 namespace ACG {
73 namespace QtWidgets {
74 
75 
76 //== IMPLEMENTATION ==========================================================
77 
78 
80  const char* _name,
81  QStatusBar *_statusBar,
82  const QGLFormat* _format,
83  const QtBaseViewer* _share,
84  Options _options ) :
85  QtBaseViewer(_parent, _name, _statusBar, _format, _share, _options)
86 {
87 
88  // timer for animation
89  timer_ = new QTimer( this );
90  connect( timer_, SIGNAL(timeout()), this, SLOT( slotAnimation()) );
91 
92  allowRotation_ = true;
93 
94  //default wheel zoom factors
95  wZoomFactor_ = 1.0;
96  wZoomFactorShift_ = 0.2;
97 }
98 
99 
100 //-----------------------------------------------------------------------------
101 
102 
103 void
105 {
106  switch (_event->type())
107  {
108  case QEvent::MouseButtonPress:
109  {
110  // shift key -> set rotation center
111  if (_event->modifiers() & Qt::ShiftModifier)
112  {
113  Vec3d c;
114  if (fast_pick(_event->pos(), c))
115  {
116  trackball_center_ = c;
117  trackball_radius_ = std::max(scene_radius_, (c-glState().eye()).norm()*0.9f);
118  }
119  }
120 
121  lastPoint_hitSphere_ = mapToSphere( lastPoint2D_=_event->pos(),
122  lastPoint3D_ );
123  isRotating_ = true;
124  timer_->stop();
125 
126 
127  break;
128  }
129 
130 
131  case QEvent::MouseButtonDblClick:
132  {
133  if (allowRotation_)
134  flyTo(_event->pos(), _event->button()==Qt::MidButton);
135  break;
136  }
137 
138 
139  case QEvent::MouseMove:
140  {
141  double factor = 1.0;
142 
143  if (_event->modifiers() == Qt::ShiftModifier)
144  factor = wZoomFactorShift_;
145 
146  // mouse button should be pressed
147  if (_event->buttons() & (Qt::LeftButton | Qt::MidButton))
148  {
149  QPoint newPoint2D = _event->pos();
150 
151  if ( (newPoint2D.x()<0) || (newPoint2D.x() > (int)glWidth()) ||
152  (newPoint2D.y()<0) || (newPoint2D.y() > (int)glHeight()) )
153  return;
154 
155  double value_y;
156  Vec3d newPoint3D;
157  bool newPoint_hitSphere = mapToSphere( newPoint2D, newPoint3D );
158 
159  makeCurrent();
160 
161  // move in z direction
162  if ( (_event->buttons() & Qt::LeftButton) &&
163  (_event->buttons() & Qt::MidButton))
164  {
165  switch (projectionMode())
166  {
168  {
169  value_y = scene_radius_ * ((newPoint2D.y() - lastPoint2D_.y())) * 3.0 / (double) glHeight();
170  translate( Vec3d(0.0, 0.0, value_y * factor ) );
171  updateGL();
172  break;
173  }
174 
176  {
177  value_y = ((newPoint2D.y() - lastPoint2D_.y())) * orthoWidth_ / (double) glHeight();
178  orthoWidth_ -= value_y * factor;
180  updateGL();
181  break;
182  }
183  }
184  }
185 
186  // move in x,y direction
187  else if (_event->buttons() & Qt::MidButton)
188  {
189  double value_x;
190  value_x = scene_radius_ * ((newPoint2D.x() - lastPoint2D_.x())) * 2.0 / (double) glWidth();
191  value_y = scene_radius_ * ((newPoint2D.y() - lastPoint2D_.y())) * 2.0 / (double) glHeight();
192  translate( Vec3d(value_x * factor , -value_y * factor , 0.0) );
193  }
194 
195  // rotate
196  else if (allowRotation_ && (_event->buttons() & Qt::LeftButton) )
197  {
198  Vec3d axis(1.0,0.0,0.0);
199  double angle(0.0);
200 
201  if ( lastPoint_hitSphere_ ) {
202 
203  if ( ( newPoint_hitSphere = mapToSphere( newPoint2D,
204  newPoint3D ) ) ) {
205  axis = lastPoint3D_ % newPoint3D;
206  double cos_angle = ( lastPoint3D_ | newPoint3D );
207  if ( fabs(cos_angle) < 1.0 ) {
208  angle = acos( cos_angle ) * 180.0 / M_PI * factor ;
209  angle *= 2.0; // inventor rotation
210  }
211  }
212 
213  rotate(axis, angle);
214 
215  }
216 
217  lastRotationAxis_ = axis;
218  lastRotationAngle_ = angle;
219  }
220 
221  lastPoint2D_ = newPoint2D;
222  lastPoint3D_ = newPoint3D;
223  lastPoint_hitSphere_ = newPoint_hitSphere;
224 
225  updateGL();
226  lastMoveTime_.restart();
227  }
228  break;
229  }
230 
231 
232 
233  case QEvent::MouseButtonRelease:
234  {
235  lastPoint_hitSphere_ = false;
236 
237  // continue rotation ?
238  if ( isRotating_ &&
239  (_event->button() == Qt::LeftButton) &&
240  (!(_event->buttons() & Qt::MidButton)) &&
241  (lastMoveTime_.elapsed() < 10) &&
242  animation() )
243  timer_->start(0);
244  break;
245  }
246 
247  default: // avoid warning
248  break;
249  }
250 
251 
252  // sync views
253  emit(signalSetView(glstate_->modelview(), glstate_->inverse_modelview()));
254 }
255 
256 
257 //-----------------------------------------------------------------------------
258 
259 
260 void
262 {
263  switch (_event->type()) {
264  case QEvent::MouseButtonPress: {
265  lastPoint_hitSphere_ = mapToSphere(lastPoint2D_ = _event->pos(), lastPoint3D_);
266  isRotating_ = true;
267  timer_->stop();
268  break;
269  }
270 
271  case QEvent::MouseMove: {
272 
273  // rotate lights
274  if (_event->buttons() & Qt::LeftButton) {
275  QPoint newPoint2D = _event->pos();
276 
277  if ((newPoint2D.x() < 0) || (newPoint2D.x() > (int) glWidth()) || (newPoint2D.y() < 0)
278  || (newPoint2D.y() > (int) glHeight()))
279  return;
280 
281  Vec3d newPoint3D;
282  bool newPoint_hitSphere = mapToSphere(newPoint2D, newPoint3D);
283 
284  makeCurrent();
285 
286  if (lastPoint_hitSphere_) {
287  Vec3d axis(1.0, 0.0, 0.0);
288  double angle(0.0);
289 
290  if ((newPoint_hitSphere = mapToSphere(newPoint2D, newPoint3D))) {
291  axis = lastPoint3D_ % newPoint3D;
292  double cos_angle = (lastPoint3D_ | newPoint3D);
293  if (fabs(cos_angle) < 1.0) {
294  angle = acos(cos_angle) * 180.0 / M_PI;
295  angle *= 2.0;
296  }
297  }
298  rotate_lights(axis, angle);
299  }
300 
301  lastPoint2D_ = newPoint2D;
302  lastPoint3D_ = newPoint3D;
303  lastPoint_hitSphere_ = newPoint_hitSphere;
304 
305  updateGL();
306  }
307  break;
308  }
309 
310  default: // avoid warning
311  break;
312  }
313 }
314 
315 
316 //-----------------------------------------------------------------------------
317 
319  return wZoomFactor_;
320 }
321 
322 //-----------------------------------------------------------------------------
323 
324 double QtExaminerViewer::wheelZoomFactorShift(){
325  return wZoomFactorShift_;
326 }
327 
328 //-----------------------------------------------------------------------------
329 
330 void QtExaminerViewer::setWheelZoomFactor(double _factor){
331  wZoomFactor_ = _factor;
332 }
333 
334 //-----------------------------------------------------------------------------
335 
336 void QtExaminerViewer::setWheelZoomFactorShift(double _factor){
337  wZoomFactorShift_ = _factor;
338 }
339 
340 //-----------------------------------------------------------------------------
341 
342 void QtExaminerViewer::viewWheelEvent( QWheelEvent* _event)
343 {
344  double factor = wZoomFactor_;
345 
346  if (_event->modifiers() == Qt::ShiftModifier)
347  factor = wZoomFactorShift_;
348 
349  switch (projectionMode())
350  {
352  {
353  double d = -(double)_event->delta() / 120.0 * 0.2 * factor * trackball_radius_/3;
354  translate( Vec3d(0.0, 0.0, d) );
355  updateGL();
356  break;
357  }
358 
360  {
361  double d = (double)_event->delta() / 120.0 * 0.2 * factor * orthoWidth_;
362  orthoWidth_ += d;
364  updateGL();
365  break;
366  }
367  }
368 
369 
370  // sync views
371  emit(signalSetView(glstate_->modelview(), glstate_->inverse_modelview()));
372 }
373 
374 
375 //-----------------------------------------------------------------------------
376 
377 
378 bool QtExaminerViewer::mapToSphere(const QPoint& _v2D, Vec3d& _v3D) const
379 {
380  if ( (_v2D.x() >= 0) && (_v2D.x() < (int)glWidth()) &&
381  (_v2D.y() >= 0) && (_v2D.y() < (int)glHeight()) )
382  {
383  double x = (double)(_v2D.x() - ((double)glWidth() / 2.0)) / (double)glWidth();
384  double y = (double)(((double)glHeight() / 2.0) - _v2D.y()) / (double)glHeight();
385  double sinx = sin(M_PI * x * 0.5);
386  double siny = sin(M_PI * y * 0.5);
387  double sinx2siny2 = sinx * sinx + siny * siny;
388 
389  _v3D[0] = sinx;
390  _v3D[1] = siny;
391  _v3D[2] = sinx2siny2 < 1.0 ? sqrt(1.0 - sinx2siny2) : 0.0;
392 
393  return true;
394  }
395  else return false;
396 }
397 
398 
399 //-----------------------------------------------------------------------------
400 
401 
402 void QtExaminerViewer::slotAnimation()
403 {
404 
405  QTime t;
406  t.start();
407  makeCurrent();
408  rotate( lastRotationAxis_, lastRotationAngle_ );
409  updateGL();
410 
411  if (!isUpdateLocked()) {
412 
413  static int msecs=0, count=0;
414 
415  msecs += t.elapsed();
416  if (count==10) {
417  assert(statusbar_!=0);
418  char s[100];
419  sprintf( s, "%.3f fps", (10000.0 / (float)msecs) );
420  statusbar_->showMessage(s,2000);
421  count = msecs = 0;
422  }
423  else
424  ++count;
425  }
426 }
427 
428 
429 //=============================================================================
430 } // namespace QtWidgets
431 } // namespace ACG
432 //=============================================================================
Namespace providing different geometric functions concerning angles.
void translate(const Vec3d &trans)
translate the scene and update modelview matrix
unsigned int glWidth() const
get width of QGLWidget
void signalSetView(const GLMatrixd &_modelview, const GLMatrixd &_inverse_modelview)
set view, used for synchronizing (cf. slotSetView())
const GLMatrixd & inverse_modelview() const
get inverse modelview matrix
Definition: GLState.hh:811
GLState & glState()
get OpenGL state
virtual void viewWheelEvent(QWheelEvent *_event)
handle wheel events
bool mapToSphere(const QPoint &_p, Vec3d &_result) const
virtual trackball: map 2D screen point to unit sphere
void rotate_lights(Vec3d &_axis, double _angle)
rotete light sources
virtual void viewMouseEvent(QMouseEvent *_event)
handle mouse events
void rotate(const Vec3d &axis, double angle)
rotate the scene (around its center) and update modelview matrix
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:121
double wheelZoomFactor()
Factors for zooming with the wheel.
virtual void lightMouseEvent(QMouseEvent *_event)
handle mouse events
virtual void makeCurrent()
Makes this widget the current widget for OpenGL operations.
void updateProjectionMatrix()
updates projection matrix
virtual void updateGL()
Redraw scene. Triggers paint event for updating the view (cf. drawNow()).
ProjectionMode projectionMode() const
get current projection mode
const GLMatrixd & modelview() const
get modelview matrix
Definition: GLState.hh:791
bool animation() const
Is animation enabled?
bool fast_pick(const QPoint &_mousePos, Vec3d &_hitPoint)
unsigned int glHeight() const
get height of QGLWidget
QtExaminerViewer(QWidget *_parent=0, const char *_name=0, QStatusBar *_statusBar=0, const QGLFormat *_format=0, const QtBaseViewer *_share=0, Options _options=DefaultOptions)
Constructor.
virtual void flyTo(const QPoint &_pos, bool _move_back)
Fly to. Get closer if _move_back=false, get more distant else.