summaryrefslogtreecommitdiffhomepage
path: root/filter-accela
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2015-10-30 07:37:41 +0100
committerStanislaw Halik <sthalik@misaki.pl>2015-10-30 08:39:32 +0100
commitaa066bdd4622d4f6824fee864f6be6806813f04d (patch)
tree3df328b8b364cba2373a85827191b259bd78d546 /filter-accela
parentd6a54431d178632a2bf466c9904f74abd143afe6 (diff)
move to subdirectory-based build system
Closes #224
Diffstat (limited to 'filter-accela')
-rw-r--r--filter-accela/CMakeLists.txt2
-rw-r--r--filter-accela/ftnoir_accela_filtercontrols.ui300
-rw-r--r--filter-accela/ftnoir_filter_accela.cpp108
-rw-r--r--filter-accela/ftnoir_filter_accela.h79
-rw-r--r--filter-accela/ftnoir_filter_accela_dialog.cpp105
5 files changed, 594 insertions, 0 deletions
diff --git a/filter-accela/CMakeLists.txt b/filter-accela/CMakeLists.txt
new file mode 100644
index 00000000..5bfa8128
--- /dev/null
+++ b/filter-accela/CMakeLists.txt
@@ -0,0 +1,2 @@
+opentrack_boilerplate(opentrack-filter-accela)
+target_link_libraries(opentrack-filter-accela opentrack-spline-widget)
diff --git a/filter-accela/ftnoir_accela_filtercontrols.ui b/filter-accela/ftnoir_accela_filtercontrols.ui
new file mode 100644
index 00000000..3ab9a78e
--- /dev/null
+++ b/filter-accela/ftnoir_accela_filtercontrols.ui
@@ -0,0 +1,300 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AccelaUICFilterControls</class>
+ <widget class="QWidget" name="AccelaUICFilterControls">
+ <property name="windowModality">
+ <enum>Qt::NonModal</enum>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>501</width>
+ <height>359</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Accela filter settings</string>
+ </property>
+ <property name="windowIcon">
+ <iconset resource="../facetracknoir/ui-res.qrc">
+ <normaloff>:/images/filter-16.png</normaloff>:/images/filter-16.png</iconset>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QFrame" name="frame">
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="1" column="3">
+ <widget class="QSlider" name="rotation_slider">
+ <property name="maximum">
+ <number>99</number>
+ </property>
+ <property name="pageStep">
+ <number>5</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="tickPosition">
+ <enum>QSlider::TicksAbove</enum>
+ </property>
+ <property name="tickInterval">
+ <number>25</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="lblSensYaw_6">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Rotation sensitivity</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Smoothing</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="ewma_label">
+ <property name="minimumSize">
+ <size>
+ <width>48</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>0 ms</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="rot_gain">
+ <property name="text">
+ <string>0°</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QSlider" name="ewma_slider">
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="singleStep">
+ <number>10</number>
+ </property>
+ <property name="pageStep">
+ <number>25</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="tickPosition">
+ <enum>QSlider::TicksAbove</enum>
+ </property>
+ <property name="tickInterval">
+ <number>25</number>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Translation deadzone</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Rotation deadzone</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="3">
+ <widget class="QSlider" name="rot_dz_slider">
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLabel" name="rot_dz">
+ <property name="text">
+ <string>0°</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="3">
+ <widget class="QSlider" name="trans_dz_slider">
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1">
+ <widget class="QLabel" name="trans_dz">
+ <property name="text">
+ <string>0mm</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Translation sensitivity</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QLabel" name="trans_gain">
+ <property name="text">
+ <string>0mm</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="3">
+ <widget class="QSlider" name="translation_slider">
+ <property name="maximum">
+ <number>99</number>
+ </property>
+ <property name="pageStep">
+ <number>5</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="tickPosition">
+ <enum>QSlider::TicksAbove</enum>
+ </property>
+ <property name="tickInterval">
+ <number>25</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string/>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="1">
+ <widget class="QLabel" name="label_9">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>7</pointsize>
+ </font>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="text">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;justify&quot;&gt;&lt;br/&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Accela by &lt;/span&gt;&lt;a href=&quot;https://github.com/sthalik&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0057ae;&quot;&gt;Stanisław Halik&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&lt;br/&gt;Thanks to &lt;/span&gt;&lt;a href=&quot;https://github.com/dbaarda&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0057ae;&quot;&gt;Donovan Baarda&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p align=&quot;right&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;2012-2015&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;right&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::RichText</enum>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="indent">
+ <number>0</number>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="font">
+ <font>
+ <pointsize>10</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Visit &lt;a href=&quot;https://github.com/opentrack/opentrack/wiki/Accela-in-opentrack-2.3&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;our wiki&lt;/span&gt;&lt;/a&gt; for description of the settings.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources>
+ <include location="../facetracknoir/ui-res.qrc"/>
+ </resources>
+ <connections/>
+ <slots>
+ <slot>startEngineClicked()</slot>
+ <slot>stopEngineClicked()</slot>
+ <slot>cameraSettingsClicked()</slot>
+ </slots>
+</ui>
diff --git a/filter-accela/ftnoir_filter_accela.cpp b/filter-accela/ftnoir_filter_accela.cpp
new file mode 100644
index 00000000..62d1598d
--- /dev/null
+++ b/filter-accela/ftnoir_filter_accela.cpp
@@ -0,0 +1,108 @@
+/* Copyright (c) 2012-2015 Stanislaw Halik
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ */
+#include "ftnoir_filter_accela.h"
+#include <algorithm>
+#include <cmath>
+#include <QDebug>
+#include <QMutexLocker>
+#include "opentrack/plugin-api.hpp"
+
+static constexpr double rot_gains[][2] = {
+ { 2.66, 110 },
+ { 2.33, 80 },
+ { 2, 50 },
+ { 1.66, 30 },
+ { 1.33, 15 },
+ { 1, 5 },
+ { .66, 1.4 },
+ { .33, .4 },
+ { 0, 0 },
+ { -1, 0 }
+};
+
+static constexpr double trans_gains[][2] = {
+ { 2, 400 },
+ { 1.66, 120 },
+ { 1.33, 40 },
+ { 1, 10 },
+ { .66, 2 },
+ { .33, .6 },
+ { 0, 0 },
+ { -1, 0 }
+};
+
+constexpr double settings_accela::mult_rot;
+constexpr double settings_accela::mult_trans;
+constexpr double settings_accela::mult_rot_dz;
+constexpr double settings_accela::mult_trans_dz;
+constexpr double settings_accela::mult_ewma;
+
+FTNoIR_Filter::FTNoIR_Filter() : first_run(true)
+{
+ rot.setMaxInput(rot_gains[0][0]);
+ trans.setMaxInput(trans_gains[0][0]);
+ rot.setMaxOutput(rot_gains[0][1]);
+ trans.setMaxOutput(trans_gains[0][1]);
+
+ for (int i = 0; rot_gains[i][0] >= 0; i++)
+ {
+ rot.addPoint(QPointF(rot_gains[i][0], rot_gains[i][1]));
+ }
+ for (int i = 0; trans_gains[i][0] >= 0; i++)
+ {
+ trans.addPoint(QPointF(trans_gains[i][0], trans_gains[i][1]));
+ }
+}
+
+void FTNoIR_Filter::filter(const double* input, double *output)
+{
+ if (first_run)
+ {
+ for (int i = 0; i < 6; i++)
+ {
+ const double f = input[i];
+ output[i] = f;
+ last_output[i] = f;
+ smoothed_input[i] = f;
+ }
+ first_run = false;
+ t.start();
+ return;
+ }
+
+ const double rot_t = (1+s.rot_threshold) * s.mult_rot;
+ const double trans_t = (1+s.trans_threshold) * s.mult_trans;
+
+ const double dt = t.elapsed() * 1e-9;
+ t.start();
+
+ const double RC = s.mult_ewma * s.ewma / 1000.; // seconds
+ const double alpha = dt/(dt+RC);
+ const double rot_dz = s.rot_deadzone * s.mult_rot_dz;
+ const double trans_dz = s.trans_deadzone * s.mult_trans_dz;
+
+ for (int i = 0; i < 6; i++)
+ {
+ Map& m = i >= 3 ? rot : trans;
+
+ smoothed_input[i] = smoothed_input[i] * (1.-alpha) + input[i] * alpha;
+
+ const double in = smoothed_input[i];
+
+ const double vec = in - last_output[i];
+ const double dz = i >= 3 ? rot_dz : trans_dz;
+ const double vec_ = std::max(0., fabs(vec) - dz);
+ const double thres = i >= 3 ? rot_t : trans_t;
+ const double val = m.getValue(vec_ / thres);
+ const double result = last_output[i] + (vec < 0 ? -1 : 1) * dt * val;
+
+ last_output[i] = output[i] = result;
+ }
+}
+
+OPENTRACK_DECLARE_FILTER(FTNoIR_Filter, FilterControls, FTNoIR_FilterDll)
+
diff --git a/filter-accela/ftnoir_filter_accela.h b/filter-accela/ftnoir_filter_accela.h
new file mode 100644
index 00000000..b15e0cea
--- /dev/null
+++ b/filter-accela/ftnoir_filter_accela.h
@@ -0,0 +1,79 @@
+/* Copyright (c) 2012-2015 Stanislaw Halik
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ */
+#pragma once
+#include "ui_ftnoir_accela_filtercontrols.h"
+#include "opentrack/plugin-api.hpp"
+#include "spline-widget/functionconfig.h"
+#include <atomic>
+#include <QMutex>
+#include <QTimer>
+
+#include "opentrack/options.hpp"
+using namespace options;
+#include "opentrack-compat/timer.hpp"
+
+struct settings_accela : opts {
+ value<int> rot_threshold, trans_threshold, ewma, rot_deadzone, trans_deadzone;
+ static constexpr double mult_rot = 4. / 100.;
+ static constexpr double mult_trans = 4. / 100.;
+ static constexpr double mult_rot_dz = 2. / 100.;
+ static constexpr double mult_trans_dz = 2. / 100.;
+ static constexpr double mult_ewma = 1.25;
+ settings_accela() :
+ opts("Accela"),
+ rot_threshold(b, "rotation-threshold", 30),
+ trans_threshold(b, "translation-threshold", 50),
+ ewma(b, "ewma", 2),
+ rot_deadzone(b, "rotation-deadzone", 0),
+ trans_deadzone(b, "translation-deadzone", 0)
+ {}
+};
+
+class FTNoIR_Filter : public IFilter
+{
+public:
+ FTNoIR_Filter();
+ void filter(const double* input, double *output) override;
+ void center() override { first_run = true; }
+ Map rot, trans;
+private:
+ settings_accela s;
+ bool first_run;
+ double last_output[6];
+ double smoothed_input[6];
+ Timer t;
+};
+
+class FilterControls: public IFilterDialog
+{
+ Q_OBJECT
+public:
+ FilterControls();
+ void register_filter(IFilter* filter);
+ void unregister_filter();
+private:
+ Ui::AccelaUICFilterControls ui;
+ void discard();
+ void save();
+ FTNoIR_Filter* accela_filter;
+ settings_accela s;
+private slots:
+ void doOK();
+ void doCancel();
+ void update_ewma_display(int value);
+ void update_rot_display(int value);
+ void update_trans_display(int value);
+ void update_rot_dz_display(int value);
+ void update_trans_dz_display(int value);
+};
+
+class FTNoIR_FilterDll : public Metadata
+{
+public:
+ QString name() { return QString("Accela"); }
+ QIcon icon() { return QIcon(":/images/filter-16.png"); }
+};
diff --git a/filter-accela/ftnoir_filter_accela_dialog.cpp b/filter-accela/ftnoir_filter_accela_dialog.cpp
new file mode 100644
index 00000000..599cb716
--- /dev/null
+++ b/filter-accela/ftnoir_filter_accela_dialog.cpp
@@ -0,0 +1,105 @@
+/* Copyright (c) 2012-2015 Stanislaw Halik
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ */
+#include "ftnoir_filter_accela.h"
+#include <cmath>
+#include <QDebug>
+#include <algorithm>
+#include <QDoubleSpinBox>
+#include "opentrack/plugin-api.hpp"
+#include "spline-widget/qfunctionconfigurator.h"
+#include <QDialog>
+
+FilterControls::FilterControls() :
+ accela_filter(nullptr)
+{
+ ui.setupUi( this );
+
+ connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK()));
+ connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel()));
+
+ connect(ui.rotation_slider, SIGNAL(valueChanged(int)), this, SLOT(update_rot_display(int)));
+ connect(ui.translation_slider, SIGNAL(valueChanged(int)), this, SLOT(update_trans_display(int)));
+ connect(ui.ewma_slider, SIGNAL(valueChanged(int)), this, SLOT(update_ewma_display(int)));
+ connect(ui.rot_dz_slider, SIGNAL(valueChanged(int)), this, SLOT(update_rot_dz_display(int)));
+ connect(ui.trans_dz_slider, SIGNAL(valueChanged(int)), this, SLOT(update_trans_dz_display(int)));
+
+ tie_setting(s.rot_threshold, ui.rotation_slider);
+ tie_setting(s.trans_threshold, ui.translation_slider);
+ tie_setting(s.ewma, ui.ewma_slider);
+ tie_setting(s.rot_deadzone, ui.rot_dz_slider);
+ tie_setting(s.trans_deadzone, ui.trans_dz_slider);
+
+ update_rot_display(ui.rotation_slider->value());
+ update_trans_display(ui.translation_slider->value());
+ update_ewma_display(ui.ewma_slider->value());
+ update_rot_dz_display(ui.rot_dz_slider->value());
+ update_trans_dz_display(ui.trans_dz_slider->value());
+}
+
+void FilterControls::register_filter(IFilter* filter)
+{
+ accela_filter = static_cast<FTNoIR_Filter*>(filter);
+//#define LEAKING_DEBUG
+#ifdef LEAKING_DEBUG
+ auto d = new QDialog();
+ auto r = new QFunctionConfigurator(d);
+ r->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ r->setConfig(&accela_filter->rot, "");
+ r->setFixedSize(800, 300);
+ d->show();
+#endif
+}
+
+void FilterControls::unregister_filter()
+{
+ accela_filter = nullptr;
+}
+
+void FilterControls::doOK() {
+ save();
+ this->close();
+}
+
+void FilterControls::doCancel() {
+ discard();
+ close();
+}
+
+void FilterControls::discard()
+{
+ s.b->reload();
+}
+
+void FilterControls::save() {
+ s.b->save();
+}
+
+void FilterControls::update_rot_display(int value)
+{
+ ui.rot_gain->setText(QString::number((value + 1) * s.mult_rot) + "°");
+}
+
+void FilterControls::update_trans_display(int value)
+{
+ ui.trans_gain->setText(QString::number((value + 1) * s.mult_trans) + "mm");
+}
+
+void FilterControls::update_ewma_display(int value)
+{
+ ui.ewma_label->setText(QString::number(value * s.mult_ewma) + "ms");
+}
+
+void FilterControls::update_rot_dz_display(int value)
+{
+ ui.rot_dz->setText(QString::number(value * s.mult_rot_dz) + "°");
+}
+
+void FilterControls::update_trans_dz_display(int value)
+{
+ ui.trans_dz->setText(QString::number(value * s.mult_trans_dz) + "mm");
+}
+