diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2015-10-30 07:37:41 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2015-10-30 08:39:32 +0100 |
commit | aa066bdd4622d4f6824fee864f6be6806813f04d (patch) | |
tree | 3df328b8b364cba2373a85827191b259bd78d546 /filter-accela | |
parent | d6a54431d178632a2bf466c9904f74abd143afe6 (diff) |
move to subdirectory-based build system
Closes #224
Diffstat (limited to 'filter-accela')
-rw-r--r-- | filter-accela/CMakeLists.txt | 2 | ||||
-rw-r--r-- | filter-accela/ftnoir_accela_filtercontrols.ui | 300 | ||||
-rw-r--r-- | filter-accela/ftnoir_filter_accela.cpp | 108 | ||||
-rw-r--r-- | filter-accela/ftnoir_filter_accela.h | 79 | ||||
-rw-r--r-- | filter-accela/ftnoir_filter_accela_dialog.cpp | 105 |
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><html><head/><body><p align="justify"><br/><span style=" font-size:10pt;">Accela by </span><a href="https://github.com/sthalik"><span style=" font-size:10pt; text-decoration: underline; color:#0057ae;">Stanisław Halik</span></a><span style=" font-size:10pt;"><br/>Thanks to </span><a href="https://github.com/dbaarda"><span style=" font-size:10pt; text-decoration: underline; color:#0057ae;">Donovan Baarda</span></a></p><p align="right"><span style=" font-size:10pt;">2012-2015</span></p><p align="right"><br/></p></body></html></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><html><head/><body><p>Visit <a href="https://github.com/opentrack/opentrack/wiki/Accela-in-opentrack-2.3"><span style=" text-decoration: underline; color:#0000ff;">our wiki</span></a> for description of the settings.</p></body></html></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"); +} + |