manipulatedFrame.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 
3  Copyright (C) 2002-2014 Gilles Debunne. All rights reserved.
4 
5  This file is part of the QGLViewer library version 2.6.3.
6 
7  http://www.libqglviewer.com - contact@libqglviewer.com
8 
9  This file may be used under the terms of the GNU General Public License
10  versions 2.0 or 3.0 as published by the Free Software Foundation and
11  appearing in the LICENSE file included in the packaging of this file.
12  In addition, as a special exception, Gilles Debunne gives you certain
13  additional rights, described in the file GPL_EXCEPTION in this package.
14 
15  libQGLViewer uses dual licensing. Commercial/proprietary software must
16  purchase a libQGLViewer Commercial License.
17 
18  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
19  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 
21 *****************************************************************************/
22 
23 #include "domUtils.h"
24 #include "manipulatedFrame.h"
25 #include "manipulatedCameraFrame.h"
26 #include "qglviewer.h"
27 #include "camera.h"
28 
29 #include <cstdlib>
30 
31 #include <QMouseEvent>
32 
33 using namespace qglviewer;
34 using namespace std;
35 
44  : action_(QGLViewer::NO_MOUSE_ACTION), keepsGrabbingMouse_(false)
45 {
46  // #CONNECTION# initFromDOMElement and accessor docs
51  setZoomSensitivity(1.0);
52 
53  isSpinning_ = false;
54  previousConstraint_ = NULL;
55 
56  connect(&spinningTimer_, SIGNAL(timeout()), SLOT(spinUpdate()));
57 }
58 
61 {
62  Frame::operator=(mf);
63 
69 
70  mouseSpeed_ = 0.0;
71  dirIsFixed_ = false;
72  keepsGrabbingMouse_ = false;
74 
75  return *this;
76 }
77 
80  : Frame(mf), MouseGrabber()
81 {
82  (*this)=mf;
83 }
84 
86 
93 void ManipulatedFrame::checkIfGrabsMouse(int x, int y, const Camera* const camera)
94 {
95  const int thresold = 10;
96  const Vec proj = camera->projectedCoordinatesOf(position());
97  setGrabsMouse(keepsGrabbingMouse_ || ((fabs(x-proj.x) < thresold) && (fabs(y-proj.y) < thresold)));
98 }
99 
101 // S t a t e s a v i n g a n d r e s t o r i n g //
103 
116 QDomElement ManipulatedFrame::domElement(const QString& name, QDomDocument& document) const
117 {
118  QDomElement e = Frame::domElement(name, document);
119  QDomElement mp = document.createElement("ManipulatedParameters");
120  mp.setAttribute("rotSens", QString::number(rotationSensitivity()));
121  mp.setAttribute("transSens", QString::number(translationSensitivity()));
122  mp.setAttribute("spinSens", QString::number(spinningSensitivity()));
123  mp.setAttribute("wheelSens", QString::number(wheelSensitivity()));
124  mp.setAttribute("zoomSens", QString::number(zoomSensitivity()));
125  e.appendChild(mp);
126  return e;
127 }
128 
138 void ManipulatedFrame::initFromDOMElement(const QDomElement& element)
139 {
140  // Not called since it would set constraint() and referenceFrame() to NULL.
141  // *this = ManipulatedFrame();
142  Frame::initFromDOMElement(element);
143 
144  stopSpinning();
145 
146  QDomElement child=element.firstChild().toElement();
147  while (!child.isNull())
148  {
149  if (child.tagName() == "ManipulatedParameters")
150  {
151  // #CONNECTION# constructor default values and accessor docs
152  setRotationSensitivity (DomUtils::qrealFromDom(child, "rotSens", 1.0));
153  setTranslationSensitivity(DomUtils::qrealFromDom(child, "transSens", 1.0));
154  setSpinningSensitivity (DomUtils::qrealFromDom(child, "spinSens", 0.3));
155  setWheelSensitivity (DomUtils::qrealFromDom(child, "wheelSens", 1.0));
156  setZoomSensitivity (DomUtils::qrealFromDom(child, "zoomSens", 1.0));
157  }
158  child = child.nextSibling().toElement();
159  }
160 }
161 
162 
164 // M o u s e h a n d l i n g //
166 
175 {
177 }
178 
183 void ManipulatedFrame::startSpinning(int updateInterval)
184 {
185  isSpinning_ = true;
186  spinningTimer_.start(updateInterval);
187 }
188 
192 {
194 }
195 
196 /* spin() and spinUpdate() differ since spin can be used by itself (for instance by
197  QGLViewer::SCREEN_ROTATE) without a spun emission. Much nicer to use the spinningQuaternion() and
198  hence spin() for these incremental updates. Nothing special to be done for continuous spinning
199  with this design. */
201 {
202  spin();
203  Q_EMIT spun();
204 }
205 
206 #ifndef DOXYGEN
207 
208 void ManipulatedFrame::startAction(int ma, bool withConstraint)
209 {
211 
212  // #CONNECTION# manipulatedFrame::wheelEvent, manipulatedCameraFrame::wheelEvent and mouseReleaseEvent()
213  // restore previous constraint
214  if (withConstraint)
215  previousConstraint_ = NULL;
216  else
217  {
219  setConstraint(NULL);
220  }
221 
222  switch (action_)
223  {
224  case QGLViewer::ROTATE:
226  mouseSpeed_ = 0.0;
227  stopSpinning();
228  break;
229 
231  dirIsFixed_ = false;
232  break;
233 
234  default:
235  break;
236  }
237 }
238 
241 void ManipulatedFrame::computeMouseSpeed(const QMouseEvent* const e)
242 {
243  const QPoint delta = (e->pos() - prevPos_);
244  const qreal dist = sqrt(qreal(delta.x()*delta.x() + delta.y()*delta.y()));
245  delay_ = last_move_time.restart();
246  if (delay_ == 0)
247  // Less than a millisecond: assume delay = 1ms
248  mouseSpeed_ = dist;
249  else
250  mouseSpeed_ = dist/delay_;
251 }
252 
255 int ManipulatedFrame::mouseOriginalDirection(const QMouseEvent* const e)
256 {
257  static bool horiz = true; // Two simultaneous manipulatedFrame require two mice !
258 
259  if (!dirIsFixed_)
260  {
261  const QPoint delta = e->pos() - pressPos_;
262  dirIsFixed_ = abs(delta.x()) != abs(delta.y());
263  horiz = abs(delta.x()) > abs(delta.y());
264  }
265 
266  if (dirIsFixed_)
267  if (horiz)
268  return 1;
269  else
270  return -1;
271  else
272  return 0;
273 }
274 
275 qreal ManipulatedFrame::deltaWithPrevPos(QMouseEvent* const event, Camera* const camera) const {
276  qreal dx = qreal(event->x() - prevPos_.x()) / camera->screenWidth();
277  qreal dy = qreal(event->y() - prevPos_.y()) / camera->screenHeight();
278 
279  qreal value = fabs(dx) > fabs(dy) ? dx : dy;
280  return value * zoomSensitivity();
281 }
282 
283 qreal ManipulatedFrame::wheelDelta(const QWheelEvent* event) const {
284  static const qreal WHEEL_SENSITIVITY_COEF = 8E-4;
285  return event->delta() * wheelSensitivity() * WHEEL_SENSITIVITY_COEF;
286 }
287 
288 void ManipulatedFrame::zoom(qreal delta, const Camera * const camera) {
289  Vec trans(0.0, 0.0, (camera->position() - position()).norm() * delta);
290 
291  trans = camera->frame()->orientation().rotate(trans);
292  if (referenceFrame())
293  trans = referenceFrame()->transformOf(trans);
294  translate(trans);
295 }
296 
297 #endif // DOXYGEN
298 
305 void ManipulatedFrame::mousePressEvent(QMouseEvent* const event, Camera* const camera)
306 {
307  Q_UNUSED(camera);
308 
309  if (grabsMouse())
310  keepsGrabbingMouse_ = true;
311 
312  // #CONNECTION setMouseBinding
313  // action_ should no longer possibly be NO_MOUSE_ACTION since this value is not inserted in mouseBinding_
314  //if (action_ == QGLViewer::NO_MOUSE_ACTION)
315  //event->ignore();
316 
317  prevPos_ = pressPos_ = event->pos();
318 }
319 
329 void ManipulatedFrame::mouseMoveEvent(QMouseEvent* const event, Camera* const camera)
330 {
331  switch (action_)
332  {
334  {
335  const QPoint delta = event->pos() - prevPos_;
336  Vec trans(delta.x(), -delta.y(), 0.0);
337  // Scale to fit the screen mouse displacement
338  switch (camera->type())
339  {
340  case Camera::PERSPECTIVE :
341  trans *= 2.0 * tan(camera->fieldOfView()/2.0) * fabs((camera->frame()->coordinatesOf(position())).z) / camera->screenHeight();
342  break;
343  case Camera::ORTHOGRAPHIC :
344  {
345  GLdouble w,h;
346  camera->getOrthoWidthHeight(w, h);
347  trans[0] *= 2.0 * w / camera->screenWidth();
348  trans[1] *= 2.0 * h / camera->screenHeight();
349  break;
350  }
351  }
352  // Transform to world coordinate system.
353  trans = camera->frame()->orientation().rotate(translationSensitivity()*trans);
354  // And then down to frame
355  if (referenceFrame()) trans = referenceFrame()->transformOf(trans);
356  translate(trans);
357  break;
358  }
359 
360  case QGLViewer::ZOOM:
361  {
362  zoom(deltaWithPrevPos(event, camera), camera);
363  break;
364  }
365 
367  {
368  Vec trans = camera->projectedCoordinatesOf(position());
369 
370  const qreal prev_angle = atan2(prevPos_.y()-trans[1], prevPos_.x()-trans[0]);
371  const qreal angle = atan2(event->y()-trans[1], event->x()-trans[0]);
372 
373  const Vec axis = transformOf(camera->frame()->inverseTransformOf(Vec(0.0, 0.0, -1.0)));
374  Quaternion rot(axis, angle-prev_angle);
375  //#CONNECTION# These two methods should go together (spinning detection and activation)
376  computeMouseSpeed(event);
378  spin();
379  break;
380  }
381 
383  {
384  Vec trans;
385  int dir = mouseOriginalDirection(event);
386  if (dir == 1)
387  trans.setValue(event->x() - prevPos_.x(), 0.0, 0.0);
388  else if (dir == -1)
389  trans.setValue(0.0, prevPos_.y() - event->y(), 0.0);
390 
391  switch (camera->type())
392  {
393  case Camera::PERSPECTIVE :
394  trans *= 2.0 * tan(camera->fieldOfView()/2.0) * fabs((camera->frame()->coordinatesOf(position())).z) / camera->screenHeight();
395  break;
396  case Camera::ORTHOGRAPHIC :
397  {
398  GLdouble w,h;
399  camera->getOrthoWidthHeight(w, h);
400  trans[0] *= 2.0 * w / camera->screenWidth();
401  trans[1] *= 2.0 * h / camera->screenHeight();
402  break;
403  }
404  }
405  // Transform to world coordinate system.
406  trans = camera->frame()->orientation().rotate(translationSensitivity()*trans);
407  // And then down to frame
408  if (referenceFrame())
409  trans = referenceFrame()->transformOf(trans);
410 
411  translate(trans);
412  break;
413  }
414 
415  case QGLViewer::ROTATE:
416  {
417  Vec trans = camera->projectedCoordinatesOf(position());
418  Quaternion rot = deformedBallQuaternion(event->x(), event->y(), trans[0], trans[1], camera);
419  trans = Vec(-rot[0], -rot[1], -rot[2]);
420  trans = camera->frame()->orientation().rotate(trans);
421  trans = transformOf(trans);
422  rot[0] = trans[0];
423  rot[1] = trans[1];
424  rot[2] = trans[2];
425  //#CONNECTION# These two methods should go together (spinning detection and activation)
426  computeMouseSpeed(event);
428  spin();
429  break;
430  }
431 
435  case QGLViewer::ROLL:
436  case QGLViewer::DRIVE:
438  // These MouseAction values make no sense for a manipulatedFrame
439  break;
440 
442  // Possible when the ManipulatedFrame is a MouseGrabber. This method is then called without startAction
443  // because of mouseTracking.
444  break;
445  }
446 
448  {
449  prevPos_ = event->pos();
450  Q_EMIT manipulated();
451  }
452 }
453 
461 void ManipulatedFrame::mouseReleaseEvent(QMouseEvent* const event, Camera* const camera)
462 {
463  Q_UNUSED(event);
464  Q_UNUSED(camera);
465 
466  keepsGrabbingMouse_ = false;
467 
470 
473 
475 }
476 
482 void ManipulatedFrame::mouseDoubleClickEvent(QMouseEvent* const event, Camera* const camera)
483 {
484  if (event->modifiers() == Qt::NoModifier)
485  switch (event->button())
486  {
487  case Qt::LeftButton: alignWithFrame(camera->frame()); break;
488  case Qt::RightButton: projectOnLine(camera->position(), camera->viewDirection()); break;
489  default: break;
490  }
491 }
492 
497 void ManipulatedFrame::wheelEvent(QWheelEvent* const event, Camera* const camera)
498 {
499  //#CONNECTION# QGLViewer::setWheelBinding
500  if (action_ == QGLViewer::ZOOM)
501  {
502  zoom(wheelDelta(event), camera);
503  Q_EMIT manipulated();
504  }
505 
506  // #CONNECTION# startAction should always be called before
509 
511 }
512 
513 
515 
520 static qreal projectOnBall(qreal x, qreal y)
521 {
522  // If you change the size value, change angle computation in deformedBallQuaternion().
523  const qreal size = 1.0;
524  const qreal size2 = size*size;
525  const qreal size_limit = size2*0.5;
526 
527  const qreal d = x*x + y*y;
528  return d < size_limit ? sqrt(size2 - d) : size_limit/sqrt(d);
529 }
530 
531 #ifndef DOXYGEN
532 
534 Quaternion ManipulatedFrame::deformedBallQuaternion(int x, int y, qreal cx, qreal cy, const Camera* const camera)
535 {
536  // Points on the deformed ball
537  qreal px = rotationSensitivity() * (prevPos_.x() - cx) / camera->screenWidth();
538  qreal py = rotationSensitivity() * (cy - prevPos_.y()) / camera->screenHeight();
539  qreal dx = rotationSensitivity() * (x - cx) / camera->screenWidth();
540  qreal dy = rotationSensitivity() * (cy - y) / camera->screenHeight();
541 
542  const Vec p1(px, py, projectOnBall(px, py));
543  const Vec p2(dx, dy, projectOnBall(dx, dy));
544  // Approximation of rotation angle
545  // Should be divided by the projectOnBall size, but it is 1.0
546  const Vec axis = cross(p2,p1);
547  const qreal angle = 5.0 * asin(sqrt(axis.squaredNorm() / p1.squaredNorm() / p2.squaredNorm()));
548  return Quaternion(axis, angle);
549 }
550 #endif // DOXYGEN
virtual void initFromDOMElement(const QDomElement &element)
Vec position() const
Definition: frame.cpp:537
Vec inverseTransformOf(const Vec &src) const
Definition: frame.cpp:856
A ManipulatedFrame is a Frame that can be rotated and translated using the mouse. ...
qreal fieldOfView() const
Definition: camera.h:170
void setZoomSensitivity(qreal sensitivity)
void setGrabsMouse(bool grabs)
Definition: mouseGrabber.h:183
Quaternion deformedBallQuaternion(int x, int y, qreal cx, qreal cy, const Camera *const camera)
virtual void mouseReleaseEvent(QMouseEvent *const event, Camera *const camera)
virtual void checkIfGrabsMouse(int x, int y, const Camera *const camera)
Vec projectedCoordinatesOf(const Vec &src, const Frame *frame=NULL) const
Definition: camera.cpp:1584
void setRotationSensitivity(qreal sensitivity)
Vec transformOf(const Vec &src) const
Definition: frame.cpp:843
void setWheelSensitivity(qreal sensitivity)
void setSpinningSensitivity(qreal sensitivity)
qreal squaredNorm() const
Definition: vec.h:332
Vec position() const
Definition: camera.cpp:1200
virtual QDomElement domElement(const QString &name, QDomDocument &document) const
Definition: frame.cpp:994
Vec rotate(const Vec &v) const
Definition: quaternion.cpp:76
int screenWidth() const
Definition: camera.h:190
qreal deltaWithPrevPos(QMouseEvent *const event, Camera *const camera) const
void setConstraint(Constraint *const constraint)
Definition: frame.h:361
Abstract class for objects that grab mouse focus in a QGLViewer.
Definition: mouseGrabber.h:130
bool grabsMouse() const
Definition: mouseGrabber.h:179
Type type() const
Definition: camera.h:158
ManipulatedCameraFrame * frame() const
Definition: camera.h:334
virtual void mousePressEvent(QMouseEvent *const event, Camera *const camera)
qreal y
Definition: vec.h:81
void rotate(Quaternion &q)
Definition: frame.cpp:376
The Vec class represents 3D positions and 3D vectors.
Definition: vec.h:65
virtual void getOrthoWidthHeight(GLdouble &halfWidth, GLdouble &halfHeight) const
Definition: camera.cpp:324
virtual void wheelEvent(QWheelEvent *const event, Camera *const camera)
void zoom(qreal delta, const Camera *const camera)
void setValue(qreal X, qreal Y, qreal Z)
Definition: vec.h:125
qreal wheelDelta(const QWheelEvent *event) const
virtual void mouseDoubleClickEvent(QMouseEvent *const event, Camera *const camera)
void projectOnLine(const Vec &origin, const Vec &direction)
Definition: frame.cpp:1133
static qreal qrealFromDom(const QDomElement &e, const QString &attribute, qreal defValue)
Definition: domUtils.h:44
int screenHeight() const
Definition: camera.h:195
virtual QDomElement domElement(const QString &name, QDomDocument &document) const
static qreal projectOnBall(qreal x, qreal y)
void setSpinningQuaternion(const Quaternion &spinningQuaternion)
A versatile 3D OpenGL viewer based on QGLWidget.
Definition: qglviewer.h:62
Vec coordinatesOf(const Vec &src) const
Definition: frame.cpp:702
void computeMouseSpeed(const QMouseEvent *const e)
QGLViewer::MouseAction action_
void translate(Vec &t)
Definition: frame.cpp:335
A perspective or orthographic camera.
Definition: camera.h:84
ManipulatedFrame & operator=(const ManipulatedFrame &mf)
qreal translationSensitivity() const
The Quaternion class represents 3D rotations and orientations.
Definition: quaternion.h:66
Quaternion orientation() const
Definition: frame.cpp:546
Vec viewDirection() const
Definition: camera.cpp:1220
Constraint * constraint() const
Definition: frame.h:356
void alignWithFrame(const Frame *const frame, bool move=false, qreal threshold=0.0)
Definition: frame.cpp:1055
The Frame class represents a coordinate system, defined by a position and an orientation.
Definition: frame.h:121
int mouseOriginalDirection(const QMouseEvent *const e)
Frame & operator=(const Frame &frame)
Definition: frame.cpp:54
const Frame * referenceFrame() const
Definition: frame.h:262
Quaternion spinningQuaternion() const
virtual void mouseMoveEvent(QMouseEvent *const event, Camera *const camera)
qreal x
Definition: vec.h:81
virtual void startAction(int ma, bool withConstraint=true)
virtual void initFromDOMElement(const QDomElement &element)
Definition: frame.cpp:1011
virtual void startSpinning(int updateInterval)
void setTranslationSensitivity(qreal sensitivity)


octovis
Author(s): Kai M. Wurm , Armin Hornung
autogenerated on Wed Jun 5 2019 19:26:39