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
79 QtExaminerViewer::QtExaminerViewer( QWidget* _parent,
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
104 QtExaminerViewer::viewMouseEvent(QMouseEvent* _event)
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 {
167 case PERSPECTIVE_PROJECTION:
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
175 case ORTHOGRAPHIC_PROJECTION:
176 {
177 value_y = ((newPoint2D.y() - lastPoint2D_.y())) * orthoWidth_ / (double) glHeight();
178 orthoWidth_ -= value_y * factor;
179 updateProjectionMatrix();
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
261 QtExaminerViewer::lightMouseEvent(QMouseEvent* _event)
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
318 double QtExaminerViewer::wheelZoomFactor(){
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 {
351 case PERSPECTIVE_PROJECTION:
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
359 case ORTHOGRAPHIC_PROJECTION:
360 {
361 double d = (double)_event->delta() / 120.0 * 0.2 * factor * orthoWidth_;
362 orthoWidth_ += d;
363 updateProjectionMatrix();
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 //=============================================================================
ACG::QtWidgets::QtBaseViewer::fast_pick
bool fast_pick(const QPoint &_mousePos, Vec3d &_hitPoint)
Definition: QtBaseViewerPicking.cc:199
ACG::QtWidgets::QtExaminerViewer::mapToSphere
bool mapToSphere(const QPoint &_p, Vec3d &_result) const
virtual trackball: map 2D screen point to unit sphere
Definition: QtExaminerViewer.cc:378
ACG::QtWidgets::QtBaseViewer::isUpdateLocked
bool isUpdateLocked() const
Definition: QtBaseViewer.hh:268
ACG::QtWidgets::QtBaseViewer::signalSetView
void signalSetView(const GLMatrixd &_modelview, const GLMatrixd &_inverse_modelview)
set view, used for synchronizing (cf. slotSetView())
ACG::QtWidgets::QtBaseViewer::updateProjectionMatrix
void updateProjectionMatrix()
updates projection matrix
Definition: QtBaseViewer.cc:519
ACG::QtWidgets::QtBaseViewer::projectionMode
ProjectionMode projectionMode() const
get current projection mode
Definition: QtBaseViewer.hh:323
ACG
Namespace providing different geometric functions concerning angles.
Definition: BaseObjectData.hh:68
ACG::QtWidgets::QtBaseViewer::PERSPECTIVE_PROJECTION
perspective
Definition: QtBaseViewer.hh:317
ACG::QtWidgets::QtBaseViewer::glState
GLState & glState()
get OpenGL state
Definition: QtBaseViewer.hh:242
OpenMesh::VectorT
Definition: Vector11T.hh:83
ACG::QtWidgets::QtBaseViewer::makeCurrent
virtual void makeCurrent()
Makes this widget the current widget for OpenGL operations.
Definition: QtBaseViewer_qt.cc:131
ACG::QtWidgets::QtBaseViewer::animation
bool animation() const
Is animation enabled?
Definition: QtBaseViewer.hh:278
ACG::QtWidgets::QtBaseViewer::Options
Options
Definition: QtBaseViewer.hh:139
ACG::QtWidgets::QtBaseViewer::rotate
void rotate(const Vec3d &axis, double angle)
rotate the scene (around its center) and update modelview matrix
Definition: QtBaseViewer.hh:491
ACG::QtWidgets::QtBaseViewer::glWidth
unsigned int glWidth() const
get width of QGLWidget
Definition: QtBaseViewer.cc:1727
ACG::QtWidgets::QtBaseViewer::ORTHOGRAPHIC_PROJECTION
orthographic
Definition: QtBaseViewer.hh:316
ACG::GLState::inverse_modelview
const GLMatrixd & inverse_modelview() const
get inverse modelview matrix
Definition: GLState.hh:811
ACG::QtWidgets::QtBaseViewer::flyTo
virtual void flyTo(const QPoint &_pos, bool _move_back)
Fly to. Get closer if _move_back=false, get more distant else.
Definition: QtBaseViewer.cc:973
ACG::QtWidgets::QtBaseViewer
Definition: QtBaseViewer.hh:129
ACG::QtWidgets::QtBaseViewer::updateGL
virtual void updateGL()
Redraw scene. Triggers paint event for updating the view (cf. drawNow()).
Definition: QtBaseViewer.cc:781
ACG::QtWidgets::QtExaminerViewer::viewMouseEvent
virtual void viewMouseEvent(QMouseEvent *_event) override
handle mouse events
Definition: QtExaminerViewer.cc:104
ACG::QtWidgets::QtBaseViewer::rotate_lights
void rotate_lights(Vec3d &_axis, double _angle)
rotete light sources
Definition: QtBaseViewer.cc:1202
ACG::QtWidgets::QtExaminerViewer::viewWheelEvent
virtual void viewWheelEvent(QWheelEvent *_event) override
handle wheel events
Definition: QtExaminerViewer.cc:342
ACG::QtWidgets::QtExaminerViewer::wheelZoomFactor
double wheelZoomFactor()
Factors for zooming with the wheel.
Definition: QtExaminerViewer.cc:318
ACG::QtWidgets::QtExaminerViewer::lightMouseEvent
virtual void lightMouseEvent(QMouseEvent *_event) override
handle mouse events
Definition: QtExaminerViewer.cc:261
ACG::GLState::modelview
const GLMatrixd & modelview() const
get modelview matrix
Definition: GLState.hh:791
ACG::QtWidgets::QtBaseViewer::translate
void translate(const Vec3d &trans)
translate the scene and update modelview matrix
Definition: QtBaseViewer.cc:1690
ACG::QtWidgets::QtExaminerViewer::QtExaminerViewer
QtExaminerViewer(QWidget *_parent=0, const char *_name=0, QStatusBar *_statusBar=0, const QGLFormat *_format=0, const QtBaseViewer *_share=0, Options _options=DefaultOptions)
Constructor.
Definition: QtExaminerViewer.cc:79
ACG::QtWidgets::QtBaseViewer::glHeight
unsigned int glHeight() const
get height of QGLWidget
Definition: QtBaseViewer.cc:1730
ACG::Vec3d
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:121