/* dtkVrGestureRecognizer.cpp --- * * Author: Julien Wintz * Copyright (C) 2008 - Julien Wintz, Inria. * Created: Thu Oct 21 19:12:40 2010 (+0200) * Version: $Id: 46e576e0e5ae07f5791b0875687667e73c230d67 $ * Last-Updated: Thu Apr 26 17:22:05 2012 (+0200) * By: Julien Wintz * Update #: 696 */ /* Commentary: * */ /* Change log: * */ #include "dtkVrGestureRecognizer.h" #include "dtkVrGestureRecognizer_p.h" #include "dtkVrScreen.h" #include #include #include #include #include #include #if defined(DTK_HAVE_VRPN) #include #include #include #include #include #include #endif // ///////////////////////////////////////////////////////////////// // vrpn callbacks (Definition at EOF.) // ///////////////////////////////////////////////////////////////// #if defined(DTK_HAVE_VRPN) void VRPN_CALLBACK vrpn_gesture_recognizer_handle_button(void *data, const vrpn_BUTTONCB callback); void VRPN_CALLBACK vrpn_gesture_recognizer_handle_analog(void *data, const vrpn_ANALOGCB callback); void VRPN_CALLBACK vrpn_gesture_recognizer_handle_tracker(void *data, const vrpn_TRACKERCB callback); #endif // ///////////////////////////////////////////////////////////////// // dtkVrGestureRecognizerPrivate // ///////////////////////////////////////////////////////////////// void dtkVrGestureRecognizerPrivate::run(void) { #if defined(DTK_HAVE_VRPN) vrpn_FILE_CONNECTIONS_SHOULD_PRELOAD = false; vrpn_FILE_CONNECTIONS_SHOULD_ACCUMULATE = false; this->analog = new vrpn_Analog_Remote(qPrintable(url.toString())); this->button = new vrpn_Button_Remote(qPrintable(url.toString())); this->tracker = new vrpn_Tracker_Remote(qPrintable(url.toString())); if (!this->analog || !this->button || !this->tracker) { qDebug() << "Error connecting to server"; return; } this->button->register_change_handler(this, vrpn_gesture_recognizer_handle_button); this->analog->register_change_handler(this, vrpn_gesture_recognizer_handle_analog); this->tracker->register_change_handler(this, vrpn_gesture_recognizer_handle_tracker); while (this->running) { this->analog->mainloop(); this->button->mainloop(); this->tracker->mainloop(); vrpn_SleepMsecs(10); } delete this->analog; delete this->button; delete this->tracker; #endif } void dtkVrGestureRecognizerPrivate::stop(void) { this->running = false; } #if defined(DTK_HAVE_VRPN) void dtkVrGestureRecognizerPrivate::handle_button(const vrpn_BUTTONCB callback) { Q_UNUSED(callback); } void dtkVrGestureRecognizerPrivate::handle_analog(const vrpn_ANALOGCB callback) { Q_UNUSED(callback); } void dtkVrGestureRecognizerPrivate::handle_tracker(const vrpn_TRACKERCB callback) { if (!this->acknowledge) return; if (callback.sensor == 100) { this->right_hand_position[0] = callback.pos[0]; this->right_hand_position[1] = callback.pos[1]; this->right_hand_position[2] = callback.pos[2]; } if (callback.sensor == 1000) { this->right_thumb_position[0] = this->right_hand_position[0] + callback.pos[0]; this->right_thumb_position[1] = this->right_hand_position[1] + callback.pos[1]; this->right_thumb_position[2] = this->right_hand_position[2] + callback.pos[2]; } if (callback.sensor == 1001) { this->right_index_position[0] = this->right_hand_position[0] + callback.pos[0]; this->right_index_position[1] = this->right_hand_position[1] + callback.pos[1]; this->right_index_position[2] = this->right_hand_position[2] + callback.pos[2]; } if (callback.sensor == 1002) { this->right_major_position[0] = this->right_hand_position[0] + callback.pos[0]; this->right_major_position[1] = this->right_hand_position[1] + callback.pos[1]; this->right_major_position[2] = this->right_hand_position[2] + callback.pos[2]; } if (callback.sensor == 101) { this->left_hand_position[0] = callback.pos[0]; this->left_hand_position[1] = callback.pos[1]; this->left_hand_position[2] = callback.pos[2]; } if (callback.sensor == 1010) { this->left_thumb_position[0] = this->left_hand_position[0] + callback.pos[0]; this->left_thumb_position[1] = this->left_hand_position[1] + callback.pos[1]; this->left_thumb_position[2] = this->left_hand_position[2] + callback.pos[2]; } if (callback.sensor == 1011) { this->left_index_position[0] = this->left_hand_position[0] + callback.pos[0]; this->left_index_position[1] = this->left_hand_position[1] + callback.pos[1]; this->left_index_position[2] = this->left_hand_position[2] + callback.pos[2]; } if (callback.sensor == 1012) { this->left_major_position[0] = this->left_hand_position[0] + callback.pos[0]; this->left_major_position[1] = this->left_hand_position[1] + callback.pos[1]; this->left_major_position[2] = this->left_hand_position[2] + callback.pos[2]; } if (callback.sensor == 1002) this->right_major_interaction = (callback.pos[0] <= 0); if (callback.sensor == 1012) this->left_major_interaction = (callback.pos[0] <= 0); if (this->left_major_interaction || this->right_major_interaction) { if (state == End) { this->left_thumb_start_position[0] = this->left_thumb_position[0]; this->left_thumb_start_position[1] = this->left_thumb_position[1]; this->left_thumb_start_position[2] = this->left_thumb_position[2]; this->right_thumb_start_position[0] = this->right_thumb_position[0]; this->right_thumb_start_position[1] = this->right_thumb_position[1]; this->right_thumb_start_position[2] = this->right_thumb_position[2]; this->left_index_start_position[0] = this->left_index_position[0]; this->left_index_start_position[1] = this->left_index_position[1]; this->left_index_start_position[2] = this->left_index_position[2]; this->right_index_start_position[0] = this->right_index_position[0]; this->right_index_start_position[1] = this->right_index_position[1]; this->right_index_start_position[2] = this->right_index_position[2]; state = Begin; } if (state == Begin) { if (this->left_major_interaction && this->right_major_interaction) { state = Pinch; emit postPinchEvent(Qt::GestureStarted); } else { state = Pan; emit postPanEvent(Qt::GestureStarted); } } if (state == Pan) { if (this->left_major_interaction && this->right_major_interaction) { state = End; this->mutex.lock(); this->acknowledge = false; this->mutex.unlock(); emit postPanEvent(Qt::GestureFinished); } else { emit postPanEvent(Qt::GestureUpdated); } } if (state == Pinch) { if (this->left_major_interaction && this->right_major_interaction) { emit postPinchEvent(Qt::GestureUpdated); } else { state = End; this->mutex.lock(); this->acknowledge = false; this->mutex.unlock(); emit postPinchEvent(Qt::GestureFinished); } } } else { if (state == Pinch) { state = End; this->mutex.lock(); this->acknowledge = false; this->mutex.unlock(); emit postPinchEvent(Qt::GestureFinished); } if (state == Pan) { state = End; this->mutex.lock(); this->acknowledge = false; this->mutex.unlock(); emit postPanEvent(Qt::GestureFinished); } } } #endif // ///////////////////////////////////////////////////////////////// // dtkVrGestureRecognizer // ///////////////////////////////////////////////////////////////// dtkVrGestureRecognizer::dtkVrGestureRecognizer(void) : QObject(), d(new dtkVrGestureRecognizerPrivate) { d->view = NULL; d->receiver = NULL; d->q = this; d->running = false; d->acknowledge = true; d->state = dtkVrGestureRecognizerPrivate::End; connect(d, SIGNAL(postPanEvent(Qt::GestureState)), this, SLOT(postPanEvent(Qt::GestureState))); connect(d, SIGNAL(postSwipeEvent(Qt::GestureState)), this, SLOT(postSwipeEvent(Qt::GestureState))); connect(d, SIGNAL(postPinchEvent(Qt::GestureState)), this, SLOT(postPinchEvent(Qt::GestureState))); connect(d, SIGNAL(postCustomEvent(Qt::GestureState)), this, SLOT(postCustomEvent(Qt::GestureState))); connect(d, SIGNAL(postClearEvent(Qt::GestureState)), this, SLOT(postClearEvent(Qt::GestureState))); } dtkVrGestureRecognizer::~dtkVrGestureRecognizer(void) { delete d; d = NULL; } void dtkVrGestureRecognizer::setReceiver(QObject *receiver) { d->receiver = receiver; } void dtkVrGestureRecognizer::setView(dtkAbstractView *view) { d->view = view; } void dtkVrGestureRecognizer::startConnection(const QUrl& server) { d->running = true; d->url = server; d->start(); } void dtkVrGestureRecognizer::stopConnection(void) { d->stop(); } void dtkVrGestureRecognizer::postPanEvent(Qt::GestureState state) { if (!d->receiver) return; if (state == Qt::GestureFinished) { d->mutex.lock(); d->acknowledge = true; d->mutex.unlock(); } static dtkDeprecated::dtkVector3D lastPosition; dtkDeprecated::dtkVector3D position; if (d->left_major_interaction && !d->right_major_interaction) { position = dtkDeprecated::dtkVector3D( d->left_index_position[0], d->left_index_position[2], - d->left_index_position[1]); } else if (!d->left_major_interaction && d->right_major_interaction) { position = dtkDeprecated::dtkVector3D( d->right_index_position[0], d->right_index_position[2], - d->right_index_position[1]); } else { position = lastPosition; } position[2] = 0; if (state == Qt::GestureStarted) lastPosition = position; dtkDeprecated::dtkVector3D offset = position - lastPosition; float xmin = 0, xmax = 0; float ymin = 0, ymax = 0; float zmin = 0, zmax = 0; double camera_up[3]; double camera_position[3]; double camera_focalpnt[3]; // d->view->bounds(xmin, xmax, ymin, ymax, zmin, zmax); // d->view->cameraUp(camera_up); // d->view->cameraPosition(camera_position); // d->view->cameraFocalPoint(camera_focalpnt); dtkDeprecated::dtkVector3D a = dtkDeprecated::dtkVector3D(xmin, ymin, zmin); dtkDeprecated::dtkVector3D b = dtkDeprecated::dtkVector3D(xmax, ymax, zmax); double dg = (b - a).norm(); Q_UNUSED(dg); dtkDeprecated::dtkVector3D u_xtk = dtkDeprecated::dtkVector3D(camera_up[0], camera_up[1], camera_up[2]); dtkDeprecated::dtkVector3D p_xtk = dtkDeprecated::dtkVector3D(camera_position[0], camera_position[1], camera_position[2]); dtkDeprecated::dtkVector3D f_xtk = dtkDeprecated::dtkVector3D(camera_focalpnt[0], camera_focalpnt[1], camera_focalpnt[2]); dtkDeprecated::dtkVector3D l = dtkDeprecated::dtkVector3D(1.0, 0.0, 0.0); dtkDeprecated::dtkVector3D m = dtkDeprecated::dtkVector3D(0.0, 1.0, 0.0); dtkDeprecated::dtkVector3D n = dtkDeprecated::dtkVector3D(0.0, 0.0, 1.0); dtkDeprecated::dtkVector3D > xtk_in_xtk = dtkDeprecated::dtkVector3D >(l, m, n); dtkDeprecated::dtkVector3D j = u_xtk; dtkDeprecated::dtkVector3D k = p_xtk - f_xtk; dtkDeprecated::dtkVector3D i = j % k; dtkDeprecated::dtkVector3D > cam_in_xtk = dtkDeprecated::dtkVector3D >(i.unit(), j.unit(), k.unit()); dtkDeprecated::dtkMatrixSquared cam_to_xtk = dtkChangeOfBasis(cam_in_xtk, xtk_in_xtk); dtkDeprecated::dtkVector3D f_art = dtkDeprecated::dtkVector3D( ( dtkVrScreen::screens[4][1][0] + dtkVrScreen::screens[4][0][0]) / 2, (-1 * dtkVrScreen::screens[4][2][2] + -1 * dtkVrScreen::screens[4][1][2]) / 2, dtkVrScreen::screens[4][0][1]); dtkDeprecated::dtkVector3D z_art = dtkDeprecated::dtkVector3D(0, f_art[1], 0); dtkDeprecated::dtkVector3D p_art = position; dtkDeprecated::dtkVector3D d_art = offset; dtkDeprecated::dtkVector3D o_xtk = cam_to_xtk * offset; // if(d->view->cameraProjectionMode() == "Parallel") { // // o_xtk *= dg/d->view->cameraZoom(); // o_xtk *= -1; // // } else { // // o_xtk *= (d->view->cameraViewAngle()/180.0*3.14159)*k.norm(); // o_xtk *= -1; // } QPanGesture *gesture = new QPanGesture(this); if (state == Qt::GestureStarted) gesture->setProperty("State", "Started"); if (state == Qt::GestureUpdated) gesture->setProperty("State", "Updated"); if (state == Qt::GestureFinished) gesture->setProperty("State", "Finished"); if (state == Qt::GestureStarted) { gesture->setProperty("PanGestureOffsetX", 0.0); gesture->setProperty("PanGestureOffsetY", 0.0); gesture->setProperty("PanGestureOffsetZ", 0.0); } else { gesture->setProperty("PanGestureOffsetX", o_xtk[0]); gesture->setProperty("PanGestureOffsetY", o_xtk[1]); gesture->setProperty("PanGestureOffsetZ", o_xtk[2]); } if ( state == Qt::GestureStarted || state == Qt::GestureFinished || (state == Qt::GestureUpdated && (offset.norm() > 0.003))) { QGestureEvent *event = new QGestureEvent(QList() << gesture); QCoreApplication::postEvent(d->receiver, event); } lastPosition = position; } void dtkVrGestureRecognizer::postSwipeEvent(Qt::GestureState state) { if (!d->receiver) return; if (state == Qt::GestureFinished) { d->mutex.lock(); d->acknowledge = true; d->mutex.unlock(); } // QSwipeGesture *gesture = new QSwipeGesture(this); // QGestureEvent *event = new QGestureEvent(QList() << gesture); // QCoreApplication::postEvent(d->receiver, event); } #include void dtkVrGestureRecognizer::postPinchEvent(Qt::GestureState state) { if (!d->receiver) return; if (state == Qt::GestureFinished) { d->mutex.lock(); d->acknowledge = true; d->mutex.unlock(); } dtkDeprecated::dtkVector3D s = dtkDeprecated::dtkVector3D( d->right_index_start_position[0] - d->left_index_start_position[0], d->right_index_start_position[2] - d->left_index_start_position[2], - d->right_index_start_position[1] + d->left_index_start_position[1]); dtkDeprecated::dtkVector3D u = dtkDeprecated::dtkVector3D( d->right_index_position[0] - d->left_index_position[0], d->right_index_position[2] - d->left_index_position[2], - d->right_index_position[1] + d->left_index_position[1]); dtkDeprecated::dtkVector3D i = dtkDeprecated::dtkVector3D(1.0, 0.0, 0.0); dtkDeprecated::dtkVector3D j = dtkDeprecated::dtkVector3D(0.0, 1.0, 0.0); dtkDeprecated::dtkVector3D k = dtkDeprecated::dtkVector3D(0.0, 0.0, 1.0); dtkDeprecated::dtkVector3D > from = dtkDeprecated::dtkVector3D >(i, j, k); dtkDeprecated::dtkVector3D l = dtkDeprecated::dtkVector3D(s[0], 0.0, s[2]).unit(); dtkDeprecated::dtkVector3D m = dtkDeprecated::dtkVector3D(0.0, 1.0, 0.0).unit(); dtkDeprecated::dtkVector3D n = (l % m).unit(); dtkDeprecated::dtkVector3D > to = dtkDeprecated::dtkVector3D >(l, m, n); dtkDeprecated::dtkMatrixSquared t = dtkChangeOfBasis(from, to); dtkDeprecated::dtkVector3D ns = t * s; ns[2] = 0; dtkDeprecated::dtkVector3D nu = t * u; nu[2] = 0; // -- Computing scale factor -- static qreal lastScaleFactor; qreal scaleFactor = nu.norm() / ns.norm(); if (state == Qt::GestureStarted) lastScaleFactor = scaleFactor; // -- Computing rotation angle -- static qreal lastRotationAngle; qreal rotationAngle = -1.0 * (acos(nu.unit() * ns.unit()) * ((ns % nu).unit() * n.unit())) * 180.0 / 3.141593; if (state == Qt::GestureStarted) lastRotationAngle = rotationAngle; // -- Post event -- QPinchGesture *gesture = new QPinchGesture; if (state == Qt::GestureStarted) gesture->setProperty("State", "Started"); if (state == Qt::GestureUpdated) gesture->setProperty("State", "Updated"); if (state == Qt::GestureFinished) gesture->setProperty("State", "Finished"); gesture->setScaleFactor(scaleFactor); gesture->setLastScaleFactor(lastScaleFactor); gesture->setRotationAngle(rotationAngle); gesture->setLastRotationAngle(lastRotationAngle); if ( state == Qt::GestureStarted || state == Qt::GestureFinished || (state == Qt::GestureUpdated && qAbs(scaleFactor - lastScaleFactor) / lastScaleFactor > 0.01) || (state == Qt::GestureUpdated && qAbs((rotationAngle - lastRotationAngle) / lastRotationAngle) > 0.01)) { QGestureEvent *event = new QGestureEvent(QList() << gesture); QCoreApplication::postEvent(d->receiver, event); } lastScaleFactor = scaleFactor; lastRotationAngle = rotationAngle; } void dtkVrGestureRecognizer::postCustomEvent(Qt::GestureState state) { if (!d->receiver) return; if (state == Qt::GestureFinished) { d->mutex.lock(); d->acknowledge = true; d->mutex.unlock(); } dtkDeprecated::dtkVector3D nis = dtkDeprecated::dtkVector3D( d->left_thumb_start_position[0] - d->left_index_start_position[0], d->left_thumb_start_position[2] - d->left_index_start_position[2], - d->left_thumb_start_position[1] + d->left_index_start_position[1]); dtkDeprecated::dtkVector3D njs = dtkDeprecated::dtkVector3D( d->right_index_start_position[0] - d->left_index_start_position[0], d->right_index_start_position[2] - d->left_index_start_position[2], - d->right_index_start_position[1] + d->left_index_start_position[1]); dtkDeprecated::dtkVector3D nks = nis % njs; dtkDeprecated::dtkVector3D niu = dtkDeprecated::dtkVector3D( d->left_thumb_position[0] - d->left_index_position[0], d->left_thumb_position[2] - d->left_index_position[2], - d->left_thumb_position[1] + d->left_index_position[1]); dtkDeprecated::dtkVector3D nju = dtkDeprecated::dtkVector3D( d->right_index_position[0] - d->left_index_position[0], d->right_index_position[2] - d->left_index_position[2], - d->right_index_position[1] + d->left_index_position[1]); dtkDeprecated::dtkVector3D nku = niu % nju; // double camera_up[3]; // double camera_position[3]; // double camera_focalpnt[3]; // d->view->cameraUp(camera_up); // d->view->cameraPosition(camera_position); // d->view->cameraFocalPoint(camera_focalpnt); // dtkDeprecated::dtkVector3D u_xtk = dtkDeprecated::dtkVector3D(camera_up[0], camera_up[1], camera_up[2]); // dtkDeprecated::dtkVector3D p_xtk = dtkDeprecated::dtkVector3D(camera_position[0], camera_position[1], camera_position[2]); // dtkDeprecated::dtkVector3D f_xtk = dtkDeprecated::dtkVector3D(camera_focalpnt[0], camera_focalpnt[1], camera_focalpnt[2]); // dtkDeprecated::dtkVector3D l = dtkDeprecated::dtkVector3D(1.0, 0.0, 0.0); // dtkDeprecated::dtkVector3D m = dtkDeprecated::dtkVector3D(0.0, 1.0, 0.0); // dtkDeprecated::dtkVector3D n = dtkDeprecated::dtkVector3D(0.0, 0.0, 1.0); // dtkDeprecated::dtkVector3D > xtk_in_xtk = dtkDeprecated::dtkVector3D >(l, m, n); // dtkDeprecated::dtkVector3D j = u_xtk; // dtkDeprecated::dtkVector3D k = p_xtk-f_xtk; // dtkDeprecated::dtkVector3D i = j%k; // dtkDeprecated::dtkVector3D > cam_in_xtk = dtkDeprecated::dtkVector3D >(i.unit(), j.unit(), k.unit()); // dtkMatrixSquared t = dtkChangeOfBasis(cam_in_xtk, xtk_in_xtk); // dtkDeprecated::dtkVector3D nnjs = t*njs; // dtkDeprecated::dtkVector3D nnju = t*nju; // dtkDeprecated::dtkVector3D nnks = t*nks; // dtkDeprecated::dtkVector3D nnku = t*nku; // dtkDeprecated::dtkVector3D nnjs_mn = nnjs; nnjs_mn[0] = 0; // dtkDeprecated::dtkVector3D nnjs_nl = nnjs; nnjs_nl[1] = 0; // dtkDeprecated::dtkVector3D nnjs_lm = nnjs; nnjs_lm[2] = 0; // dtkDeprecated::dtkVector3D nnju_mn = nnju; nnju_mn[0] = 0; // dtkDeprecated::dtkVector3D nnju_nl = nnju; nnju_nl[1] = 0; // dtkDeprecated::dtkVector3D nnju_lm = nnju; nnju_lm[2] = 0; // dtkDeprecated::dtkVector3D nnks_mn = nnks; nnks_mn[0] = 0; // dtkDeprecated::dtkVector3D nnks_nl = nnks; nnks_nl[1] = 0; // dtkDeprecated::dtkVector3D nnks_lm = nnks; nnks_lm[2] = 0; // dtkDeprecated::dtkVector3D nnku_mn = nnku; nnku_mn[0] = 0; // dtkDeprecated::dtkVector3D nnku_nl = nnku; nnku_nl[1] = 0; // dtkDeprecated::dtkVector3D nnku_lm = nnku; nnku_lm[2] = 0; // // -- Computing rotation angle -- // static qreal lastAzAngle; // static qreal lastElAngle; // static qreal lastRoAngle; // qreal azAngle = -0.0 * (acos(nnju_lm.unit() * nnjs_lm.unit()) * ((nnjs_lm % nnju_lm).unit() * j.unit())) * 180.0 / 3.141593; // qreal elAngle = 0.0 * (acos(nnku_mn.unit() * nnks_mn.unit()) * ((nnks_mn % nnku_mn).unit() * i.unit())) * 180.0 / 3.141593; // qreal roAngle = 1.0 * (acos(nnju_nl.unit() * nnjs_nl.unit()) * ((nnjs_nl % nnju_nl).unit() * k.unit())) * 180.0 / 3.141593; // if(state == Qt::GestureStarted) { // lastAzAngle = azAngle; // lastElAngle = elAngle; // lastRoAngle = roAngle; // } // -- Computing rotation angle -- dtkDeprecated::dtkVector3D i = dtkDeprecated::dtkVector3D(1.0, 0.0, 0.0); dtkDeprecated::dtkVector3D j = dtkDeprecated::dtkVector3D(0.0, 1.0, 0.0); dtkDeprecated::dtkVector3D k = dtkDeprecated::dtkVector3D(0.0, 0.0, 1.0); dtkDeprecated::dtkVector3D njs_ki = njs; njs_ki[1] = 0; dtkDeprecated::dtkVector3D nju_ki = nju; nju_ki[1] = 0; dtkDeprecated::dtkVector3D njs_ij = njs; njs_ij[2] = 0; dtkDeprecated::dtkVector3D nju_ij = nju; nju_ij[2] = 0; dtkDeprecated::dtkVector3D nks_jk = nks; nks_jk[0] = 0; dtkDeprecated::dtkVector3D nku_jk = nku; nku_jk[0] = 0; static qreal lastAzAngle; static qreal lastElAngle; static qreal lastRoAngle; qreal azAngle = -1.0 * (acos(nju_ki.unit() * njs_ki.unit()) * ((njs_ki % nju_ki).unit() * j.unit())) * 180.0 / 3.141593; qreal elAngle = 0.0 * (acos(nku_jk.unit() * nks_jk.unit()) * ((nks_jk % nku_jk).unit() * i.unit())) * 180.0 / 3.141593; qreal roAngle = 1.0 * (acos(nju_ij.unit() * njs_ij.unit()) * ((njs_ij % nju_ij).unit() * k.unit())) * 180.0 / 3.141593; if (state == Qt::GestureStarted) { lastAzAngle = azAngle; lastElAngle = elAngle; lastRoAngle = roAngle; } // -- Post event -- QGesture *gesture = new QGesture; if (state == Qt::GestureStarted) gesture->setProperty("State", "Started"); if (state == Qt::GestureUpdated) gesture->setProperty("State", "Updated"); if (state == Qt::GestureFinished) gesture->setProperty("State", "Finished"); gesture->setProperty("Type", "Custom"); gesture->setProperty("CustomGestureAngleAz", (azAngle - lastAzAngle)); gesture->setProperty("CustomGestureAngleEl", (elAngle - lastElAngle)); gesture->setProperty("CustomGestureAngleRo", (roAngle - lastRoAngle)); if ( state == Qt::GestureStarted || state == Qt::GestureFinished || (state == Qt::GestureUpdated && qAbs((azAngle - lastAzAngle) / lastAzAngle) > 0.01) || (state == Qt::GestureUpdated && qAbs((elAngle - lastElAngle) / lastElAngle) > 0.01) || (state == Qt::GestureUpdated && qAbs((roAngle - lastRoAngle) / lastRoAngle) > 0.01)) { qDebug() << "posting sutom gesture"; QGestureEvent *event = new QGestureEvent(QList() << gesture); QCoreApplication::postEvent(d->receiver, event); } lastAzAngle = azAngle; lastElAngle = elAngle; lastRoAngle = roAngle; } void dtkVrGestureRecognizer::postClearEvent(Qt::GestureState state) { DTK_UNUSED(state); if (!d->receiver) return; QGesture *gesture = new QGesture(this); QGestureEvent *event = new QGestureEvent(QList() << gesture); QCoreApplication::postEvent(d->receiver, event); } // ///////////////////////////////////////////////////////////////// // vrpn callbacks // ///////////////////////////////////////////////////////////////// #if defined(DTK_HAVE_VRPN) void VRPN_CALLBACK vrpn_gesture_recognizer_handle_button(void *data, const vrpn_BUTTONCB callback) { if (dtkVrGestureRecognizerPrivate *recognizer = static_cast(data)) recognizer->handle_button(callback); } void VRPN_CALLBACK vrpn_gesture_recognizer_handle_analog(void *data, const vrpn_ANALOGCB callback) { if (dtkVrGestureRecognizerPrivate *recognizer = static_cast(data)) recognizer->handle_analog(callback); } void VRPN_CALLBACK vrpn_gesture_recognizer_handle_tracker(void *data, const vrpn_TRACKERCB callback) { if (dtkVrGestureRecognizerPrivate *recognizer = static_cast(data)) recognizer->handle_tracker(callback); } #endif