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