Developer Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 //=============================================================================
virtual void viewWheelEvent(QWheelEvent *_event)
handle wheel events
ProjectionMode projectionMode() const
get current projection mode
double wheelZoomFactor()
Factors for zooming with the wheel.
void rotate(const Vec3d &axis, double angle)
rotate the scene (around its center) and update modelview matrix
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
bool animation() const
Is animation enabled?
unsigned int glWidth() const
get width of QGLWidget
void signalSetView(const GLMatrixd &_modelview, const GLMatrixd &_inverse_modelview)
set view, used for synchronizing (cf. slotSetView())
virtual void viewMouseEvent(QMouseEvent *_event)
handle mouse events
GLState & glState()
get OpenGL state
void updateProjectionMatrix()
updates projection matrix
bool fast_pick(const QPoint &_mousePos, Vec3d &_hitPoint)
virtual void lightMouseEvent(QMouseEvent *_event)
handle mouse events
QtExaminerViewer(QWidget *_parent=0, const char *_name=0, QStatusBar *_statusBar=0, const QGLFormat *_format=0, const QtBaseViewer *_share=0, Options _options=DefaultOptions)
Constructor.
void rotate_lights(Vec3d &_axis, double _angle)
rotete light sources
virtual void flyTo(const QPoint &_pos, bool _move_back)
Fly to. Get closer if _move_back=false, get more distant else.
const GLMatrixd & inverse_modelview() const
get inverse modelview matrix
Definition: GLState.hh:814
bool mapToSphere(const QPoint &_p, Vec3d &_result) const
virtual trackball: map 2D screen point to unit sphere
const GLMatrixd & modelview() const
get modelview matrix
Definition: GLState.hh:794
void translate(const Vec3d &trans)
translate the scene and update modelview matrix
unsigned int glHeight() const
get height of QGLWidget
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:127
virtual void makeCurrent()
Makes this widget the current widget for OpenGL operations.
virtual void updateGL()
Redraw scene. Triggers paint event for updating the view (cf. drawNow()).