From Kristofer Tingdahl, "I and my team have gone over the code again, and we feel that we are comfortable in our current proposal for change. It goes deeper than it did before, and I explain why:

There was code in the osgViewer/Viewer.cpp and osgViewer/CompositeViewer.cpp that transformed the Y-coordinates of an event. The code in the composite viewer did however miss the touch-data of the event. I thought that it should really be the GUIEventAdapter that should know about this, and hence I added the
GUIEventAdapter::setMouseYOrientationAndUpdateCoords which is re-computing the coordinates. First I simply added a boolean to the setMouseYOrientation function:

setMouseYOrientation( MouseYOrientation, bool updatecooreds=false );

but then the serializer complained.

This function is called from both the Viewer and the CompositeViewer. We have not tested from the viewer, but I cannot see it would not work from visual inspection.

The other change is in MultiTouchTrackballManipulator::handleMultiTouchDrag. I have removed the normalisation. The reason for that is that it normalised into screen coordinates from 0,0 to 1,1. The problem with that is that if you have a pinch event and you keep the distance say 300 pixels between your fingers, these 300 pixels represent 0.20 of the screen in the horizontal domain, but 0.3 of the screen in the vertical domain. A rotation of the pinch-fingers will hence result in a zoom in, as the normalised distance is changing between them.

A consequence of this is that I have changed the pan-code to use the same algorithm as the middle-mouse-pan.

The rest of it is very similar from previous revision, and there has been some fine-tuning here and there.

"
This commit is contained in:
Robert Osfield 2014-04-24 17:14:54 +00:00
parent 6f2d003bc5
commit bc5575f83a
8 changed files with 164 additions and 37 deletions

View File

@ -5,7 +5,7 @@
#include <osgViewer/CompositeViewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osgGA/MultiTouchTrackballManipulator>
#include <osgDB/ReadFile>
@ -57,8 +57,8 @@ public:
view->setSceneData( scene );
view->addEventHandler( new osgViewer::StatsHandler );
view->setCameraManipulator( new osgGA::TrackballManipulator );
view->setCameraManipulator( new osgGA::MultiTouchTrackballManipulator );
gw->setTouchEventsEnabled( true );
return gw->getGLWidget();
}

View File

@ -602,6 +602,9 @@ public:
/// get mouse-Y orientation (mouse-Y increases upwards or downwards).
MouseYOrientation getMouseYOrientation() const { return _mouseYOrientation; }
/// set mouse-Y orientation (mouse-Y increases upwards or downwards) and recompute variables
void setMouseYOrientationAndUpdateCoords(MouseYOrientation myo);
/// set current mouse button state.
void setButtonMask(int mask) { _buttonMask = mask; }

View File

@ -23,8 +23,10 @@
#include <QEvent>
#include <QQueue>
#include <QSet>
#include <QGLWidget>
class QInputEvent;
class QGestureEvent;
namespace osgViewer {
class ViewerBase;
@ -66,6 +68,9 @@ public:
inline bool getForwardKeyEvents() const { return _forwardKeyEvents; }
virtual void setForwardKeyEvents( bool f ) { _forwardKeyEvents = f; }
inline bool getTouchEventsEnabled() const { return _touchEventsEnabled; }
void setTouchEventsEnabled( bool e );
void setKeyboardModifiers( QInputEvent* event );
@ -76,6 +81,7 @@ public:
virtual void mouseDoubleClickEvent( QMouseEvent* event );
virtual void mouseMoveEvent( QMouseEvent* event );
virtual void wheelEvent( QWheelEvent* event );
virtual bool gestureEvent( QGestureEvent* event );
protected:
@ -109,6 +115,8 @@ protected:
QQueue<QEvent::Type> _deferredEventQueue;
QSet<QEvent::Type> _eventCompressor;
bool _touchEventsEnabled;
bool _forwardKeyEvents;
qreal _devicePixelRatio;
@ -157,6 +165,9 @@ public:
virtual std::string getWindowName();
virtual void useCursor( bool cursorOn );
virtual void setCursor( MouseCursor cursor );
inline bool getTouchEventsEnabled() const { return _widget->getTouchEventsEnabled(); }
virtual void setTouchEventsEnabled( bool e ) { _widget->setTouchEventsEnabled(e); }
virtual bool valid() const;
virtual bool realizeImplementation();

View File

@ -132,3 +132,20 @@ void GUIEventAdapter::copyPointerDataFrom(const osgGA::GUIEventAdapter& sourceEv
setMouseYOrientation(sourceEvent.getMouseYOrientation());
setPointerDataList(sourceEvent.getPointerDataList());
}
void GUIEventAdapter::setMouseYOrientationAndUpdateCoords(osgGA::GUIEventAdapter::MouseYOrientation myo)
{
if ( myo==_mouseYOrientation )
return;
setMouseYOrientation( myo );
_my = _Ymax - _my + _Ymin;
if( isMultiTouchEvent() )
{
for( TouchData::iterator itr = getTouchData()->begin(); itr != getTouchData()->end(); itr++ )
itr->y = _Ymax - itr->y + _Ymin;
}
}

View File

@ -37,29 +37,28 @@ MultiTouchTrackballManipulator::MultiTouchTrackballManipulator( const MultiTouch
void MultiTouchTrackballManipulator::handleMultiTouchDrag(const GUIEventAdapter* now, const GUIEventAdapter* last, const double eventTimeDelta)
{
osg::Vec2 pt_1_now(now->getTouchPointNormalizedX(0),now->getTouchPointNormalizedY(0));
osg::Vec2 pt_2_now(now->getTouchPointNormalizedX(1),now->getTouchPointNormalizedY(1));
osg::Vec2 pt_1_last(last->getTouchPointNormalizedX(0),last->getTouchPointNormalizedY(0));
osg::Vec2 pt_2_last(last->getTouchPointNormalizedX(1),last->getTouchPointNormalizedY(1));
const osg::Vec2 pt_1_now( now->getTouchData()->get(0).x, now->getTouchData()->get(0).y);
const osg::Vec2 pt_2_now( now->getTouchData()->get(1).x, now->getTouchData()->get(1).y);
const osg::Vec2 pt_1_last( last->getTouchData()->get(0).x, last->getTouchData()->get(0).y);
const osg::Vec2 pt_2_last( last->getTouchData()->get(1).x, last->getTouchData()->get(1).y);
float gap_now((pt_1_now - pt_2_now).length());
float gap_last((pt_1_last - pt_2_last).length());
const float gap_now((pt_1_now - pt_2_now).length());
const float gap_last((pt_1_last - pt_2_last).length());
// osg::notify(osg::ALWAYS) << gap_now << " " << gap_last << std::endl;
const float relativeChange = (gap_last - gap_now)/gap_last;
// zoom gesture
if (fabs(gap_last - gap_now) > 0.02)
zoomModel( (gap_last - gap_now) , true );
if (fabs(relativeChange) > 0.02)
zoomModel( relativeChange , true );
// drag gesture
osg::Vec2 delta = ((pt_1_last - pt_1_now) + (pt_2_last - pt_2_now)) / 2.0f;
const osg::Vec2 delta = ((pt_1_last - pt_1_now) + (pt_2_last - pt_2_now)) / 2.0f;
float scale = _distance / 3.0f;
// osg::notify(osg::ALWAYS) << "drag: " << delta << " scale: " << scale << std::endl;
const float scale = -0.3f * _distance * getThrowScale( eventTimeDelta );
//osg::notify(osg::ALWAYS) << "drag: " << delta << " scale: " << scale << std::endl;
panModel( delta.x() * scale, delta.y() * scale);
}

View File

@ -11,12 +11,17 @@
* OpenSceneGraph Public License for more details.
*/
#include <osgQt/GraphicsWindowQt>
#include <osg/DeleteHandler>
#include <osgQt/GraphicsWindowQt>
#include <osgViewer/ViewerBase>
#include <QInputEvent>
#if (QT_VERSION>=QT_VERSION_CHECK(4, 6, 0))
# define USE_GESTURES
# include <QGestureEvent>
# include <QGesture>
#endif
using namespace osgQt;
@ -136,7 +141,8 @@ static HeartBeat heartBeat;
GLWidget::GLWidget( QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f, bool forwardKeyEvents )
: QGLWidget(parent, shareWidget, f),
_gw( NULL ),
_forwardKeyEvents( forwardKeyEvents )
_forwardKeyEvents( forwardKeyEvents ),
_touchEventsEnabled( false )
{
_devicePixelRatio = GETDEVICEPIXELRATIO();
}
@ -145,7 +151,8 @@ GLWidget::GLWidget( QGLContext* context, QWidget* parent, const QGLWidget* share
bool forwardKeyEvents )
: QGLWidget(context, parent, shareWidget, f),
_gw( NULL ),
_forwardKeyEvents( forwardKeyEvents )
_forwardKeyEvents( forwardKeyEvents ),
_touchEventsEnabled( false )
{
_devicePixelRatio = GETDEVICEPIXELRATIO();
}
@ -154,7 +161,8 @@ GLWidget::GLWidget( const QGLFormat& format, QWidget* parent, const QGLWidget* s
bool forwardKeyEvents )
: QGLWidget(format, parent, shareWidget, f),
_gw( NULL ),
_forwardKeyEvents( forwardKeyEvents )
_forwardKeyEvents( forwardKeyEvents ),
_touchEventsEnabled( false )
{
_devicePixelRatio = GETDEVICEPIXELRATIO();
}
@ -170,6 +178,25 @@ GLWidget::~GLWidget()
}
}
void GLWidget::setTouchEventsEnabled(bool e)
{
#ifdef USE_GESTURES
if (e==_touchEventsEnabled)
return;
_touchEventsEnabled = e;
if (_touchEventsEnabled)
{
grabGesture(Qt::PinchGesture);
}
else
{
ungrabGesture(Qt::PinchGesture);
}
#endif
}
void GLWidget::processDeferredEvents()
{
QQueue<QEvent::Type> deferredEventQueueCopy;
@ -189,6 +216,10 @@ void GLWidget::processDeferredEvents()
bool GLWidget::event( QEvent* event )
{
#ifdef USE_GESTURES
if ( event->type()==QEvent::Gesture )
return gestureEvent(static_cast<QGestureEvent*>(event));
#endif
// QEvent::Hide
//
@ -361,6 +392,85 @@ void GLWidget::wheelEvent( QWheelEvent* event )
(event->delta()>0 ? osgGA::GUIEventAdapter::SCROLL_LEFT : osgGA::GUIEventAdapter::SCROLL_RIGHT) );
}
#ifdef USE_GESTURES
static osgGA::GUIEventAdapter::TouchPhase translateQtGestureState( Qt::GestureState state )
{
osgGA::GUIEventAdapter::TouchPhase touchPhase;
switch ( state )
{
case Qt::GestureStarted:
touchPhase = osgGA::GUIEventAdapter::TOUCH_BEGAN;
break;
case Qt::GestureUpdated:
touchPhase = osgGA::GUIEventAdapter::TOUCH_MOVED;
break;
case Qt::GestureFinished:
case Qt::GestureCanceled:
touchPhase = osgGA::GUIEventAdapter::TOUCH_ENDED;
break;
default:
touchPhase = osgGA::GUIEventAdapter::TOUCH_UNKNOWN;
};
return touchPhase;
}
#endif
bool GLWidget::gestureEvent( QGestureEvent* qevent )
{
#ifndef USE_GESTURES
return false;
#else
bool accept = false;
if ( QPinchGesture* pinch = static_cast<QPinchGesture *>(qevent->gesture(Qt::PinchGesture) ) )
{
const QPointF qcenterf = pinch->centerPoint();
const float angle = pinch->totalRotationAngle();
const float scale = pinch->totalScaleFactor();
const QPoint pinchCenterQt = mapFromGlobal(qcenterf.toPoint());
const osg::Vec2 pinchCenter( pinchCenterQt.x(), pinchCenterQt.y() );
//We don't have absolute positions of the two touches, only a scale and rotation
//Hence we create pseudo-coordinates which are reasonable, and centered around the
//real position
const float radius = (width()+height())/4;
const osg::Vec2 vector( scale*cos(angle)*radius, scale*sin(angle)*radius);
const osg::Vec2 p0 = pinchCenter+vector;
const osg::Vec2 p1 = pinchCenter-vector;
osg::ref_ptr<osgGA::GUIEventAdapter> event = 0;
const osgGA::GUIEventAdapter::TouchPhase touchPhase = translateQtGestureState( pinch->state() );
if ( touchPhase==osgGA::GUIEventAdapter::TOUCH_BEGAN )
{
event = _gw->getEventQueue()->touchBegan(0 , touchPhase, p0[0], p0[1] );
}
else if ( touchPhase==osgGA::GUIEventAdapter::TOUCH_MOVED )
{
event = _gw->getEventQueue()->touchMoved( 0, touchPhase, p0[0], p0[1] );
}
else
{
event = _gw->getEventQueue()->touchEnded( 0, touchPhase, p0[0], p0[1], 1 );
}
if ( event )
{
event->addTouchPoint( 1, touchPhase, p1[0], p1[1] );
accept = true;
}
}
if ( accept )
qevent->accept();
return accept;
#endif
}
GraphicsWindowQt::GraphicsWindowQt( osg::GraphicsContext::Traits* traits, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f )

View File

@ -1008,11 +1008,7 @@ void CompositeViewer::eventTraversal()
event->setInputRange(pd->xMin, pd->yMin, pd->xMax, pd->yMax);
event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
#else
if (event->getMouseYOrientation()!=osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS)
{
event->setY((event->getYmax()-event->getY())+event->getYmin());
event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
}
event->setMouseYOrientationAndUpdateCoords(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
#endif
_previousEvent = event;

View File

@ -929,16 +929,7 @@ void Viewer::eventTraversal()
event->setInputRange(pd->xMin, pd->yMin, pd->xMax, pd->yMax);
event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
#else
if (event->getMouseYOrientation()!=osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS)
{
event->setY((event->getYmax()-event->getY())+event->getYmin());
event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
if(event->isMultiTouchEvent()) {
for(osgGA::GUIEventAdapter::TouchData::iterator itr = event->getTouchData()->begin(); itr != event->getTouchData()->end(); itr++) {
itr->y = event->getYmax() - itr->y + event->getYmin();
}
}
}
event->setMouseYOrientationAndUpdateCoords(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
#endif
eventState->copyPointerDataFrom(*event);