summaryrefslogtreecommitdiffstats
path: root/src/platformsupport/input/evdevtouch/qevdevtouchfilter_p.h
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar@sletta.org>2016-10-27 13:29:13 +0200
committerGunnar Sletta <gunnar@sletta.org>2016-12-13 13:59:46 +0000
commite63f861e52b80aa3e6dbeb3c50649f666bc025b1 (patch)
treef6ca8e00fb67e89b42591179edae56720b45fca4 /src/platformsupport/input/evdevtouch/qevdevtouchfilter_p.h
parent6755ec891a1740110c48895afd53d39e8370704a (diff)
Add support for filtering in the qevdevtouch plugin
This patch adds a Kalman filter to the evdev touch plugin which samples velocity and position in x and y direction and uses this to emit touch points in sync with the application's repaint rate. The filter also allows for basic prediction based on current position and velocity estimates. Filtering is opt-in, and can be enabled by passing for instance > app -plugin evdevtouch:/dev/touchscreen:filtered:prediction=16 The logic relies on a stable QWindow::requestUpdate() and will work best in combination with QtQuick and blocking swap buffers (or equivalent). QScreen::refreshRate() will also have to be reasonably accurate. [ChangeLog][Platform Specific Changes] The evdevtouch plugin now has the option to apply filtering and prediction. Enabled by passing "filtered" as an argument. Prediction can be specified by passing "prediction=X" as an argument, where X is in milliseconds. Change-Id: I682db4386fe3a7cef8b4a08ea0d16c1491efb873 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'src/platformsupport/input/evdevtouch/qevdevtouchfilter_p.h')
-rw-r--r--src/platformsupport/input/evdevtouch/qevdevtouchfilter_p.h158
1 files changed, 158 insertions, 0 deletions
diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchfilter_p.h b/src/platformsupport/input/evdevtouch/qevdevtouchfilter_p.h
new file mode 100644
index 0000000000..ebb793b3db
--- /dev/null
+++ b/src/platformsupport/input/evdevtouch/qevdevtouchfilter_p.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QEvdevTouchFilter
+{
+ QEvdevTouchFilter();
+
+ void initialize(float pos, float velocity);
+ void update(float pos, float velocity, float timeDelta);
+
+ float position() const { return x.x; }
+ float velocity() const { return x.y; }
+
+private:
+ struct vec2 {
+ vec2(float x = 0.0f, float y = 0.0f) : x(x), y(y) { }
+ float x, y;
+
+ vec2 operator-(vec2 v) {
+ return vec2(x - v.x, y - v.y);
+ }
+
+ vec2 operator+(vec2 v) {
+ return vec2(x + v.x, y + v.y);
+ }
+ };
+
+ struct mat2 {
+ float a, b, c, d;
+ mat2(float a = 1.0f, float b = 0.0f, float c = 0.0f, float d = 1.0f)
+ : a(a)
+ , b(b)
+ , c(c)
+ , d(d)
+ {
+ }
+
+ mat2 transposed() const {
+ return mat2(a, c,
+ b, d);
+ }
+
+ mat2 inverted() const {
+ float det = 1.0f / (a * d - b * c);
+ return mat2( d * det, -b * det,
+ -c * det, a * det);
+ }
+
+ mat2 operator+(mat2 m) const {
+ return mat2(a + m.a, b + m.b,
+ c + m.c, d + m.d);
+ }
+
+ mat2 operator-(mat2 m) const {
+ return mat2(a - m.a, b - m.b,
+ c - m.c, d - m.d);
+ }
+
+ vec2 operator*(vec2 v) const {
+ return vec2(a * v.x + b * v.y,
+ c * v.x + d * v.y);
+ }
+
+ mat2 operator*(mat2 M) const {
+ return mat2(a * M.a + b * M.c,
+ a * M.b + b * M.d,
+ c * M.a + d * M.c,
+ c * M.b + d * M.d);
+ }
+ };
+
+ vec2 x;
+ mat2 A;
+ mat2 P;
+ mat2 Q;
+ mat2 R;
+ mat2 H;
+};
+
+inline QEvdevTouchFilter::QEvdevTouchFilter()
+{
+}
+
+inline void QEvdevTouchFilter::initialize(float pos, float velocity)
+{
+ x = vec2(pos, velocity);
+
+ P = mat2(0.0f, 0.0f,
+ 0.0f, 0.0f);
+
+ Q = mat2(0.0f, 0.0f,
+ 0.0f, 0.1f);
+ R = mat2(0.1f, 0.0f,
+ 0.0f, 0.1f);
+}
+
+inline void QEvdevTouchFilter::update(float pos, float velocity, float dT)
+{
+ A.b = dT;
+
+ // Prediction setp
+ x = A * x;
+ P = A * P * A.transposed() + Q;
+
+ // Correction step (complete with H)
+ // mat2 S = H * P * H.transposed() + R;
+ // mat2 K = P * H.transposed() * S.inverted();
+ // vec2 m(pos, velocity);
+ // vec2 y = m - H * x;
+ // x = x + K * y;
+ // P = (mat2() - K * H) * P;
+
+ // Correction step (without H as H is currently set to I, so we can ignore
+ // it in the calculations...)
+ mat2 S = P + R;
+ mat2 K = P * S.inverted();
+ vec2 m(pos, velocity);
+ vec2 y = m - x;
+ x = x + K * y;
+ P = (mat2() - K) * P;
+
+}
+
+QT_END_NAMESPACE