From c4c4e9ddc1f659abd3abb57ba04b8524e2224bfe Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Fri, 22 Jul 2016 14:59:04 +0200 Subject: Estimate the velocity of a point MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I45cbfc69a533ea9e295825aef23edc70c88fa2c6 Reviewed-by: Jan Arve Sæther Reviewed-by: Shawn Rutledge --- src/quick/items/qquickevents.cpp | 64 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) (limited to 'src/quick/items/qquickevents.cpp') diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index 1fd9014408..727819b3f0 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qquickevents_p_p.h" +#include #include #include #include @@ -531,8 +532,7 @@ void QQuickEventPoint::reset(Qt::TouchPointState state, const QPointF &scenePos, m_pressTimestamp = timestamp; m_scenePressPos = scenePos; } - // TODO if Q_LIKELY(velocity.isNull) calculate velocity - m_velocity = velocity; + m_velocity = (Q_LIKELY(velocity.isNull()) ? estimatedVelocity() : velocity); } void QQuickEventPoint::localize(QQuickItem *target) @@ -637,6 +637,66 @@ void QQuickEventTouchPoint::reset(const QTouchEvent::TouchPoint &tp, ulong times m_uniqueId = tp.uniqueId(); } +struct PointVelocityData { + QVector2D velocity; + QPointF pos; + ulong timestamp; +}; + +typedef QMap PointDataForPointIdMap; +Q_GLOBAL_STATIC(PointDataForPointIdMap, g_previousPointData) +static const int PointVelocityAgeLimit = 500; // milliseconds + +/*! + * \interal + * \brief Estimates the velocity based on a weighted average of all previous velocities. + * The older the velocity is, the less significant it becomes for the estimate. + * \return + */ +QVector2D QQuickEventPoint::estimatedVelocity() const +{ + PointVelocityData *prevPoint = g_previousPointData->value(m_pointId); + if (!prevPoint) { + // cleanup events older than PointVelocityAgeLimit + auto end = g_previousPointData->end(); + for (auto it = g_previousPointData->begin(); it != end; ) { + PointVelocityData *data = it.value(); + if (m_timestamp - data->timestamp > PointVelocityAgeLimit) { + it = g_previousPointData->erase(it); + delete data; + } else { + ++it; + } + } + // TODO optimize: stop this dynamic memory thrashing + prevPoint = new PointVelocityData; + prevPoint->velocity = QVector2D(); + prevPoint->timestamp = 0; + prevPoint->pos = QPointF(); + g_previousPointData->insert(m_pointId, prevPoint); + } + if (prevPoint) { + const ulong timeElapsed = m_timestamp - prevPoint->timestamp; + if (timeElapsed == 0) // in case we call estimatedVelocity() twice on the same QQuickEventPoint + return m_velocity; + + QVector2D newVelocity; + if (prevPoint->timestamp != 0) + newVelocity = QVector2D(m_scenePos - prevPoint->pos)/timeElapsed; + + // VERY simple kalman filter: does a weighted average + // where the older velocities get less and less significant + static const float KalmanGain = 0.7f; + QVector2D filteredVelocity = newVelocity * KalmanGain + m_velocity * (1.0f - KalmanGain); + + prevPoint->velocity = filteredVelocity; + prevPoint->pos = m_scenePos; + prevPoint->timestamp = m_timestamp; + return filteredVelocity; + } + return QVector2D(); +} + /*! \internal \class QQuickPointerEvent -- cgit v1.2.3