manipulatedFrame.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 
3  Copyright (C) 2002-2013 Gilles Debunne. All rights reserved.
4 
5  This file is part of the QGLViewer library version 2.4.0.
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 "qglviewer.h"
26 #include "camera.h"
27 
28 #include <cstdlib>
29 
30 #if QT_VERSION >= 0x040000
31 # include <QMouseEvent>
32 #endif
33 
34 using namespace qglviewer;
35 using namespace std;
36 
45  : action_(QGLViewer::NO_MOUSE_ACTION), keepsGrabbingMouse_(false)
46 {
47  // #CONNECTION# initFromDOMElement and accessor docs
51  setWheelSensitivity(1.0f);
52 
53  isSpinning_ = false;
54  previousConstraint_ = NULL;
55 
56  connect(&spinningTimer_, SIGNAL(timeout()), SLOT(spinUpdate()));
57 }
58 
61 {
62  Frame::operator=(mf);
63 
68 
69  mouseSpeed_ = 0.0;
70  dirIsFixed_ = false;
71  keepsGrabbingMouse_ = false;
72 
73  return *this;
74 }
75 
78  : Frame(mf), MouseGrabber()
79 {
80  (*this)=mf;
81 }
82 
84 
91 void ManipulatedFrame::checkIfGrabsMouse(int x, int y, const Camera* const camera)
92 {
93  const int thresold = 10;
94  const Vec proj = camera->projectedCoordinatesOf(position());
95  setGrabsMouse(keepsGrabbingMouse_ || ((fabs(x-proj.x) < thresold) && (fabs(y-proj.y) < thresold)));
96 }
97 
99 // S t a t e s a v i n g a n d r e s t o r i n g //
101 
114 QDomElement ManipulatedFrame::domElement(const QString& name, QDomDocument& document) const
115 {
116  QDomElement e = Frame::domElement(name, document);
117  QDomElement mp = document.createElement("ManipulatedParameters");
118  mp.setAttribute("rotSens", QString::number(rotationSensitivity()));
119  mp.setAttribute("transSens", QString::number(translationSensitivity()));
120  mp.setAttribute("spinSens", QString::number(spinningSensitivity()));
121  mp.setAttribute("wheelSens", QString::number(wheelSensitivity()));
122  e.appendChild(mp);
123  return e;
124 }
125 
135 void ManipulatedFrame::initFromDOMElement(const QDomElement& element)
136 {
137  // Not called since it would set constraint() and referenceFrame() to NULL.
138  // *this = ManipulatedFrame();
139  Frame::initFromDOMElement(element);
140 
141  stopSpinning();
142 
143  QDomElement child=element.firstChild().toElement();
144  while (!child.isNull())
145  {
146  if (child.tagName() == "ManipulatedParameters")
147  {
148  // #CONNECTION# constructor default values and accessor docs
149  setRotationSensitivity (DomUtils::floatFromDom(child, "rotSens", 1.0f));
150  setTranslationSensitivity(DomUtils::floatFromDom(child, "transSens", 1.0f));
151  setSpinningSensitivity (DomUtils::floatFromDom(child, "spinSens", 0.3f));
152  setWheelSensitivity (DomUtils::floatFromDom(child, "wheelSens", 1.0f));
153  }
154  child = child.nextSibling().toElement();
155  }
156 }
157 
158 
160 // M o u s e h a n d l i n g //
162 
171 {
173 }
174 
179 void ManipulatedFrame::startSpinning(int updateInterval)
180 {
181  isSpinning_ = true;
182  spinningTimer_.start(updateInterval);
183 }
184 
188 {
190 }
191 
192 /* spin() and spinUpdate() differ since spin can be used by itself (for instance by
193  QGLViewer::SCREEN_ROTATE) without a spun emission. Much nicer to use the spinningQuaternion() and
194  hence spin() for these incremental updates. Nothing special to be done for continuous spinning
195  with this design. */
197 {
198  spin();
199  Q_EMIT spun();
200 }
201 
202 #ifndef DOXYGEN
203 
204 void ManipulatedFrame::startAction(int ma, bool withConstraint)
205 {
207 
208  // #CONNECTION# manipulatedFrame::wheelEvent, manipulatedCameraFrame::wheelEvent and mouseReleaseEvent()
209  // restore previous constraint
210  if (withConstraint)
211  previousConstraint_ = NULL;
212  else
213  {
215  setConstraint(NULL);
216  }
217 
218  switch (action_)
219  {
220  case QGLViewer::ROTATE:
222  mouseSpeed_ = 0.0;
223  stopSpinning();
224  break;
225 
227  dirIsFixed_ = false;
228  break;
229 
230  default:
231  break;
232  }
233 }
234 
237 void ManipulatedFrame::computeMouseSpeed(const QMouseEvent* const e)
238 {
239  const QPoint delta = (e->pos() - prevPos_);
240  const float dist = sqrt(static_cast<float>(delta.x()*delta.x() + delta.y()*delta.y()));
241  delay_ = last_move_time.restart();
242  if (delay_ == 0)
243  // Less than a millisecond: assume delay = 1ms
244  mouseSpeed_ = dist;
245  else
246  mouseSpeed_ = dist/delay_;
247 }
248 
251 int ManipulatedFrame::mouseOriginalDirection(const QMouseEvent* const e)
252 {
253  static bool horiz = true; // Two simultaneous manipulatedFrame require two mice !
254 
255  if (!dirIsFixed_)
256  {
257  const QPoint delta = e->pos() - pressPos_;
258  dirIsFixed_ = abs(delta.x()) != abs(delta.y());
259  horiz = abs(delta.x()) > abs(delta.y());
260  }
261 
262  if (dirIsFixed_)
263  if (horiz)
264  return 1;
265  else
266  return -1;
267  else
268  return 0;
269 }
270 #endif // DOXYGEN
271 
278 void ManipulatedFrame::mousePressEvent(QMouseEvent* const event, Camera* const camera)
279 {
280  Q_UNUSED(camera);
281 
282  if (grabsMouse())
283  keepsGrabbingMouse_ = true;
284 
285  // #CONNECTION setMouseBinding
286  // action_ should no longer possibly be NO_MOUSE_ACTION since this value is not inserted in mouseBinding_
287  //#if QT_VERSION >= 0x030000
288  //if (action_ == QGLViewer::NO_MOUSE_ACTION)
289  //event->ignore();
290  //#endif
291 
292  prevPos_ = pressPos_ = event->pos();
293 }
294 
304 void ManipulatedFrame::mouseMoveEvent(QMouseEvent* const event, Camera* const camera)
305 {
306  switch (action_)
307  {
309  {
310  const QPoint delta = event->pos() - prevPos_;
311  Vec trans(static_cast<float>(delta.x()), static_cast<float>(-delta.y()), 0.0);
312  // Scale to fit the screen mouse displacement
313  switch (camera->type())
314  {
315  case Camera::PERSPECTIVE :
316  trans *= 2.0 * tan(camera->fieldOfView()/2.0) * fabs((camera->frame()->coordinatesOf(position())).z) / camera->screenHeight();
317  break;
318  case Camera::ORTHOGRAPHIC :
319  {
320  GLdouble w,h;
321  camera->getOrthoWidthHeight(w, h);
322  trans[0] *= 2.0 * w / camera->screenWidth();
323  trans[1] *= 2.0 * h / camera->screenHeight();
324  break;
325  }
326  }
327  // Transform to world coordinate system.
328  trans = camera->frame()->orientation().rotate(translationSensitivity()*trans);
329  // And then down to frame
330  if (referenceFrame()) trans = referenceFrame()->transformOf(trans);
331  translate(trans);
332  break;
333  }
334 
335  case QGLViewer::ZOOM:
336  {
337  //#CONNECTION# wheelEvent ZOOM case
338  Vec trans(0.0, 0.0, (camera->position()-position()).norm() * (event->y() - prevPos_.y()) / camera->screenHeight());
339 
340  trans = camera->frame()->orientation().rotate(trans);
341  if (referenceFrame())
342  trans = referenceFrame()->transformOf(trans);
343  translate(trans);
344  break;
345  }
346 
348  {
349  Vec trans = camera->projectedCoordinatesOf(position());
350 
351  const double prev_angle = atan2(prevPos_.y()-trans[1], prevPos_.x()-trans[0]);
352  const double angle = atan2(event->y()-trans[1], event->x()-trans[0]);
353 
354  const Vec axis = transformOf(camera->frame()->inverseTransformOf(Vec(0.0, 0.0, -1.0)));
355  Quaternion rot(axis, angle-prev_angle);
356  //#CONNECTION# These two methods should go together (spinning detection and activation)
357  computeMouseSpeed(event);
359  spin();
360  break;
361  }
362 
364  {
365  Vec trans;
366  int dir = mouseOriginalDirection(event);
367  if (dir == 1)
368  trans.setValue(static_cast<float>(event->x() - prevPos_.x()), 0.0, 0.0);
369  else if (dir == -1)
370  trans.setValue(0.0, static_cast<float>(prevPos_.y() - event->y()), 0.0);
371 
372  switch (camera->type())
373  {
374  case Camera::PERSPECTIVE :
375  trans *= 2.0 * tan(camera->fieldOfView()/2.0) * fabs((camera->frame()->coordinatesOf(position())).z) / camera->screenHeight();
376  break;
377  case Camera::ORTHOGRAPHIC :
378  {
379  GLdouble w,h;
380  camera->getOrthoWidthHeight(w, h);
381  trans[0] *= 2.0 * w / camera->screenWidth();
382  trans[1] *= 2.0 * h / camera->screenHeight();
383  break;
384  }
385  }
386  // Transform to world coordinate system.
387  trans = camera->frame()->orientation().rotate(translationSensitivity()*trans);
388  // And then down to frame
389  if (referenceFrame())
390  trans = referenceFrame()->transformOf(trans);
391 
392  translate(trans);
393  break;
394  }
395 
396  case QGLViewer::ROTATE:
397  {
398  Vec trans = camera->projectedCoordinatesOf(position());
399  Quaternion rot = deformedBallQuaternion(event->x(), event->y(), trans[0], trans[1], camera);
400  trans = Vec(-rot[0], -rot[1], -rot[2]);
401  trans = camera->frame()->orientation().rotate(trans);
402  trans = transformOf(trans);
403  rot[0] = trans[0];
404  rot[1] = trans[1];
405  rot[2] = trans[2];
406  //#CONNECTION# These two methods should go together (spinning detection and activation)
407  computeMouseSpeed(event);
409  spin();
410  break;
411  }
412 
414  // Possible when the ManipulatedFrame is a MouseGrabber. This method is then called without startAction
415  // because of mouseTracking.
416  break;
417  }
418 
420  {
421  prevPos_ = event->pos();
423  }
424 }
425 
433 void ManipulatedFrame::mouseReleaseEvent(QMouseEvent* const event, Camera* const camera)
434 {
435  Q_UNUSED(event);
436  Q_UNUSED(camera);
437 
438  keepsGrabbingMouse_ = false;
439 
442 
445 
447 }
448 
454 void ManipulatedFrame::mouseDoubleClickEvent(QMouseEvent* const event, Camera* const camera)
455 {
456 #if QT_VERSION >= 0x040000
457  if (event->modifiers() == Qt::NoModifier)
458 #else
459  if (event->state() == Qt::NoButton)
460 #endif
461  switch (event->button())
462  {
463  case Qt::LeftButton: alignWithFrame(camera->frame()); break;
464  case Qt::RightButton: projectOnLine(camera->position(), camera->viewDirection()); break;
465  default: break;
466  }
467 }
468 
473 void ManipulatedFrame::wheelEvent(QWheelEvent* const event, Camera* const camera)
474 {
475  //#CONNECTION# QGLViewer::setWheelBinding
476  if (action_ == QGLViewer::ZOOM)
477  {
478  const float wheelSensitivityCoef = 8E-4f;
479  Vec trans(0.0, 0.0, -event->delta()*wheelSensitivity()*wheelSensitivityCoef*(camera->position()-position()).norm());
480 
481  //#CONNECTION# Cut-pasted from the mouseMoveEvent ZOOM case
482  trans = camera->frame()->orientation().rotate(trans);
483  if (referenceFrame())
484  trans = referenceFrame()->transformOf(trans);
485  translate(trans);
487  }
488 
489  // #CONNECTION# startAction should always be called before
492 
494 }
495 
496 
498 
503 static float projectOnBall(float x, float y)
504 {
505  // If you change the size value, change angle computation in deformedBallQuaternion().
506  const float size = 1.0f;
507  const float size2 = size*size;
508  const float size_limit = size2*0.5;
509 
510  const float d = x*x + y*y;
511  return d < size_limit ? sqrt(size2 - d) : size_limit/sqrt(d);
512 }
513 
514 #ifndef DOXYGEN
515 
517 Quaternion ManipulatedFrame::deformedBallQuaternion(int x, int y, float cx, float cy, const Camera* const camera)
518 {
519  // Points on the deformed ball
520  float px = rotationSensitivity() * (prevPos_.x() - cx) / camera->screenWidth();
521  float py = rotationSensitivity() * (cy - prevPos_.y()) / camera->screenHeight();
522  float dx = rotationSensitivity() * (x - cx) / camera->screenWidth();
523  float dy = rotationSensitivity() * (cy - y) / camera->screenHeight();
524 
525  const Vec p1(px, py, projectOnBall(px, py));
526  const Vec p2(dx, dy, projectOnBall(dx, dy));
527  // Approximation of rotation angle
528  // Should be divided by the projectOnBall size, but it is 1.0
529  const Vec axis = cross(p2,p1);
530  const float angle = 2.0 * asin(sqrt(axis.squaredNorm() / p1.squaredNorm() / p2.squaredNorm()));
531  return Quaternion(axis, angle);
532 }
533 #endif // DOXYGEN
void setValue(double X, double Y, double Z)
Definition: vec.h:129
virtual void initFromDOMElement(const QDomElement &element)
void setTranslationSensitivity(float sensitivity)
Vec inverseTransformOf(const Vec &src) const
Definition: frame.cpp:847
A ManipulatedFrame is a Frame that can be rotated and translated using the mouse. ...
void setWheelSensitivity(float sensitivity)
void setGrabsMouse(bool grabs)
Definition: mouseGrabber.h:191
Vec position() const
Definition: frame.h:192
static float projectOnBall(float x, float y)
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:1441
float translationSensitivity() const
Vec transformOf(const Vec &src) const
Definition: frame.cpp:834
virtual QDomElement domElement(const QString &name, QDomDocument &document) const
Definition: frame.cpp:985
Vec rotate(const Vec &v) const
Definition: quaternion.cpp:76
int screenWidth() const
Definition: camera.h:228
void setRotationSensitivity(float sensitivity)
void setConstraint(Constraint *const constraint)
Definition: frame.h:368
Abstract class for objects that grab mouse focus in a QGLViewer.
Definition: mouseGrabber.h:134
bool grabsMouse() const
Definition: mouseGrabber.h:187
Type type() const
Definition: camera.h:196
ManipulatedCameraFrame * frame() const
Definition: camera.h:372
virtual void mousePressEvent(QMouseEvent *const event, Camera *const camera)
void rotate(Quaternion &q)
Definition: frame.cpp:376
The Vec class represents 3D positions and 3D vectors.
Definition: vec.h:69
virtual void getOrthoWidthHeight(GLdouble &halfWidth, GLdouble &halfHeight) const
Definition: camera.cpp:301
virtual void wheelEvent(QWheelEvent *const event, Camera *const camera)
virtual void mouseDoubleClickEvent(QMouseEvent *const event, Camera *const camera)
void projectOnLine(const Vec &origin, const Vec &direction)
Definition: frame.cpp:1126
int screenHeight() const
Definition: camera.h:233
virtual QDomElement domElement(const QString &name, QDomDocument &document) const
void setSpinningQuaternion(const Quaternion &spinningQuaternion)
#define Q_EMIT
Definition: config.h:121
double squaredNorm() const
Definition: vec.h:336
A versatile 3D OpenGL viewer based on QGLWidget.
Definition: qglviewer.h:70
void setSpinningSensitivity(float sensitivity)
Vec coordinatesOf(const Vec &src) const
Definition: frame.cpp:693
void computeMouseSpeed(const QMouseEvent *const e)
void translate(Vec &t)
Definition: frame.cpp:335
A perspective or orthographic camera.
Definition: camera.h:81
ManipulatedFrame & operator=(const ManipulatedFrame &mf)
The Quaternion class represents 3D rotations and orientations.
Definition: quaternion.h:66
Quaternion orientation() const
Definition: frame.cpp:537
Constraint * constraint() const
Definition: frame.h:363
The Frame class represents a coordinate system, defined by a position and an orientation.
Definition: frame.h:126
float fieldOfView() const
Definition: camera.h:208
int mouseOriginalDirection(const QMouseEvent *const e)
Quaternion deformedBallQuaternion(int x, int y, float cx, float cy, const Camera *const camera)
Frame & operator=(const Frame &frame)
Definition: frame.cpp:54
const Frame * referenceFrame() const
Definition: frame.h:269
Quaternion spinningQuaternion() const
double y
Definition: vec.h:85
virtual void mouseMoveEvent(QMouseEvent *const event, Camera *const camera)
Vec viewDirection() const
Definition: camera.h:134
Vec position() const
Definition: camera.h:114
void alignWithFrame(const Frame *const frame, bool move=false, float threshold=0.85f)
Definition: frame.cpp:1045
static float floatFromDom(const QDomElement &e, const QString &attribute, float defValue)
Definition: domUtils.h:56
virtual void startAction(int ma, bool withConstraint=true)
virtual void initFromDOMElement(const QDomElement &element)
Definition: frame.cpp:1002
virtual void startSpinning(int updateInterval)
double x
Definition: vec.h:85


octovis
Author(s): Kai M. Wurm , Armin Hornung
autogenerated on Mon Jun 10 2019 14:00:25