From 9d9620d2820eb9064fe7b75c509f3209f4ca3b9e Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Tue, 30 May 2023 14:18:40 +0100 Subject: Added a filter based on natural body movements, which reduces higher frequency noise and cancels low speed position drift --- filter-tom/CMakeLists.txt | 1 + filter-tom/filter_tom.cpp | 48 +++ filter-tom/filter_tom.h | 93 ++++++ filter-tom/filter_tom_dialog.cpp | 88 ++++++ filter-tom/lang/nl_NL.ts | 78 +++++ filter-tom/lang/ru_RU.ts | 78 +++++ filter-tom/lang/stub.ts | 78 +++++ filter-tom/lang/zh_CN.ts | 78 +++++ filter-tom/tom_filtercontrols.ui | 610 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 1152 insertions(+) create mode 100644 filter-tom/CMakeLists.txt create mode 100644 filter-tom/filter_tom.cpp create mode 100644 filter-tom/filter_tom.h create mode 100644 filter-tom/filter_tom_dialog.cpp create mode 100644 filter-tom/lang/nl_NL.ts create mode 100644 filter-tom/lang/ru_RU.ts create mode 100644 filter-tom/lang/stub.ts create mode 100644 filter-tom/lang/zh_CN.ts create mode 100644 filter-tom/tom_filtercontrols.ui diff --git a/filter-tom/CMakeLists.txt b/filter-tom/CMakeLists.txt new file mode 100644 index 00000000..d98e90e2 --- /dev/null +++ b/filter-tom/CMakeLists.txt @@ -0,0 +1 @@ +otr_module(filter-tom) diff --git a/filter-tom/filter_tom.cpp b/filter-tom/filter_tom.cpp new file mode 100644 index 00000000..6bcfeae0 --- /dev/null +++ b/filter-tom/filter_tom.cpp @@ -0,0 +1,48 @@ +/* Copyright (c) 2023 Tom Brazier + * + * 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 "filter_tom.h" +#include "compat/math-imports.hpp" +#include "compat/macros.h" + +#include "api/plugin-api.hpp" +#include "opentrack/defs.hpp" + +#include + +tom::tom() +{ +} + +void tom::filter(const double* input, double* output) +{ + // order of axes: x, y, z, yaw, pitch, roll + if (unlikely(first_run)) + { + first_run = false; + t.start(); + + std::fill(speeds, speeds + 6, 0.0); + std::copy(input, input + 6, filtered_output); + } + else + { + const double dt = t.elapsed_seconds(); + t.start(); + + for (int i = 0; i < 6; i++) + { + double speed = (input[i] - last_input[i]) / dt; + speeds[i] += dt * (double)s.responsiveness[i] * (speed - speeds[i]); + filtered_output[i] += dt * (double)s.responsiveness[i] * min(1.0, abs(speeds[i]) / (double)s.drift_speeds[i]) * (input[i] - filtered_output[i]); + } + } + + std::copy(input, input + 6, last_input); + std::copy(filtered_output, filtered_output + 6, output); +} + +OPENTRACK_DECLARE_FILTER(tom, dialog_tom, tomDll) diff --git a/filter-tom/filter_tom.h b/filter-tom/filter_tom.h new file mode 100644 index 00000000..0f6d07c2 --- /dev/null +++ b/filter-tom/filter_tom.h @@ -0,0 +1,93 @@ +/* Copyright (c) 2023 Tom Brazier + * + * 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_tom_filtercontrols.h" + +#include "api/plugin-api.hpp" +#include "compat/timer.hpp" +#include "options/options.hpp" + +using namespace options; + +struct settings_tom : opts +{ + value responsiveness[6]; + value drift_speeds[6]; + + settings_tom() : + opts("tom-filter"), + responsiveness{ value(b, "x-responsiveness", { 10.0, .0, 20.0 }), + value(b, "y-responsiveness", { 10.0, .0, 20.0 }), + value(b, "z-responsiveness", { 10.0, .0, 20.0 }), + value(b, "yaw-responsiveness", { 10.0, .0, 20.0 }), + value(b, "pitch-responsiveness", { 10.0, .0, 20.0 }), + value(b, "roll-responsiveness", { 10.0, .0, 20.0 }) }, + drift_speeds{ value(b, "x-drift-speed", { 50.0, 1.0, 200.0 }), + value(b, "y-drift-speed", { 50.0, 1.0, 200.0 }), + value(b, "z-drift-speed", { 50.0, 1.0, 200.0 }), + value(b, "yaw-drift-speed", { 100.0, 1.0, 400.0 }), + value(b, "pitch-drift-speed", { 100.0, 1.0, 400.0 }), + value(b, "roll-drift-speed", { 100.0, 1.0, 400.0 }) } + { + } + + /* value kMinSmoothing, kMaxSmoothing, kSmoothingScaleCurve; + settings() + : opts("ewma-filter"), + kMinSmoothing(b, "min-smoothing", { .02, .01, 1 }), + kMaxSmoothing(b, "max-smoothing", { .7, .01, 1 }), + kSmoothingScaleCurve(b, "smoothing-scale-curve", { .8, .1, 5 }) + { + } +*/ +}; + +struct tom : IFilter +{ + tom(); + void filter(const double* input, double* output) override; + void center() override { first_run = true; } + module_status initialize() override { return status_ok(); } + +private: + double last_input[6]{}; + double speeds[6]{}; + double filtered_output[6]{}; + Timer t; + settings_tom s; + bool first_run = true; +}; + +class dialog_tom : public IFilterDialog +{ + Q_OBJECT +public: + dialog_tom(); + void register_filter(IFilter*) override {} + void unregister_filter() override {} + void save() override; + void reload() override; + bool embeddable() noexcept override { return true; } + void set_buttons_visible(bool x) override; + +private: + Ui::UICdialog_tom ui; + settings_tom s; + +private slots: + void doOK(); + void doCancel(); +}; + +class tomDll : public Metadata +{ + Q_OBJECT + + QString name() override { return tr("Tom"); } + QIcon icon() override { return QIcon(":/images/filter-16.png"); } +}; diff --git a/filter-tom/filter_tom_dialog.cpp b/filter-tom/filter_tom_dialog.cpp new file mode 100644 index 00000000..5a6ad3a4 --- /dev/null +++ b/filter-tom/filter_tom_dialog.cpp @@ -0,0 +1,88 @@ +/* Copyright (c) 2023 Tom Brazier + * + * 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 "filter_tom.h" + +using namespace options; + +dialog_tom::dialog_tom() +{ + ui.setupUi(this); + + tie_setting(s.responsiveness[0], ui.x_responsiveness_slider); + tie_setting(s.responsiveness[0], ui.x_responsiveness, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.responsiveness[1], ui.y_responsiveness_slider); + tie_setting(s.responsiveness[1], ui.y_responsiveness, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.responsiveness[2], ui.z_responsiveness_slider); + tie_setting(s.responsiveness[2], ui.z_responsiveness, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.responsiveness[3], ui.yaw_responsiveness_slider); + tie_setting(s.responsiveness[3], ui.yaw_responsiveness, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.responsiveness[4], ui.pitch_responsiveness_slider); + tie_setting(s.responsiveness[4], ui.pitch_responsiveness, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.responsiveness[5], ui.roll_responsiveness_slider); + tie_setting(s.responsiveness[5], ui.roll_responsiveness, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.drift_speeds[0], ui.x_drift_speed_slider); + tie_setting(s.drift_speeds[0], ui.x_drift_speed, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.drift_speeds[1], ui.y_drift_speed_slider); + tie_setting(s.drift_speeds[1], ui.y_drift_speed, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.drift_speeds[2], ui.z_drift_speed_slider); + tie_setting(s.drift_speeds[2], ui.z_drift_speed, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.drift_speeds[3], ui.yaw_drift_speed_slider); + tie_setting(s.drift_speeds[3], ui.yaw_drift_speed, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.drift_speeds[4], ui.pitch_drift_speed_slider); + tie_setting(s.drift_speeds[4], ui.pitch_drift_speed, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.drift_speeds[5], ui.roll_drift_speed_slider); + tie_setting(s.drift_speeds[5], ui.roll_drift_speed, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); +} + +void dialog_tom::doOK() +{ + save(); + close(); +} + +void dialog_tom::doCancel() +{ + close(); +} + +void dialog_tom::save() +{ + s.b->save(); +} + +void dialog_tom::reload() +{ + s.b->reload(); +} + +void dialog_tom::set_buttons_visible(bool x) +{ + ui.buttonBox->setVisible(x); +} diff --git a/filter-tom/lang/nl_NL.ts b/filter-tom/lang/nl_NL.ts new file mode 100644 index 00000000..ce0aefe3 --- /dev/null +++ b/filter-tom/lang/nl_NL.ts @@ -0,0 +1,78 @@ + + + + + UICdialog_tom + + Dialog + + + + X + + + + Y + + + + Z + + + + Yaw + + + + Pitch + + + + Roll + + + + °/s + + + + mm/s + + + + Responsiveness + + + + 10.0 + + + + Drift speeds + + + + 50 + + + + 100 + + + + Natural movement filter: cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + + + + Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + + + + + tomDll + + Tom + + + + diff --git a/filter-tom/lang/ru_RU.ts b/filter-tom/lang/ru_RU.ts new file mode 100644 index 00000000..b72d73ad --- /dev/null +++ b/filter-tom/lang/ru_RU.ts @@ -0,0 +1,78 @@ + + + + + UICdialog_tom + + Dialog + + + + X + + + + Y + + + + Z + + + + Yaw + + + + Pitch + + + + Roll + + + + °/s + + + + mm/s + + + + Responsiveness + + + + 10.0 + + + + Drift speeds + + + + 50 + + + + 100 + + + + Natural movement filter: cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + + + + Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + + + + + tomDll + + Tom + + + + diff --git a/filter-tom/lang/stub.ts b/filter-tom/lang/stub.ts new file mode 100644 index 00000000..f212040f --- /dev/null +++ b/filter-tom/lang/stub.ts @@ -0,0 +1,78 @@ + + + + + UICdialog_tom + + Dialog + + + + X + + + + Y + + + + Z + + + + Yaw + + + + Pitch + + + + Roll + + + + °/s + + + + mm/s + + + + Responsiveness + + + + 10.0 + + + + Drift speeds + + + + 50 + + + + 100 + + + + Natural movement filter: cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + + + + Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + + + + + tomDll + + Tom + + + + diff --git a/filter-tom/lang/zh_CN.ts b/filter-tom/lang/zh_CN.ts new file mode 100644 index 00000000..5a322913 --- /dev/null +++ b/filter-tom/lang/zh_CN.ts @@ -0,0 +1,78 @@ + + + + + UICdialog_tom + + Dialog + + + + X + + + + Y + + + + Z + + + + Yaw + + + + Pitch + + + + Roll + + + + °/s + + + + mm/s + + + + Responsiveness + + + + 10.0 + + + + Drift speeds + + + + 50 + + + + 100 + + + + Natural movement filter: cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + + + + Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + + + + + tomDll + + Tom + + + + diff --git a/filter-tom/tom_filtercontrols.ui b/filter-tom/tom_filtercontrols.ui new file mode 100644 index 00000000..1a135c1e --- /dev/null +++ b/filter-tom/tom_filtercontrols.ui @@ -0,0 +1,610 @@ + + + UICdialog_tom + + + + 0 + 0 + 438 + 559 + + + + Dialog + + + + + + Responsiveness + + + + + + X + + + + + + + + 0 + 0 + + + + + 30 + 0 + + + + 10.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + 40 + + + Qt::Horizontal + + + + + + + Y + + + + + + + + 30 + 0 + + + + 10.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 40 + + + Qt::Horizontal + + + + + + + Z + + + + + + + + 30 + 0 + + + + 10.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 40 + + + Qt::Horizontal + + + + + + + Yaw + + + + + + + + 30 + 0 + + + + 10.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 40 + + + Qt::Horizontal + + + + + + + Pitch + + + + + + + + 30 + 0 + + + + 10.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 40 + + + Qt::Horizontal + + + + + + + Roll + + + + + + + + 30 + 0 + + + + 10.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 40 + + + Qt::Horizontal + + + + + + + + + + + 0 + 0 + + + + Natural movement filter by Tom Brazier: Cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + + + Qt::PlainText + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + Drift speeds + + + + + + Z + + + + + + + 1 + + + 200 + + + Qt::Horizontal + + + + + + + Roll + + + + + + + + 30 + 0 + + + + 50 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + °/s + + + + + + + mm/s + + + + + + + °/s + + + + + + + 1 + + + 200 + + + Qt::Horizontal + + + + + + + + 30 + 0 + + + + 50 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 30 + 0 + + + + 100 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Y + + + + + + + + 30 + 0 + + + + 100 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Pitch + + + + + + + 1 + + + 400 + + + Qt::Horizontal + + + + + + + X + + + + + + + + 30 + 0 + + + + 100 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + mm/s + + + + + + + mm/s + + + + + + + Yaw + + + + + + + + 0 + 0 + + + + 1 + + + 200 + + + Qt::Horizontal + + + + + + + °/s + + + + + + + 1 + + + 400 + + + Qt::Horizontal + + + + + + + 1 + + + 400 + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + + 30 + 0 + + + + 50 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + buttonBox + accepted() + UICdialog_tom + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + UICdialog_tom + reject() + + + 316 + 260 + + + 286 + 274 + + + + + -- cgit v1.2.3 From 3a1f8606c5b415be00ebf21cd57f4fed6832b800 Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Tue, 30 May 2023 16:20:30 +0100 Subject: Picked a name - natural movement filter --- filter-nm/CMakeLists.txt | 1 + filter-nm/ftnoir_filter_nm.cpp | 48 +++ filter-nm/ftnoir_filter_nm.h | 93 ++++++ filter-nm/ftnoir_filter_nm_dialog.cpp | 88 +++++ filter-nm/ftnoir_nm_filtercontrols.ui | 610 ++++++++++++++++++++++++++++++++++ filter-nm/lang/nl_NL.ts | 78 +++++ filter-nm/lang/ru_RU.ts | 78 +++++ filter-nm/lang/stub.ts | 78 +++++ filter-nm/lang/zh_CN.ts | 78 +++++ filter-tom/CMakeLists.txt | 1 - filter-tom/filter_tom.cpp | 48 --- filter-tom/filter_tom.h | 93 ------ filter-tom/filter_tom_dialog.cpp | 88 ----- filter-tom/lang/nl_NL.ts | 78 ----- filter-tom/lang/ru_RU.ts | 78 ----- filter-tom/lang/stub.ts | 78 ----- filter-tom/lang/zh_CN.ts | 78 ----- filter-tom/tom_filtercontrols.ui | 610 ---------------------------------- 18 files changed, 1152 insertions(+), 1152 deletions(-) create mode 100644 filter-nm/CMakeLists.txt create mode 100644 filter-nm/ftnoir_filter_nm.cpp create mode 100644 filter-nm/ftnoir_filter_nm.h create mode 100644 filter-nm/ftnoir_filter_nm_dialog.cpp create mode 100644 filter-nm/ftnoir_nm_filtercontrols.ui create mode 100644 filter-nm/lang/nl_NL.ts create mode 100644 filter-nm/lang/ru_RU.ts create mode 100644 filter-nm/lang/stub.ts create mode 100644 filter-nm/lang/zh_CN.ts delete mode 100644 filter-tom/CMakeLists.txt delete mode 100644 filter-tom/filter_tom.cpp delete mode 100644 filter-tom/filter_tom.h delete mode 100644 filter-tom/filter_tom_dialog.cpp delete mode 100644 filter-tom/lang/nl_NL.ts delete mode 100644 filter-tom/lang/ru_RU.ts delete mode 100644 filter-tom/lang/stub.ts delete mode 100644 filter-tom/lang/zh_CN.ts delete mode 100644 filter-tom/tom_filtercontrols.ui diff --git a/filter-nm/CMakeLists.txt b/filter-nm/CMakeLists.txt new file mode 100644 index 00000000..d98e90e2 --- /dev/null +++ b/filter-nm/CMakeLists.txt @@ -0,0 +1 @@ +otr_module(filter-tom) diff --git a/filter-nm/ftnoir_filter_nm.cpp b/filter-nm/ftnoir_filter_nm.cpp new file mode 100644 index 00000000..6bcfeae0 --- /dev/null +++ b/filter-nm/ftnoir_filter_nm.cpp @@ -0,0 +1,48 @@ +/* Copyright (c) 2023 Tom Brazier + * + * 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 "filter_tom.h" +#include "compat/math-imports.hpp" +#include "compat/macros.h" + +#include "api/plugin-api.hpp" +#include "opentrack/defs.hpp" + +#include + +tom::tom() +{ +} + +void tom::filter(const double* input, double* output) +{ + // order of axes: x, y, z, yaw, pitch, roll + if (unlikely(first_run)) + { + first_run = false; + t.start(); + + std::fill(speeds, speeds + 6, 0.0); + std::copy(input, input + 6, filtered_output); + } + else + { + const double dt = t.elapsed_seconds(); + t.start(); + + for (int i = 0; i < 6; i++) + { + double speed = (input[i] - last_input[i]) / dt; + speeds[i] += dt * (double)s.responsiveness[i] * (speed - speeds[i]); + filtered_output[i] += dt * (double)s.responsiveness[i] * min(1.0, abs(speeds[i]) / (double)s.drift_speeds[i]) * (input[i] - filtered_output[i]); + } + } + + std::copy(input, input + 6, last_input); + std::copy(filtered_output, filtered_output + 6, output); +} + +OPENTRACK_DECLARE_FILTER(tom, dialog_tom, tomDll) diff --git a/filter-nm/ftnoir_filter_nm.h b/filter-nm/ftnoir_filter_nm.h new file mode 100644 index 00000000..0f6d07c2 --- /dev/null +++ b/filter-nm/ftnoir_filter_nm.h @@ -0,0 +1,93 @@ +/* Copyright (c) 2023 Tom Brazier + * + * 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_tom_filtercontrols.h" + +#include "api/plugin-api.hpp" +#include "compat/timer.hpp" +#include "options/options.hpp" + +using namespace options; + +struct settings_tom : opts +{ + value responsiveness[6]; + value drift_speeds[6]; + + settings_tom() : + opts("tom-filter"), + responsiveness{ value(b, "x-responsiveness", { 10.0, .0, 20.0 }), + value(b, "y-responsiveness", { 10.0, .0, 20.0 }), + value(b, "z-responsiveness", { 10.0, .0, 20.0 }), + value(b, "yaw-responsiveness", { 10.0, .0, 20.0 }), + value(b, "pitch-responsiveness", { 10.0, .0, 20.0 }), + value(b, "roll-responsiveness", { 10.0, .0, 20.0 }) }, + drift_speeds{ value(b, "x-drift-speed", { 50.0, 1.0, 200.0 }), + value(b, "y-drift-speed", { 50.0, 1.0, 200.0 }), + value(b, "z-drift-speed", { 50.0, 1.0, 200.0 }), + value(b, "yaw-drift-speed", { 100.0, 1.0, 400.0 }), + value(b, "pitch-drift-speed", { 100.0, 1.0, 400.0 }), + value(b, "roll-drift-speed", { 100.0, 1.0, 400.0 }) } + { + } + + /* value kMinSmoothing, kMaxSmoothing, kSmoothingScaleCurve; + settings() + : opts("ewma-filter"), + kMinSmoothing(b, "min-smoothing", { .02, .01, 1 }), + kMaxSmoothing(b, "max-smoothing", { .7, .01, 1 }), + kSmoothingScaleCurve(b, "smoothing-scale-curve", { .8, .1, 5 }) + { + } +*/ +}; + +struct tom : IFilter +{ + tom(); + void filter(const double* input, double* output) override; + void center() override { first_run = true; } + module_status initialize() override { return status_ok(); } + +private: + double last_input[6]{}; + double speeds[6]{}; + double filtered_output[6]{}; + Timer t; + settings_tom s; + bool first_run = true; +}; + +class dialog_tom : public IFilterDialog +{ + Q_OBJECT +public: + dialog_tom(); + void register_filter(IFilter*) override {} + void unregister_filter() override {} + void save() override; + void reload() override; + bool embeddable() noexcept override { return true; } + void set_buttons_visible(bool x) override; + +private: + Ui::UICdialog_tom ui; + settings_tom s; + +private slots: + void doOK(); + void doCancel(); +}; + +class tomDll : public Metadata +{ + Q_OBJECT + + QString name() override { return tr("Tom"); } + QIcon icon() override { return QIcon(":/images/filter-16.png"); } +}; diff --git a/filter-nm/ftnoir_filter_nm_dialog.cpp b/filter-nm/ftnoir_filter_nm_dialog.cpp new file mode 100644 index 00000000..5a6ad3a4 --- /dev/null +++ b/filter-nm/ftnoir_filter_nm_dialog.cpp @@ -0,0 +1,88 @@ +/* Copyright (c) 2023 Tom Brazier + * + * 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 "filter_tom.h" + +using namespace options; + +dialog_tom::dialog_tom() +{ + ui.setupUi(this); + + tie_setting(s.responsiveness[0], ui.x_responsiveness_slider); + tie_setting(s.responsiveness[0], ui.x_responsiveness, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.responsiveness[1], ui.y_responsiveness_slider); + tie_setting(s.responsiveness[1], ui.y_responsiveness, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.responsiveness[2], ui.z_responsiveness_slider); + tie_setting(s.responsiveness[2], ui.z_responsiveness, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.responsiveness[3], ui.yaw_responsiveness_slider); + tie_setting(s.responsiveness[3], ui.yaw_responsiveness, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.responsiveness[4], ui.pitch_responsiveness_slider); + tie_setting(s.responsiveness[4], ui.pitch_responsiveness, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.responsiveness[5], ui.roll_responsiveness_slider); + tie_setting(s.responsiveness[5], ui.roll_responsiveness, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.drift_speeds[0], ui.x_drift_speed_slider); + tie_setting(s.drift_speeds[0], ui.x_drift_speed, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.drift_speeds[1], ui.y_drift_speed_slider); + tie_setting(s.drift_speeds[1], ui.y_drift_speed, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.drift_speeds[2], ui.z_drift_speed_slider); + tie_setting(s.drift_speeds[2], ui.z_drift_speed, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.drift_speeds[3], ui.yaw_drift_speed_slider); + tie_setting(s.drift_speeds[3], ui.yaw_drift_speed, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.drift_speeds[4], ui.pitch_drift_speed_slider); + tie_setting(s.drift_speeds[4], ui.pitch_drift_speed, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); + + tie_setting(s.drift_speeds[5], ui.roll_drift_speed_slider); + tie_setting(s.drift_speeds[5], ui.roll_drift_speed, [](double x) + { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); +} + +void dialog_tom::doOK() +{ + save(); + close(); +} + +void dialog_tom::doCancel() +{ + close(); +} + +void dialog_tom::save() +{ + s.b->save(); +} + +void dialog_tom::reload() +{ + s.b->reload(); +} + +void dialog_tom::set_buttons_visible(bool x) +{ + ui.buttonBox->setVisible(x); +} diff --git a/filter-nm/ftnoir_nm_filtercontrols.ui b/filter-nm/ftnoir_nm_filtercontrols.ui new file mode 100644 index 00000000..1a135c1e --- /dev/null +++ b/filter-nm/ftnoir_nm_filtercontrols.ui @@ -0,0 +1,610 @@ + + + UICdialog_tom + + + + 0 + 0 + 438 + 559 + + + + Dialog + + + + + + Responsiveness + + + + + + X + + + + + + + + 0 + 0 + + + + + 30 + 0 + + + + 10.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + 40 + + + Qt::Horizontal + + + + + + + Y + + + + + + + + 30 + 0 + + + + 10.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 40 + + + Qt::Horizontal + + + + + + + Z + + + + + + + + 30 + 0 + + + + 10.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 40 + + + Qt::Horizontal + + + + + + + Yaw + + + + + + + + 30 + 0 + + + + 10.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 40 + + + Qt::Horizontal + + + + + + + Pitch + + + + + + + + 30 + 0 + + + + 10.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 40 + + + Qt::Horizontal + + + + + + + Roll + + + + + + + + 30 + 0 + + + + 10.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 40 + + + Qt::Horizontal + + + + + + + + + + + 0 + 0 + + + + Natural movement filter by Tom Brazier: Cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + + + Qt::PlainText + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + Drift speeds + + + + + + Z + + + + + + + 1 + + + 200 + + + Qt::Horizontal + + + + + + + Roll + + + + + + + + 30 + 0 + + + + 50 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + °/s + + + + + + + mm/s + + + + + + + °/s + + + + + + + 1 + + + 200 + + + Qt::Horizontal + + + + + + + + 30 + 0 + + + + 50 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 30 + 0 + + + + 100 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Y + + + + + + + + 30 + 0 + + + + 100 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Pitch + + + + + + + 1 + + + 400 + + + Qt::Horizontal + + + + + + + X + + + + + + + + 30 + 0 + + + + 100 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + mm/s + + + + + + + mm/s + + + + + + + Yaw + + + + + + + + 0 + 0 + + + + 1 + + + 200 + + + Qt::Horizontal + + + + + + + °/s + + + + + + + 1 + + + 400 + + + Qt::Horizontal + + + + + + + 1 + + + 400 + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + + 30 + 0 + + + + 50 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + buttonBox + accepted() + UICdialog_tom + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + UICdialog_tom + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/filter-nm/lang/nl_NL.ts b/filter-nm/lang/nl_NL.ts new file mode 100644 index 00000000..ce0aefe3 --- /dev/null +++ b/filter-nm/lang/nl_NL.ts @@ -0,0 +1,78 @@ + + + + + UICdialog_tom + + Dialog + + + + X + + + + Y + + + + Z + + + + Yaw + + + + Pitch + + + + Roll + + + + °/s + + + + mm/s + + + + Responsiveness + + + + 10.0 + + + + Drift speeds + + + + 50 + + + + 100 + + + + Natural movement filter: cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + + + + Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + + + + + tomDll + + Tom + + + + diff --git a/filter-nm/lang/ru_RU.ts b/filter-nm/lang/ru_RU.ts new file mode 100644 index 00000000..b72d73ad --- /dev/null +++ b/filter-nm/lang/ru_RU.ts @@ -0,0 +1,78 @@ + + + + + UICdialog_tom + + Dialog + + + + X + + + + Y + + + + Z + + + + Yaw + + + + Pitch + + + + Roll + + + + °/s + + + + mm/s + + + + Responsiveness + + + + 10.0 + + + + Drift speeds + + + + 50 + + + + 100 + + + + Natural movement filter: cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + + + + Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + + + + + tomDll + + Tom + + + + diff --git a/filter-nm/lang/stub.ts b/filter-nm/lang/stub.ts new file mode 100644 index 00000000..f212040f --- /dev/null +++ b/filter-nm/lang/stub.ts @@ -0,0 +1,78 @@ + + + + + UICdialog_tom + + Dialog + + + + X + + + + Y + + + + Z + + + + Yaw + + + + Pitch + + + + Roll + + + + °/s + + + + mm/s + + + + Responsiveness + + + + 10.0 + + + + Drift speeds + + + + 50 + + + + 100 + + + + Natural movement filter: cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + + + + Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + + + + + tomDll + + Tom + + + + diff --git a/filter-nm/lang/zh_CN.ts b/filter-nm/lang/zh_CN.ts new file mode 100644 index 00000000..5a322913 --- /dev/null +++ b/filter-nm/lang/zh_CN.ts @@ -0,0 +1,78 @@ + + + + + UICdialog_tom + + Dialog + + + + X + + + + Y + + + + Z + + + + Yaw + + + + Pitch + + + + Roll + + + + °/s + + + + mm/s + + + + Responsiveness + + + + 10.0 + + + + Drift speeds + + + + 50 + + + + 100 + + + + Natural movement filter: cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + + + + Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + + + + + tomDll + + Tom + + + + diff --git a/filter-tom/CMakeLists.txt b/filter-tom/CMakeLists.txt deleted file mode 100644 index d98e90e2..00000000 --- a/filter-tom/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -otr_module(filter-tom) diff --git a/filter-tom/filter_tom.cpp b/filter-tom/filter_tom.cpp deleted file mode 100644 index 6bcfeae0..00000000 --- a/filter-tom/filter_tom.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright (c) 2023 Tom Brazier - * - * 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 "filter_tom.h" -#include "compat/math-imports.hpp" -#include "compat/macros.h" - -#include "api/plugin-api.hpp" -#include "opentrack/defs.hpp" - -#include - -tom::tom() -{ -} - -void tom::filter(const double* input, double* output) -{ - // order of axes: x, y, z, yaw, pitch, roll - if (unlikely(first_run)) - { - first_run = false; - t.start(); - - std::fill(speeds, speeds + 6, 0.0); - std::copy(input, input + 6, filtered_output); - } - else - { - const double dt = t.elapsed_seconds(); - t.start(); - - for (int i = 0; i < 6; i++) - { - double speed = (input[i] - last_input[i]) / dt; - speeds[i] += dt * (double)s.responsiveness[i] * (speed - speeds[i]); - filtered_output[i] += dt * (double)s.responsiveness[i] * min(1.0, abs(speeds[i]) / (double)s.drift_speeds[i]) * (input[i] - filtered_output[i]); - } - } - - std::copy(input, input + 6, last_input); - std::copy(filtered_output, filtered_output + 6, output); -} - -OPENTRACK_DECLARE_FILTER(tom, dialog_tom, tomDll) diff --git a/filter-tom/filter_tom.h b/filter-tom/filter_tom.h deleted file mode 100644 index 0f6d07c2..00000000 --- a/filter-tom/filter_tom.h +++ /dev/null @@ -1,93 +0,0 @@ -/* Copyright (c) 2023 Tom Brazier - * - * 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_tom_filtercontrols.h" - -#include "api/plugin-api.hpp" -#include "compat/timer.hpp" -#include "options/options.hpp" - -using namespace options; - -struct settings_tom : opts -{ - value responsiveness[6]; - value drift_speeds[6]; - - settings_tom() : - opts("tom-filter"), - responsiveness{ value(b, "x-responsiveness", { 10.0, .0, 20.0 }), - value(b, "y-responsiveness", { 10.0, .0, 20.0 }), - value(b, "z-responsiveness", { 10.0, .0, 20.0 }), - value(b, "yaw-responsiveness", { 10.0, .0, 20.0 }), - value(b, "pitch-responsiveness", { 10.0, .0, 20.0 }), - value(b, "roll-responsiveness", { 10.0, .0, 20.0 }) }, - drift_speeds{ value(b, "x-drift-speed", { 50.0, 1.0, 200.0 }), - value(b, "y-drift-speed", { 50.0, 1.0, 200.0 }), - value(b, "z-drift-speed", { 50.0, 1.0, 200.0 }), - value(b, "yaw-drift-speed", { 100.0, 1.0, 400.0 }), - value(b, "pitch-drift-speed", { 100.0, 1.0, 400.0 }), - value(b, "roll-drift-speed", { 100.0, 1.0, 400.0 }) } - { - } - - /* value kMinSmoothing, kMaxSmoothing, kSmoothingScaleCurve; - settings() - : opts("ewma-filter"), - kMinSmoothing(b, "min-smoothing", { .02, .01, 1 }), - kMaxSmoothing(b, "max-smoothing", { .7, .01, 1 }), - kSmoothingScaleCurve(b, "smoothing-scale-curve", { .8, .1, 5 }) - { - } -*/ -}; - -struct tom : IFilter -{ - tom(); - void filter(const double* input, double* output) override; - void center() override { first_run = true; } - module_status initialize() override { return status_ok(); } - -private: - double last_input[6]{}; - double speeds[6]{}; - double filtered_output[6]{}; - Timer t; - settings_tom s; - bool first_run = true; -}; - -class dialog_tom : public IFilterDialog -{ - Q_OBJECT -public: - dialog_tom(); - void register_filter(IFilter*) override {} - void unregister_filter() override {} - void save() override; - void reload() override; - bool embeddable() noexcept override { return true; } - void set_buttons_visible(bool x) override; - -private: - Ui::UICdialog_tom ui; - settings_tom s; - -private slots: - void doOK(); - void doCancel(); -}; - -class tomDll : public Metadata -{ - Q_OBJECT - - QString name() override { return tr("Tom"); } - QIcon icon() override { return QIcon(":/images/filter-16.png"); } -}; diff --git a/filter-tom/filter_tom_dialog.cpp b/filter-tom/filter_tom_dialog.cpp deleted file mode 100644 index 5a6ad3a4..00000000 --- a/filter-tom/filter_tom_dialog.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright (c) 2023 Tom Brazier - * - * 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 "filter_tom.h" - -using namespace options; - -dialog_tom::dialog_tom() -{ - ui.setupUi(this); - - tie_setting(s.responsiveness[0], ui.x_responsiveness_slider); - tie_setting(s.responsiveness[0], ui.x_responsiveness, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.responsiveness[1], ui.y_responsiveness_slider); - tie_setting(s.responsiveness[1], ui.y_responsiveness, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.responsiveness[2], ui.z_responsiveness_slider); - tie_setting(s.responsiveness[2], ui.z_responsiveness, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.responsiveness[3], ui.yaw_responsiveness_slider); - tie_setting(s.responsiveness[3], ui.yaw_responsiveness, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.responsiveness[4], ui.pitch_responsiveness_slider); - tie_setting(s.responsiveness[4], ui.pitch_responsiveness, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.responsiveness[5], ui.roll_responsiveness_slider); - tie_setting(s.responsiveness[5], ui.roll_responsiveness, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.drift_speeds[0], ui.x_drift_speed_slider); - tie_setting(s.drift_speeds[0], ui.x_drift_speed, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.drift_speeds[1], ui.y_drift_speed_slider); - tie_setting(s.drift_speeds[1], ui.y_drift_speed, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.drift_speeds[2], ui.z_drift_speed_slider); - tie_setting(s.drift_speeds[2], ui.z_drift_speed, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.drift_speeds[3], ui.yaw_drift_speed_slider); - tie_setting(s.drift_speeds[3], ui.yaw_drift_speed, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.drift_speeds[4], ui.pitch_drift_speed_slider); - tie_setting(s.drift_speeds[4], ui.pitch_drift_speed, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.drift_speeds[5], ui.roll_drift_speed_slider); - tie_setting(s.drift_speeds[5], ui.roll_drift_speed, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); -} - -void dialog_tom::doOK() -{ - save(); - close(); -} - -void dialog_tom::doCancel() -{ - close(); -} - -void dialog_tom::save() -{ - s.b->save(); -} - -void dialog_tom::reload() -{ - s.b->reload(); -} - -void dialog_tom::set_buttons_visible(bool x) -{ - ui.buttonBox->setVisible(x); -} diff --git a/filter-tom/lang/nl_NL.ts b/filter-tom/lang/nl_NL.ts deleted file mode 100644 index ce0aefe3..00000000 --- a/filter-tom/lang/nl_NL.ts +++ /dev/null @@ -1,78 +0,0 @@ - - - - - UICdialog_tom - - Dialog - - - - X - - - - Y - - - - Z - - - - Yaw - - - - Pitch - - - - Roll - - - - °/s - - - - mm/s - - - - Responsiveness - - - - 10.0 - - - - Drift speeds - - - - 50 - - - - 100 - - - - Natural movement filter: cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. - - - - Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. - - - - - tomDll - - Tom - - - - diff --git a/filter-tom/lang/ru_RU.ts b/filter-tom/lang/ru_RU.ts deleted file mode 100644 index b72d73ad..00000000 --- a/filter-tom/lang/ru_RU.ts +++ /dev/null @@ -1,78 +0,0 @@ - - - - - UICdialog_tom - - Dialog - - - - X - - - - Y - - - - Z - - - - Yaw - - - - Pitch - - - - Roll - - - - °/s - - - - mm/s - - - - Responsiveness - - - - 10.0 - - - - Drift speeds - - - - 50 - - - - 100 - - - - Natural movement filter: cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. - - - - Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. - - - - - tomDll - - Tom - - - - diff --git a/filter-tom/lang/stub.ts b/filter-tom/lang/stub.ts deleted file mode 100644 index f212040f..00000000 --- a/filter-tom/lang/stub.ts +++ /dev/null @@ -1,78 +0,0 @@ - - - - - UICdialog_tom - - Dialog - - - - X - - - - Y - - - - Z - - - - Yaw - - - - Pitch - - - - Roll - - - - °/s - - - - mm/s - - - - Responsiveness - - - - 10.0 - - - - Drift speeds - - - - 50 - - - - 100 - - - - Natural movement filter: cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. - - - - Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. - - - - - tomDll - - Tom - - - - diff --git a/filter-tom/lang/zh_CN.ts b/filter-tom/lang/zh_CN.ts deleted file mode 100644 index 5a322913..00000000 --- a/filter-tom/lang/zh_CN.ts +++ /dev/null @@ -1,78 +0,0 @@ - - - - - UICdialog_tom - - Dialog - - - - X - - - - Y - - - - Z - - - - Yaw - - - - Pitch - - - - Roll - - - - °/s - - - - mm/s - - - - Responsiveness - - - - 10.0 - - - - Drift speeds - - - - 50 - - - - 100 - - - - Natural movement filter: cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. - - - - Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. - - - - - tomDll - - Tom - - - - diff --git a/filter-tom/tom_filtercontrols.ui b/filter-tom/tom_filtercontrols.ui deleted file mode 100644 index 1a135c1e..00000000 --- a/filter-tom/tom_filtercontrols.ui +++ /dev/null @@ -1,610 +0,0 @@ - - - UICdialog_tom - - - - 0 - 0 - 438 - 559 - - - - Dialog - - - - - - Responsiveness - - - - - - X - - - - - - - - 0 - 0 - - - - - 30 - 0 - - - - 10.0 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - 40 - - - Qt::Horizontal - - - - - - - Y - - - - - - - - 30 - 0 - - - - 10.0 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - 40 - - - Qt::Horizontal - - - - - - - Z - - - - - - - - 30 - 0 - - - - 10.0 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - 40 - - - Qt::Horizontal - - - - - - - Yaw - - - - - - - - 30 - 0 - - - - 10.0 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - 40 - - - Qt::Horizontal - - - - - - - Pitch - - - - - - - - 30 - 0 - - - - 10.0 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - 40 - - - Qt::Horizontal - - - - - - - Roll - - - - - - - - 30 - 0 - - - - 10.0 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - 40 - - - Qt::Horizontal - - - - - - - - - - - 0 - 0 - - - - Natural movement filter by Tom Brazier: Cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. - - - Qt::PlainText - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - Drift speeds - - - - - - Z - - - - - - - 1 - - - 200 - - - Qt::Horizontal - - - - - - - Roll - - - - - - - - 30 - 0 - - - - 50 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - °/s - - - - - - - mm/s - - - - - - - °/s - - - - - - - 1 - - - 200 - - - Qt::Horizontal - - - - - - - - 30 - 0 - - - - 50 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 30 - 0 - - - - 100 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Y - - - - - - - - 30 - 0 - - - - 100 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Pitch - - - - - - - 1 - - - 400 - - - Qt::Horizontal - - - - - - - X - - - - - - - - 30 - 0 - - - - 100 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - mm/s - - - - - - - mm/s - - - - - - - Yaw - - - - - - - - 0 - 0 - - - - 1 - - - 200 - - - Qt::Horizontal - - - - - - - °/s - - - - - - - 1 - - - 400 - - - Qt::Horizontal - - - - - - - 1 - - - 400 - - - Qt::Horizontal - - - - - - - - 0 - 0 - - - - - 30 - 0 - - - - 50 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - buttonBox - accepted() - UICdialog_tom - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - UICdialog_tom - reject() - - - 316 - 260 - - - 286 - 274 - - - - - -- cgit v1.2.3 From bd04206c6a86a46bceff710749ef4119303a1f85 Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Tue, 30 May 2023 16:34:37 +0100 Subject: Picked a name - natural movement filter --- filter-nm/CMakeLists.txt | 2 +- filter-nm/ftnoir_filter_nm.cpp | 8 ++++---- filter-nm/ftnoir_filter_nm.h | 26 +++++++++++++------------- filter-nm/ftnoir_filter_nm_dialog.cpp | 14 +++++++------- filter-nm/ftnoir_nm_filtercontrols.ui | 8 ++++---- filter-nm/lang/nl_NL.ts | 6 +++--- filter-nm/lang/ru_RU.ts | 6 +++--- filter-nm/lang/stub.ts | 6 +++--- filter-nm/lang/zh_CN.ts | 6 +++--- 9 files changed, 41 insertions(+), 41 deletions(-) diff --git a/filter-nm/CMakeLists.txt b/filter-nm/CMakeLists.txt index d98e90e2..49daaee2 100644 --- a/filter-nm/CMakeLists.txt +++ b/filter-nm/CMakeLists.txt @@ -1 +1 @@ -otr_module(filter-tom) +otr_module(filter-nm) diff --git a/filter-nm/ftnoir_filter_nm.cpp b/filter-nm/ftnoir_filter_nm.cpp index 6bcfeae0..b616f722 100644 --- a/filter-nm/ftnoir_filter_nm.cpp +++ b/filter-nm/ftnoir_filter_nm.cpp @@ -4,7 +4,7 @@ * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. */ -#include "filter_tom.h" +#include "ftnoir_filter_nm.h" #include "compat/math-imports.hpp" #include "compat/macros.h" @@ -13,11 +13,11 @@ #include -tom::tom() +filter_nm::filter_nm() { } -void tom::filter(const double* input, double* output) +void filter_nm::filter(const double* input, double* output) { // order of axes: x, y, z, yaw, pitch, roll if (unlikely(first_run)) @@ -45,4 +45,4 @@ void tom::filter(const double* input, double* output) std::copy(filtered_output, filtered_output + 6, output); } -OPENTRACK_DECLARE_FILTER(tom, dialog_tom, tomDll) +OPENTRACK_DECLARE_FILTER(filter_nm, dialog_nm, nmDll) diff --git a/filter-nm/ftnoir_filter_nm.h b/filter-nm/ftnoir_filter_nm.h index 0f6d07c2..fe0924d1 100644 --- a/filter-nm/ftnoir_filter_nm.h +++ b/filter-nm/ftnoir_filter_nm.h @@ -6,7 +6,7 @@ */ #pragma once -#include "ui_tom_filtercontrols.h" +#include "ui_ftnoir_nm_filtercontrols.h" #include "api/plugin-api.hpp" #include "compat/timer.hpp" @@ -14,13 +14,13 @@ using namespace options; -struct settings_tom : opts +struct settings_nm : opts { value responsiveness[6]; value drift_speeds[6]; - settings_tom() : - opts("tom-filter"), + settings_nm() : + opts("nm-filter"), responsiveness{ value(b, "x-responsiveness", { 10.0, .0, 20.0 }), value(b, "y-responsiveness", { 10.0, .0, 20.0 }), value(b, "z-responsiveness", { 10.0, .0, 20.0 }), @@ -47,9 +47,9 @@ struct settings_tom : opts */ }; -struct tom : IFilter +struct filter_nm : IFilter { - tom(); + filter_nm(); void filter(const double* input, double* output) override; void center() override { first_run = true; } module_status initialize() override { return status_ok(); } @@ -59,15 +59,15 @@ private: double speeds[6]{}; double filtered_output[6]{}; Timer t; - settings_tom s; + settings_nm s; bool first_run = true; }; -class dialog_tom : public IFilterDialog +class dialog_nm : public IFilterDialog { Q_OBJECT public: - dialog_tom(); + dialog_nm(); void register_filter(IFilter*) override {} void unregister_filter() override {} void save() override; @@ -76,18 +76,18 @@ public: void set_buttons_visible(bool x) override; private: - Ui::UICdialog_tom ui; - settings_tom s; + Ui::UICdialog_nm ui; + settings_nm s; private slots: void doOK(); void doCancel(); }; -class tomDll : public Metadata +class nmDll : public Metadata { Q_OBJECT - QString name() override { return tr("Tom"); } + QString name() override { return tr("NaturalMovement"); } QIcon icon() override { return QIcon(":/images/filter-16.png"); } }; diff --git a/filter-nm/ftnoir_filter_nm_dialog.cpp b/filter-nm/ftnoir_filter_nm_dialog.cpp index 5a6ad3a4..ccf894db 100644 --- a/filter-nm/ftnoir_filter_nm_dialog.cpp +++ b/filter-nm/ftnoir_filter_nm_dialog.cpp @@ -4,11 +4,11 @@ * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. */ -#include "filter_tom.h" +#include "ftnoir_filter_nm.h" using namespace options; -dialog_tom::dialog_tom() +dialog_nm::dialog_nm() { ui.setupUi(this); @@ -61,28 +61,28 @@ dialog_tom::dialog_tom() { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); } -void dialog_tom::doOK() +void dialog_nm::doOK() { save(); close(); } -void dialog_tom::doCancel() +void dialog_nm::doCancel() { close(); } -void dialog_tom::save() +void dialog_nm::save() { s.b->save(); } -void dialog_tom::reload() +void dialog_nm::reload() { s.b->reload(); } -void dialog_tom::set_buttons_visible(bool x) +void dialog_nm::set_buttons_visible(bool x) { ui.buttonBox->setVisible(x); } diff --git a/filter-nm/ftnoir_nm_filtercontrols.ui b/filter-nm/ftnoir_nm_filtercontrols.ui index 1a135c1e..c50cc1a6 100644 --- a/filter-nm/ftnoir_nm_filtercontrols.ui +++ b/filter-nm/ftnoir_nm_filtercontrols.ui @@ -1,7 +1,7 @@ - UICdialog_tom - + UICdialog_nm + 0 @@ -577,7 +577,7 @@ buttonBox accepted() - UICdialog_tom + UICdialog_nm accept() @@ -593,7 +593,7 @@ buttonBox rejected() - UICdialog_tom + UICdialog_nm reject() diff --git a/filter-nm/lang/nl_NL.ts b/filter-nm/lang/nl_NL.ts index ce0aefe3..b3c85f91 100644 --- a/filter-nm/lang/nl_NL.ts +++ b/filter-nm/lang/nl_NL.ts @@ -2,7 +2,7 @@ - UICdialog_tom + UICdialog_nm Dialog @@ -69,9 +69,9 @@ - tomDll + nmDll - Tom + NaturalMovement diff --git a/filter-nm/lang/ru_RU.ts b/filter-nm/lang/ru_RU.ts index b72d73ad..456ed403 100644 --- a/filter-nm/lang/ru_RU.ts +++ b/filter-nm/lang/ru_RU.ts @@ -2,7 +2,7 @@ - UICdialog_tom + UICdialog_nm Dialog @@ -69,9 +69,9 @@ - tomDll + nmDll - Tom + NaturalMovement diff --git a/filter-nm/lang/stub.ts b/filter-nm/lang/stub.ts index f212040f..875051cd 100644 --- a/filter-nm/lang/stub.ts +++ b/filter-nm/lang/stub.ts @@ -2,7 +2,7 @@ - UICdialog_tom + UICdialog_nm Dialog @@ -69,9 +69,9 @@ - tomDll + nmDll - Tom + NaturalMovement diff --git a/filter-nm/lang/zh_CN.ts b/filter-nm/lang/zh_CN.ts index 5a322913..561030af 100644 --- a/filter-nm/lang/zh_CN.ts +++ b/filter-nm/lang/zh_CN.ts @@ -2,7 +2,7 @@ - UICdialog_tom + UICdialog_nm Dialog @@ -69,9 +69,9 @@ - tomDll + nmDll - Tom + NaturalMovement -- cgit v1.2.3 From 1e88d84e1df7d04e0a17d70e07ecdc2586d8b5e6 Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Tue, 30 May 2023 16:56:06 +0100 Subject: dialog cleanup --- filter-nm/ftnoir_nm_filtercontrols.ui | 26 ++++++++++++++++++++------ filter-nm/lang/nl_NL.ts | 4 ++-- filter-nm/lang/ru_RU.ts | 4 ++-- filter-nm/lang/stub.ts | 4 ++-- filter-nm/lang/zh_CN.ts | 4 ++-- 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/filter-nm/ftnoir_nm_filtercontrols.ui b/filter-nm/ftnoir_nm_filtercontrols.ui index c50cc1a6..93f3cb91 100644 --- a/filter-nm/ftnoir_nm_filtercontrols.ui +++ b/filter-nm/ftnoir_nm_filtercontrols.ui @@ -292,7 +292,7 @@ - 30 + 40 0 @@ -342,7 +342,7 @@ - 30 + 40 0 @@ -358,7 +358,7 @@ - 30 + 40 0 @@ -381,7 +381,7 @@ - 30 + 40 0 @@ -424,7 +424,7 @@ - 30 + 40 0 @@ -519,7 +519,7 @@ - 30 + 40 0 @@ -572,6 +572,20 @@ + + x_responsiveness_slider + y_responsiveness_slider + z_responsiveness_slider + yaw_responsiveness_slider + pitch_responsiveness_slider + roll_responsiveness_slider + x_drift_speed_slider + y_drift_speed_slider + z_drift_speed_slider + yaw_drift_speed_slider + pitch_drift_speed_slider + roll_drift_speed_slider + diff --git a/filter-nm/lang/nl_NL.ts b/filter-nm/lang/nl_NL.ts index b3c85f91..d68712e9 100644 --- a/filter-nm/lang/nl_NL.ts +++ b/filter-nm/lang/nl_NL.ts @@ -60,11 +60,11 @@ - Natural movement filter: cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. - Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + Natural movement filter by Tom Brazier: Cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. diff --git a/filter-nm/lang/ru_RU.ts b/filter-nm/lang/ru_RU.ts index 456ed403..9ea3d158 100644 --- a/filter-nm/lang/ru_RU.ts +++ b/filter-nm/lang/ru_RU.ts @@ -60,11 +60,11 @@ - Natural movement filter: cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. - Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + Natural movement filter by Tom Brazier: Cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. diff --git a/filter-nm/lang/stub.ts b/filter-nm/lang/stub.ts index 875051cd..61c1f5bc 100644 --- a/filter-nm/lang/stub.ts +++ b/filter-nm/lang/stub.ts @@ -60,11 +60,11 @@ - Natural movement filter: cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. - Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + Natural movement filter by Tom Brazier: Cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. diff --git a/filter-nm/lang/zh_CN.ts b/filter-nm/lang/zh_CN.ts index 561030af..d6490d99 100644 --- a/filter-nm/lang/zh_CN.ts +++ b/filter-nm/lang/zh_CN.ts @@ -60,11 +60,11 @@ - Natural movement filter: cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. - Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + Natural movement filter by Tom Brazier: Cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. -- cgit v1.2.3 From 26db426f05657edcaf4bd5ea84d807e63c7ef181 Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Fri, 2 Jun 2023 15:25:04 +0100 Subject: corrected EWA logic for large values of dt * responsiveness --- filter-nm/ftnoir_filter_nm.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/filter-nm/ftnoir_filter_nm.cpp b/filter-nm/ftnoir_filter_nm.cpp index b616f722..cd395f1b 100644 --- a/filter-nm/ftnoir_filter_nm.cpp +++ b/filter-nm/ftnoir_filter_nm.cpp @@ -36,8 +36,10 @@ void filter_nm::filter(const double* input, double* output) for (int i = 0; i < 6; i++) { double speed = (input[i] - last_input[i]) / dt; - speeds[i] += dt * (double)s.responsiveness[i] * (speed - speeds[i]); - filtered_output[i] += dt * (double)s.responsiveness[i] * min(1.0, abs(speeds[i]) / (double)s.drift_speeds[i]) * (input[i] - filtered_output[i]); + double timescale = 1. / *(s.responsiveness[i]); + double alpha = dt / (dt + timescale); + speeds[i] += alpha * (speed - speeds[i]); // EWA + filtered_output[i] += alpha * min(1.0, abs(speeds[i]) / *(s.drift_speeds[i])) * (input[i] - filtered_output[i]); } } -- cgit v1.2.3 From 0962b47c9cd39a72160b3c0d96f21cd7eb907f26 Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Sat, 3 Jun 2023 21:15:39 +0100 Subject: Removed commented sample code --- filter-nm/ftnoir_filter_nm.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/filter-nm/ftnoir_filter_nm.h b/filter-nm/ftnoir_filter_nm.h index fe0924d1..d2eae43d 100644 --- a/filter-nm/ftnoir_filter_nm.h +++ b/filter-nm/ftnoir_filter_nm.h @@ -35,16 +35,6 @@ struct settings_nm : opts value(b, "roll-drift-speed", { 100.0, 1.0, 400.0 }) } { } - - /* value kMinSmoothing, kMaxSmoothing, kSmoothingScaleCurve; - settings() - : opts("ewma-filter"), - kMinSmoothing(b, "min-smoothing", { .02, .01, 1 }), - kMaxSmoothing(b, "max-smoothing", { .7, .01, 1 }), - kSmoothingScaleCurve(b, "smoothing-scale-curve", { .8, .1, 5 }) - { - } -*/ }; struct filter_nm : IFilter -- cgit v1.2.3 From 049a84956400a4f764a850ec7c6e42c43a506c84 Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Mon, 5 Jun 2023 14:38:44 +0100 Subject: Moved hamilton tools to compat so they can be used more widely --- compat/hamilton-tools.cpp | 135 +++++++++++++++++++++++++++++ compat/hamilton-tools.h | 27 ++++++ filter-hamilton/ftnoir_filter_hamilton.cpp | 2 +- filter-hamilton/ftnoir_filter_hamilton.h | 2 +- filter-hamilton/hamilton-tools.cpp | 135 ----------------------------- filter-hamilton/hamilton-tools.h | 27 ------ 6 files changed, 164 insertions(+), 164 deletions(-) create mode 100644 compat/hamilton-tools.cpp create mode 100644 compat/hamilton-tools.h delete mode 100644 filter-hamilton/hamilton-tools.cpp delete mode 100644 filter-hamilton/hamilton-tools.h diff --git a/compat/hamilton-tools.cpp b/compat/hamilton-tools.cpp new file mode 100644 index 00000000..e18082a8 --- /dev/null +++ b/compat/hamilton-tools.cpp @@ -0,0 +1,135 @@ +#include "hamilton-tools.h" +#include + +double VectorLength(const tVector v) +{ + return(sqrt(v.v[0]*v.v[0] + v.v[1]*v.v[1] + v.v[2]*v.v[2])); +} + +double sqr(const double v) { return(v*v); } + +double VectorDistance(const double v1[], const tVector v2) +{ + return(sqrt(sqr(v2.v[0]-v1[0])+sqr(v2.v[1]-v1[1])+sqr(v2.v[2]-v1[2]))); +} + +tVector Lerp(const tVector s, const double d[], const double alpha) +{ + tVector V; + V.v[0] = s.v[0] + (d[0] - s.v[0]) * alpha; + V.v[1] = s.v[1] + (d[1] - s.v[1]) * alpha; + V.v[2] = s.v[2] + (d[2] - s.v[2]) * alpha; + return(V); +} + +tQuat QuatFromAngleAxe(const double angle, const tVector axe) +{ + double a = TO_RAD * 0.5 * angle; + double d = sin(a) / VectorLength(axe); + return ( tQuat ( + axe.v[0] * d, + axe.v[1] * d, + axe.v[2] * d, + cos(a) + ) + ); +} + +tQuat QuatMultiply(const tQuat qL, const tQuat qR) +{ + tQuat Q; + Q.x = qL.w*qR.x + qL.x*qR.w + qL.y*qR.z - qL.z*qR.y; + Q.y = qL.w*qR.y + qL.y*qR.w + qL.z*qR.x - qL.x*qR.z; + Q.z = qL.w*qR.z + qL.z*qR.w + qL.x*qR.y - qL.y*qR.x; + Q.w = qL.w*qR.w - qL.x*qR.x - qL.y*qR.y - qL.z*qR.z; + return(Q); +} + +double AngleBetween(const tQuat S, const tQuat D) +{ + return( TO_DEG * 2*acos(fabs(S.x*D.x + S.y*D.y + S.z*D.z + S.w*D.w)) ); +} + +tQuat QuatFromYPR(const double YPR[]) +{ + tQuat Q, Qp, Qy; + Q = QuatFromAngleAxe( -YPR[2], {0, 0, 1} ); //Roll, Z axe + Qp = QuatFromAngleAxe( -YPR[1], {1, 0, 0} ); //Pitch, X axe + Qy = QuatFromAngleAxe( -YPR[0], {0, 1, 0} ); //Yaw, Y axe + + Q = QuatMultiply(Qp, Q); + return(QuatMultiply(Qy, Q)); +} + +void Normalize(tQuat Q) +{ + double m = sqrt(Q.x*Q.x + Q.y*Q.y + Q.z*Q.z + Q.w*Q.w); + if (m > EPSILON) + { + m = 1 / m; + Q.x = Q.x * m; + Q.y = Q.y * m; + Q.z = Q.z * m; + Q.w = Q.w * m; + } + else Q = tQuat(0, 0, 0, 1); +} + +tQuat Slerp(const tQuat S, const tQuat D, const double alpha) +{ + // calc cosine of half angle + double cosin = S.x*D.x + S.y*D.y + S.z*D.z + S.w*D.w; + + // select nearest rotation direction + tQuat Q; + if (cosin < 0) + { + cosin = - cosin; + Q.x = - D.x; + Q.y = - D.y; + Q.z = - D.z; + Q.w = - D.w; + } + else Q = D; + + // calculate coefficients + double scale0, scale1; + if ((1.0 - cosin) > EPSILON) + { + double omega = acos(cosin); + double sinus = 1 / sin(omega); + scale0 = sin((1.0 - alpha) * omega) * sinus; + scale1 = sin(alpha * omega)* sinus; + } + else + { + scale0 = 1.0 - alpha; + scale1 = alpha; + } + + Q.x = scale0 * S.x + scale1 * Q.x; + Q.y = scale0 * S.y + scale1 * Q.y; + Q.z = scale0 * S.z + scale1 * Q.z; + Q.w = scale0 * S.w + scale1 * Q.w; + + Normalize(Q); + + return( Q ); +} + +void QuatToYPR(const tQuat Q, double YPR[]) +{ + const double xx = Q.x * Q.x; + const double xy = Q.x * Q.y; + const double xz = Q.x * Q.z; + const double xw = Q.x * Q.w; + const double yy = Q.y * Q.y; + const double yz = Q.y * Q.z; + const double yw = Q.y * Q.w; + const double zz = Q.z * Q.z; + const double zw = Q.z * Q.w; + + YPR[0] = TO_DEG * ( -atan2( 2 * ( xz + yw ), 1 - 2 * ( xx + yy ) )); + YPR[1] = TO_DEG * ( asin ( 2 * ( yz - xw ) )); + YPR[2] = TO_DEG * ( -atan2( 2 * ( xy + zw ), 1 - 2 * ( xx + zz ) )); +} diff --git a/compat/hamilton-tools.h b/compat/hamilton-tools.h new file mode 100644 index 00000000..2e288225 --- /dev/null +++ b/compat/hamilton-tools.h @@ -0,0 +1,27 @@ +#pragma once + +#include "compat/math.hpp" +constexpr double TO_RAD = (M_PI / 180); +constexpr double TO_DEG = (180 / M_PI); +constexpr double EPSILON = 1e-30; + +struct tVector +{ + double v[3]; + tVector(double X = 0, double Y = 0, double Z = 0) {v[0]=X; v[1]=Y; v[2]=Z;} + tVector(double V[]) {v[0]=V[0]; v[1]=V[1]; v[2]=V[2];} +}; + +struct tQuat +{ + double x, y, z, w; + tQuat(double X = 0, double Y = 0, double Z = 0, double W = 1) + {x = X; y = Y; z = Z; w = W;} +}; + +double VectorDistance(const double v1[], const tVector v2); +tVector Lerp (const tVector s, const double d[], const double alpha); +tQuat QuatFromYPR (const double YPR[]); +double AngleBetween (const tQuat S, const tQuat D); +tQuat Slerp (const tQuat S, const tQuat D, const double alpha); +void QuatToYPR (const tQuat Q, double YPR[]); diff --git a/filter-hamilton/ftnoir_filter_hamilton.cpp b/filter-hamilton/ftnoir_filter_hamilton.cpp index 7bbc91de..c4429ecc 100644 --- a/filter-hamilton/ftnoir_filter_hamilton.cpp +++ b/filter-hamilton/ftnoir_filter_hamilton.cpp @@ -9,7 +9,7 @@ #include #include #include "api/plugin-api.hpp" -#include "hamilton-tools.h" +#include "compat/hamilton-tools.h" hamilton::hamilton() = default; diff --git a/filter-hamilton/ftnoir_filter_hamilton.h b/filter-hamilton/ftnoir_filter_hamilton.h index b724d973..199eef80 100644 --- a/filter-hamilton/ftnoir_filter_hamilton.h +++ b/filter-hamilton/ftnoir_filter_hamilton.h @@ -13,7 +13,7 @@ #include #include "options/options.hpp" //#include "compat/timer.hpp" -#include "hamilton-tools.h" +#include "compat/hamilton-tools.h" using namespace options; diff --git a/filter-hamilton/hamilton-tools.cpp b/filter-hamilton/hamilton-tools.cpp deleted file mode 100644 index e18082a8..00000000 --- a/filter-hamilton/hamilton-tools.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "hamilton-tools.h" -#include - -double VectorLength(const tVector v) -{ - return(sqrt(v.v[0]*v.v[0] + v.v[1]*v.v[1] + v.v[2]*v.v[2])); -} - -double sqr(const double v) { return(v*v); } - -double VectorDistance(const double v1[], const tVector v2) -{ - return(sqrt(sqr(v2.v[0]-v1[0])+sqr(v2.v[1]-v1[1])+sqr(v2.v[2]-v1[2]))); -} - -tVector Lerp(const tVector s, const double d[], const double alpha) -{ - tVector V; - V.v[0] = s.v[0] + (d[0] - s.v[0]) * alpha; - V.v[1] = s.v[1] + (d[1] - s.v[1]) * alpha; - V.v[2] = s.v[2] + (d[2] - s.v[2]) * alpha; - return(V); -} - -tQuat QuatFromAngleAxe(const double angle, const tVector axe) -{ - double a = TO_RAD * 0.5 * angle; - double d = sin(a) / VectorLength(axe); - return ( tQuat ( - axe.v[0] * d, - axe.v[1] * d, - axe.v[2] * d, - cos(a) - ) - ); -} - -tQuat QuatMultiply(const tQuat qL, const tQuat qR) -{ - tQuat Q; - Q.x = qL.w*qR.x + qL.x*qR.w + qL.y*qR.z - qL.z*qR.y; - Q.y = qL.w*qR.y + qL.y*qR.w + qL.z*qR.x - qL.x*qR.z; - Q.z = qL.w*qR.z + qL.z*qR.w + qL.x*qR.y - qL.y*qR.x; - Q.w = qL.w*qR.w - qL.x*qR.x - qL.y*qR.y - qL.z*qR.z; - return(Q); -} - -double AngleBetween(const tQuat S, const tQuat D) -{ - return( TO_DEG * 2*acos(fabs(S.x*D.x + S.y*D.y + S.z*D.z + S.w*D.w)) ); -} - -tQuat QuatFromYPR(const double YPR[]) -{ - tQuat Q, Qp, Qy; - Q = QuatFromAngleAxe( -YPR[2], {0, 0, 1} ); //Roll, Z axe - Qp = QuatFromAngleAxe( -YPR[1], {1, 0, 0} ); //Pitch, X axe - Qy = QuatFromAngleAxe( -YPR[0], {0, 1, 0} ); //Yaw, Y axe - - Q = QuatMultiply(Qp, Q); - return(QuatMultiply(Qy, Q)); -} - -void Normalize(tQuat Q) -{ - double m = sqrt(Q.x*Q.x + Q.y*Q.y + Q.z*Q.z + Q.w*Q.w); - if (m > EPSILON) - { - m = 1 / m; - Q.x = Q.x * m; - Q.y = Q.y * m; - Q.z = Q.z * m; - Q.w = Q.w * m; - } - else Q = tQuat(0, 0, 0, 1); -} - -tQuat Slerp(const tQuat S, const tQuat D, const double alpha) -{ - // calc cosine of half angle - double cosin = S.x*D.x + S.y*D.y + S.z*D.z + S.w*D.w; - - // select nearest rotation direction - tQuat Q; - if (cosin < 0) - { - cosin = - cosin; - Q.x = - D.x; - Q.y = - D.y; - Q.z = - D.z; - Q.w = - D.w; - } - else Q = D; - - // calculate coefficients - double scale0, scale1; - if ((1.0 - cosin) > EPSILON) - { - double omega = acos(cosin); - double sinus = 1 / sin(omega); - scale0 = sin((1.0 - alpha) * omega) * sinus; - scale1 = sin(alpha * omega)* sinus; - } - else - { - scale0 = 1.0 - alpha; - scale1 = alpha; - } - - Q.x = scale0 * S.x + scale1 * Q.x; - Q.y = scale0 * S.y + scale1 * Q.y; - Q.z = scale0 * S.z + scale1 * Q.z; - Q.w = scale0 * S.w + scale1 * Q.w; - - Normalize(Q); - - return( Q ); -} - -void QuatToYPR(const tQuat Q, double YPR[]) -{ - const double xx = Q.x * Q.x; - const double xy = Q.x * Q.y; - const double xz = Q.x * Q.z; - const double xw = Q.x * Q.w; - const double yy = Q.y * Q.y; - const double yz = Q.y * Q.z; - const double yw = Q.y * Q.w; - const double zz = Q.z * Q.z; - const double zw = Q.z * Q.w; - - YPR[0] = TO_DEG * ( -atan2( 2 * ( xz + yw ), 1 - 2 * ( xx + yy ) )); - YPR[1] = TO_DEG * ( asin ( 2 * ( yz - xw ) )); - YPR[2] = TO_DEG * ( -atan2( 2 * ( xy + zw ), 1 - 2 * ( xx + zz ) )); -} diff --git a/filter-hamilton/hamilton-tools.h b/filter-hamilton/hamilton-tools.h deleted file mode 100644 index 2e288225..00000000 --- a/filter-hamilton/hamilton-tools.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "compat/math.hpp" -constexpr double TO_RAD = (M_PI / 180); -constexpr double TO_DEG = (180 / M_PI); -constexpr double EPSILON = 1e-30; - -struct tVector -{ - double v[3]; - tVector(double X = 0, double Y = 0, double Z = 0) {v[0]=X; v[1]=Y; v[2]=Z;} - tVector(double V[]) {v[0]=V[0]; v[1]=V[1]; v[2]=V[2];} -}; - -struct tQuat -{ - double x, y, z, w; - tQuat(double X = 0, double Y = 0, double Z = 0, double W = 1) - {x = X; y = Y; z = Z; w = W;} -}; - -double VectorDistance(const double v1[], const tVector v2); -tVector Lerp (const tVector s, const double d[], const double alpha); -tQuat QuatFromYPR (const double YPR[]); -double AngleBetween (const tQuat S, const tQuat D); -tQuat Slerp (const tQuat S, const tQuat D, const double alpha); -void QuatToYPR (const tQuat Q, double YPR[]); -- cgit v1.2.3 From 91c278657ee5e424dcc1b7c83d078fde18cf8c55 Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Mon, 5 Jun 2023 15:02:07 +0100 Subject: Export hamilton tools functions --- compat/hamilton-tools.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/compat/hamilton-tools.h b/compat/hamilton-tools.h index 2e288225..6bcd7b5d 100644 --- a/compat/hamilton-tools.h +++ b/compat/hamilton-tools.h @@ -1,6 +1,8 @@ #pragma once +#include "export.hpp" #include "compat/math.hpp" + constexpr double TO_RAD = (M_PI / 180); constexpr double TO_DEG = (180 / M_PI); constexpr double EPSILON = 1e-30; @@ -19,9 +21,9 @@ struct tQuat {x = X; y = Y; z = Z; w = W;} }; -double VectorDistance(const double v1[], const tVector v2); -tVector Lerp (const tVector s, const double d[], const double alpha); -tQuat QuatFromYPR (const double YPR[]); -double AngleBetween (const tQuat S, const tQuat D); -tQuat Slerp (const tQuat S, const tQuat D, const double alpha); -void QuatToYPR (const tQuat Q, double YPR[]); +double OTR_COMPAT_EXPORT VectorDistance(const double v1[], const tVector v2); +tVector OTR_COMPAT_EXPORT Lerp (const tVector s, const double d[], const double alpha); +tQuat OTR_COMPAT_EXPORT QuatFromYPR (const double YPR[]); +double OTR_COMPAT_EXPORT AngleBetween (const tQuat S, const tQuat D); +tQuat OTR_COMPAT_EXPORT Slerp (const tQuat S, const tQuat D, const double alpha); +void OTR_COMPAT_EXPORT QuatToYPR (const tQuat Q, double YPR[]); -- cgit v1.2.3 From 8af36d5f6590b4f49acc288f9113cca4df3c99a0 Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Mon, 5 Jun 2023 15:26:24 +0100 Subject: Changed hamiltons tools to use pass by reference --- compat/hamilton-tools.cpp | 18 +++++++++--------- compat/hamilton-tools.h | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/compat/hamilton-tools.cpp b/compat/hamilton-tools.cpp index e18082a8..dfbb4630 100644 --- a/compat/hamilton-tools.cpp +++ b/compat/hamilton-tools.cpp @@ -1,19 +1,19 @@ #include "hamilton-tools.h" #include -double VectorLength(const tVector v) +double VectorLength(const tVector& v) { return(sqrt(v.v[0]*v.v[0] + v.v[1]*v.v[1] + v.v[2]*v.v[2])); } double sqr(const double v) { return(v*v); } -double VectorDistance(const double v1[], const tVector v2) +double VectorDistance(const double v1[], const tVector& v2) { return(sqrt(sqr(v2.v[0]-v1[0])+sqr(v2.v[1]-v1[1])+sqr(v2.v[2]-v1[2]))); } -tVector Lerp(const tVector s, const double d[], const double alpha) +tVector Lerp(const tVector& s, const double d[], const double alpha) { tVector V; V.v[0] = s.v[0] + (d[0] - s.v[0]) * alpha; @@ -22,7 +22,7 @@ tVector Lerp(const tVector s, const double d[], const double alpha) return(V); } -tQuat QuatFromAngleAxe(const double angle, const tVector axe) +tQuat QuatFromAngleAxe(const double angle, const tVector& axe) { double a = TO_RAD * 0.5 * angle; double d = sin(a) / VectorLength(axe); @@ -35,7 +35,7 @@ tQuat QuatFromAngleAxe(const double angle, const tVector axe) ); } -tQuat QuatMultiply(const tQuat qL, const tQuat qR) +tQuat QuatMultiply(const tQuat& qL, const tQuat& qR) { tQuat Q; Q.x = qL.w*qR.x + qL.x*qR.w + qL.y*qR.z - qL.z*qR.y; @@ -45,7 +45,7 @@ tQuat QuatMultiply(const tQuat qL, const tQuat qR) return(Q); } -double AngleBetween(const tQuat S, const tQuat D) +double AngleBetween(const tQuat& S, const tQuat& D) { return( TO_DEG * 2*acos(fabs(S.x*D.x + S.y*D.y + S.z*D.z + S.w*D.w)) ); } @@ -61,7 +61,7 @@ tQuat QuatFromYPR(const double YPR[]) return(QuatMultiply(Qy, Q)); } -void Normalize(tQuat Q) +void Normalize(tQuat& Q) { double m = sqrt(Q.x*Q.x + Q.y*Q.y + Q.z*Q.z + Q.w*Q.w); if (m > EPSILON) @@ -75,7 +75,7 @@ void Normalize(tQuat Q) else Q = tQuat(0, 0, 0, 1); } -tQuat Slerp(const tQuat S, const tQuat D, const double alpha) +tQuat Slerp(const tQuat& S, const tQuat& D, const double alpha) { // calc cosine of half angle double cosin = S.x*D.x + S.y*D.y + S.z*D.z + S.w*D.w; @@ -117,7 +117,7 @@ tQuat Slerp(const tQuat S, const tQuat D, const double alpha) return( Q ); } -void QuatToYPR(const tQuat Q, double YPR[]) +void QuatToYPR(const tQuat& Q, double YPR[]) { const double xx = Q.x * Q.x; const double xy = Q.x * Q.y; diff --git a/compat/hamilton-tools.h b/compat/hamilton-tools.h index 6bcd7b5d..73bc882c 100644 --- a/compat/hamilton-tools.h +++ b/compat/hamilton-tools.h @@ -21,9 +21,9 @@ struct tQuat {x = X; y = Y; z = Z; w = W;} }; -double OTR_COMPAT_EXPORT VectorDistance(const double v1[], const tVector v2); -tVector OTR_COMPAT_EXPORT Lerp (const tVector s, const double d[], const double alpha); +double OTR_COMPAT_EXPORT VectorDistance(const double v1[], const tVector& v2); +tVector OTR_COMPAT_EXPORT Lerp (const tVector& s, const double d[], const double alpha); tQuat OTR_COMPAT_EXPORT QuatFromYPR (const double YPR[]); -double OTR_COMPAT_EXPORT AngleBetween (const tQuat S, const tQuat D); -tQuat OTR_COMPAT_EXPORT Slerp (const tQuat S, const tQuat D, const double alpha); -void OTR_COMPAT_EXPORT QuatToYPR (const tQuat Q, double YPR[]); +double OTR_COMPAT_EXPORT AngleBetween (const tQuat& S, const tQuat& D); +tQuat OTR_COMPAT_EXPORT Slerp (const tQuat& S, const tQuat& D, const double alpha); +void OTR_COMPAT_EXPORT QuatToYPR (const tQuat& Q, double YPR[]); -- cgit v1.2.3 From 96f51ea8a769c2f49525e2424ace165ec3c05ef8 Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Mon, 5 Jun 2023 15:52:26 +0100 Subject: Added new vector and quaternion functions and inlined many of them --- compat/hamilton-tools.cpp | 26 -------------------- compat/hamilton-tools.h | 60 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 53 insertions(+), 33 deletions(-) diff --git a/compat/hamilton-tools.cpp b/compat/hamilton-tools.cpp index dfbb4630..eb0ef984 100644 --- a/compat/hamilton-tools.cpp +++ b/compat/hamilton-tools.cpp @@ -1,27 +1,6 @@ #include "hamilton-tools.h" #include -double VectorLength(const tVector& v) -{ - return(sqrt(v.v[0]*v.v[0] + v.v[1]*v.v[1] + v.v[2]*v.v[2])); -} - -double sqr(const double v) { return(v*v); } - -double VectorDistance(const double v1[], const tVector& v2) -{ - return(sqrt(sqr(v2.v[0]-v1[0])+sqr(v2.v[1]-v1[1])+sqr(v2.v[2]-v1[2]))); -} - -tVector Lerp(const tVector& s, const double d[], const double alpha) -{ - tVector V; - V.v[0] = s.v[0] + (d[0] - s.v[0]) * alpha; - V.v[1] = s.v[1] + (d[1] - s.v[1]) * alpha; - V.v[2] = s.v[2] + (d[2] - s.v[2]) * alpha; - return(V); -} - tQuat QuatFromAngleAxe(const double angle, const tVector& axe) { double a = TO_RAD * 0.5 * angle; @@ -45,11 +24,6 @@ tQuat QuatMultiply(const tQuat& qL, const tQuat& qR) return(Q); } -double AngleBetween(const tQuat& S, const tQuat& D) -{ - return( TO_DEG * 2*acos(fabs(S.x*D.x + S.y*D.y + S.z*D.z + S.w*D.w)) ); -} - tQuat QuatFromYPR(const double YPR[]) { tQuat Q, Qp, Qy; diff --git a/compat/hamilton-tools.h b/compat/hamilton-tools.h index 73bc882c..d4604301 100644 --- a/compat/hamilton-tools.h +++ b/compat/hamilton-tools.h @@ -11,7 +11,50 @@ struct tVector { double v[3]; tVector(double X = 0, double Y = 0, double Z = 0) {v[0]=X; v[1]=Y; v[2]=Z;} - tVector(double V[]) {v[0]=V[0]; v[1]=V[1]; v[2]=V[2];} + tVector(const double V[]) {v[0]=V[0]; v[1]=V[1]; v[2]=V[2];} + + void operator=(const tVector& other) + { + std::copy(other.v, other.v + 3, v); + } + inline const tVector operator+(const tVector& other) const + { + return tVector(v[0] + other.v[0], v[1] + other.v[1], v[2] + other.v[2]); + } + void operator+=(const tVector& other) + { + v[0] += other.v[0]; + v[1] += other.v[1]; + v[2] += other.v[2]; + } + const tVector operator-(const tVector& other) const + { + return tVector(v[0] - other.v[0], v[1] - other.v[1], v[2] - other.v[2]); + } + void operator-=(const tVector& other) + { + v[0] -= other.v[0]; + v[1] -= other.v[1]; + v[2] -= other.v[2]; + } + const tVector operator*(double scalar) const + { + return tVector(v[0] * scalar, v[1] * scalar, v[2] * scalar); + } + void operator*=(double scalar) + { + v[0] *= scalar; + v[1] *= scalar; + v[2] *= scalar; + } + const tVector operator/(double scalar) const + { + return *this * (1.0 / scalar); + } + void operator/= (double scalar) + { + *this *= 1.0 / scalar; + } }; struct tQuat @@ -21,9 +64,12 @@ struct tQuat {x = X; y = Y; z = Z; w = W;} }; -double OTR_COMPAT_EXPORT VectorDistance(const double v1[], const tVector& v2); -tVector OTR_COMPAT_EXPORT Lerp (const tVector& s, const double d[], const double alpha); -tQuat OTR_COMPAT_EXPORT QuatFromYPR (const double YPR[]); -double OTR_COMPAT_EXPORT AngleBetween (const tQuat& S, const tQuat& D); -tQuat OTR_COMPAT_EXPORT Slerp (const tQuat& S, const tQuat& D, const double alpha); -void OTR_COMPAT_EXPORT QuatToYPR (const tQuat& Q, double YPR[]); +inline double VectorLength(const tVector& v) { return sqrt(v.v[0] * v.v[0] + v.v[1] * v.v[1] + v.v[2] * v.v[2]); } +inline double VectorDistance(const tVector& v1, const tVector& v2) { return VectorLength(v2 - v1); } +inline tVector Lerp(const tVector& s, const tVector& d, const double alpha) { return s + (d - s) * alpha; } +tQuat OTR_COMPAT_EXPORT QuatFromYPR(const double YPR[]); +tQuat OTR_COMPAT_EXPORT QuatMultiply(const tQuat& qL, const tQuat& qR); +inline tQuat QuatDivide(const tQuat& qL, const tQuat& qR) { return QuatMultiply(qL, tQuat(-qR.x, -qR.y, -qR.z, qR.w)); } +inline double AngleBetween(const tQuat& S, const tQuat& D) { return TO_DEG * 2 * acos(fabs(S.x * D.x + S.y * D.y + S.z * D.z + S.w * D.w)); } +tQuat OTR_COMPAT_EXPORT Slerp(const tQuat& S, const tQuat& D, const double alpha); +void OTR_COMPAT_EXPORT QuatToYPR(const tQuat& Q, double YPR[]); -- cgit v1.2.3 From 89c346c1b1a7d0d395d446a2113ff5e6771441fe Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Mon, 5 Jun 2023 15:53:14 +0100 Subject: Changed nm filter to use vectors and quaterions like the hamilton filter for a spherical deadzone --- filter-nm/ftnoir_filter_nm.cpp | 43 ++-- filter-nm/ftnoir_filter_nm.h | 32 ++- filter-nm/ftnoir_filter_nm_dialog.cpp | 48 +--- filter-nm/ftnoir_nm_filtercontrols.ui | 400 ++++------------------------------ filter-nm/lang/nl_NL.ts | 36 +-- filter-nm/lang/ru_RU.ts | 36 +-- filter-nm/lang/stub.ts | 36 +-- filter-nm/lang/zh_CN.ts | 36 +-- 8 files changed, 136 insertions(+), 531 deletions(-) diff --git a/filter-nm/ftnoir_filter_nm.cpp b/filter-nm/ftnoir_filter_nm.cpp index cd395f1b..5d274790 100644 --- a/filter-nm/ftnoir_filter_nm.cpp +++ b/filter-nm/ftnoir_filter_nm.cpp @@ -19,32 +19,47 @@ filter_nm::filter_nm() void filter_nm::filter(const double* input, double* output) { + tVector position = { input[TX], input[TY], input[TZ] }; + tQuat rotation = QuatFromYPR(input + Yaw); + // order of axes: x, y, z, yaw, pitch, roll if (unlikely(first_run)) { first_run = false; t.start(); - std::fill(speeds, speeds + 6, 0.0); - std::copy(input, input + 6, filtered_output); + last_pos_speed = tVector(); + last_rot_speed = tQuat(); + last_pos_out = position; + last_rot_out = rotation; } else { const double dt = t.elapsed_seconds(); t.start(); - for (int i = 0; i < 6; i++) - { - double speed = (input[i] - last_input[i]) / dt; - double timescale = 1. / *(s.responsiveness[i]); - double alpha = dt / (dt + timescale); - speeds[i] += alpha * (speed - speeds[i]); // EWA - filtered_output[i] += alpha * min(1.0, abs(speeds[i]) / *(s.drift_speeds[i])) * (input[i] - filtered_output[i]); - } - } - - std::copy(input, input + 6, last_input); - std::copy(filtered_output, filtered_output + 6, output); + const tVector pos_speed = (position - last_pos_in) / dt; + const double pos_tau = 1. / *s.pos_responsiveness; + double alpha = dt / (dt + pos_tau); + last_pos_speed += (pos_speed - last_pos_speed) * alpha; + alpha *= min(1.0, VectorLength(last_pos_speed) / *s.pos_drift_speed); + last_pos_out += (position - last_pos_out) * alpha; + + const tQuat rot_delta = QuatDivide(rotation, last_rot_in); + const double ms_per_s = 1000.0; // angular speed quaternions need to be small to work so use °/ms + const tQuat rot_speed = Slerp(tQuat(), rot_delta, 1.0 / dt / ms_per_s); + const double rot_tau = 1. / *s.rot_responsiveness; + alpha = dt / (dt + rot_tau); + last_rot_speed = Slerp(last_rot_speed, rot_speed, alpha); + const double angular_speed = AngleBetween(tQuat(), last_rot_speed) * ms_per_s; + alpha *= min(1.0, angular_speed / *s.rot_drift_speed); + last_rot_out = Slerp(last_rot_out, rotation, alpha); + } + + last_pos_in = position; + last_rot_in = rotation; + std::copy(last_pos_out.v, last_pos_out.v + 3, output + TX); + QuatToYPR(last_rot_out, &output[Yaw]); } OPENTRACK_DECLARE_FILTER(filter_nm, dialog_nm, nmDll) diff --git a/filter-nm/ftnoir_filter_nm.h b/filter-nm/ftnoir_filter_nm.h index d2eae43d..7bf012a6 100644 --- a/filter-nm/ftnoir_filter_nm.h +++ b/filter-nm/ftnoir_filter_nm.h @@ -10,29 +10,24 @@ #include "api/plugin-api.hpp" #include "compat/timer.hpp" +#include "compat/hamilton-tools.h" #include "options/options.hpp" using namespace options; struct settings_nm : opts { - value responsiveness[6]; - value drift_speeds[6]; + value pos_responsiveness; + value rot_responsiveness; + value pos_drift_speed; + value rot_drift_speed; settings_nm() : opts("nm-filter"), - responsiveness{ value(b, "x-responsiveness", { 10.0, .0, 20.0 }), - value(b, "y-responsiveness", { 10.0, .0, 20.0 }), - value(b, "z-responsiveness", { 10.0, .0, 20.0 }), - value(b, "yaw-responsiveness", { 10.0, .0, 20.0 }), - value(b, "pitch-responsiveness", { 10.0, .0, 20.0 }), - value(b, "roll-responsiveness", { 10.0, .0, 20.0 }) }, - drift_speeds{ value(b, "x-drift-speed", { 50.0, 1.0, 200.0 }), - value(b, "y-drift-speed", { 50.0, 1.0, 200.0 }), - value(b, "z-drift-speed", { 50.0, 1.0, 200.0 }), - value(b, "yaw-drift-speed", { 100.0, 1.0, 400.0 }), - value(b, "pitch-drift-speed", { 100.0, 1.0, 400.0 }), - value(b, "roll-drift-speed", { 100.0, 1.0, 400.0 }) } + pos_responsiveness(value(b, "pos-responsiveness", { 15.0, .0, 20.0 })), + rot_responsiveness(value(b, "rot-responsiveness", { 18.0, .0, 20.0 })), + pos_drift_speed(value(b, "pos-drift-speed", { 30.0, 1.0, 200.0 })), + rot_drift_speed(value(b, "rot-drift-speed", { 45.0, 1.0, 400.0 })) { } }; @@ -45,9 +40,12 @@ struct filter_nm : IFilter module_status initialize() override { return status_ok(); } private: - double last_input[6]{}; - double speeds[6]{}; - double filtered_output[6]{}; + tVector last_pos_in; + tQuat last_rot_in; + tVector last_pos_out; + tQuat last_rot_out; + tVector last_pos_speed; + tQuat last_rot_speed; Timer t; settings_nm s; bool first_run = true; diff --git a/filter-nm/ftnoir_filter_nm_dialog.cpp b/filter-nm/ftnoir_filter_nm_dialog.cpp index ccf894db..f3626cae 100644 --- a/filter-nm/ftnoir_filter_nm_dialog.cpp +++ b/filter-nm/ftnoir_filter_nm_dialog.cpp @@ -12,52 +12,20 @@ dialog_nm::dialog_nm() { ui.setupUi(this); - tie_setting(s.responsiveness[0], ui.x_responsiveness_slider); - tie_setting(s.responsiveness[0], ui.x_responsiveness, [](double x) + tie_setting(s.pos_responsiveness, ui.pos_responsiveness_slider); + tie_setting(s.pos_responsiveness, ui.pos_responsiveness, [](double x) { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - tie_setting(s.responsiveness[1], ui.y_responsiveness_slider); - tie_setting(s.responsiveness[1], ui.y_responsiveness, [](double x) + tie_setting(s.rot_responsiveness, ui.rot_responsiveness_slider); + tie_setting(s.rot_responsiveness, ui.rot_responsiveness, [](double x) { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - tie_setting(s.responsiveness[2], ui.z_responsiveness_slider); - tie_setting(s.responsiveness[2], ui.z_responsiveness, [](double x) + tie_setting(s.pos_drift_speed, ui.pos_drift_speed_slider); + tie_setting(s.pos_drift_speed, ui.pos_drift_speed, [](double x) { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - tie_setting(s.responsiveness[3], ui.yaw_responsiveness_slider); - tie_setting(s.responsiveness[3], ui.yaw_responsiveness, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.responsiveness[4], ui.pitch_responsiveness_slider); - tie_setting(s.responsiveness[4], ui.pitch_responsiveness, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.responsiveness[5], ui.roll_responsiveness_slider); - tie_setting(s.responsiveness[5], ui.roll_responsiveness, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.drift_speeds[0], ui.x_drift_speed_slider); - tie_setting(s.drift_speeds[0], ui.x_drift_speed, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.drift_speeds[1], ui.y_drift_speed_slider); - tie_setting(s.drift_speeds[1], ui.y_drift_speed, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.drift_speeds[2], ui.z_drift_speed_slider); - tie_setting(s.drift_speeds[2], ui.z_drift_speed, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.drift_speeds[3], ui.yaw_drift_speed_slider); - tie_setting(s.drift_speeds[3], ui.yaw_drift_speed, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.drift_speeds[4], ui.pitch_drift_speed_slider); - tie_setting(s.drift_speeds[4], ui.pitch_drift_speed, [](double x) - { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); - - tie_setting(s.drift_speeds[5], ui.roll_drift_speed_slider); - tie_setting(s.drift_speeds[5], ui.roll_drift_speed, [](double x) + tie_setting(s.rot_drift_speed, ui.rot_drift_speed_slider); + tie_setting(s.rot_drift_speed, ui.rot_drift_speed, [](double x) { return QStringLiteral("%1").arg(x, 0, 'f', 2); }); } diff --git a/filter-nm/ftnoir_nm_filtercontrols.ui b/filter-nm/ftnoir_nm_filtercontrols.ui index 93f3cb91..ad307daf 100644 --- a/filter-nm/ftnoir_nm_filtercontrols.ui +++ b/filter-nm/ftnoir_nm_filtercontrols.ui @@ -20,15 +20,15 @@ Responsiveness - - + + - X + Rotation - + 0 @@ -49,31 +49,8 @@ - - - - - 0 - 0 - - - - 40 - - - Qt::Horizontal - - - - - - - Y - - - - + 30 @@ -89,7 +66,7 @@ - + 40 @@ -98,97 +75,14 @@ - - - - Z - - - - - - - - 30 - 0 - - - - 10.0 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - 40 - - - Qt::Horizontal - - - - - - - Yaw - - - - - - - - 30 - 0 - - - - 10.0 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - 40 - - - Qt::Horizontal - - - - - - - Pitch - - - - - - - - 30 - 0 - - - - 10.0 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + 0 + 0 + - - - - 40 @@ -197,36 +91,10 @@ - - - - Roll - - - - - - - - 30 - 0 - - + + - 10.0 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - 40 - - - Qt::Horizontal + Position @@ -261,85 +129,28 @@ Drift speeds - - - - Z - - - - - - - 1 - - - 200 - - - Qt::Horizontal - - - - - - - Roll - - - - - - - - 40 - 0 - - - - 50 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - °/s - - - - - + + mm/s - - + + - °/s + Position - - - - 1 - - - 200 - - - Qt::Horizontal + + + + + 0 + 0 + - - - - 40 @@ -354,54 +165,8 @@ - - - - - 40 - 0 - - - - 100 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Y - - - - - - - - 40 - 0 - - - - 100 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Pitch - - - - - + + 1 @@ -413,15 +178,15 @@ - - + + - X + Rotation - - + + 40 @@ -436,29 +201,15 @@ - - - - mm/s - - - - - - - mm/s - - - - - + + - Yaw + °/s - + 0 @@ -476,61 +227,6 @@ - - - - °/s - - - - - - - 1 - - - 400 - - - Qt::Horizontal - - - - - - - 1 - - - 400 - - - Qt::Horizontal - - - - - - - - 0 - 0 - - - - - 40 - 0 - - - - 50 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - @@ -547,7 +243,7 @@ - Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + Instructions: Set all sliders to minimum. Then for each of rotation and position: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop @@ -573,18 +269,10 @@ - x_responsiveness_slider - y_responsiveness_slider - z_responsiveness_slider - yaw_responsiveness_slider - pitch_responsiveness_slider - roll_responsiveness_slider - x_drift_speed_slider - y_drift_speed_slider - z_drift_speed_slider - yaw_drift_speed_slider - pitch_drift_speed_slider - roll_drift_speed_slider + pos_responsiveness_slider + rot_responsiveness_slider + pos_drift_speed_slider + rot_drift_speed_slider diff --git a/filter-nm/lang/nl_NL.ts b/filter-nm/lang/nl_NL.ts index d68712e9..540e2d51 100644 --- a/filter-nm/lang/nl_NL.ts +++ b/filter-nm/lang/nl_NL.ts @@ -7,30 +7,6 @@ Dialog - - X - - - - Y - - - - Z - - - - Yaw - - - - Pitch - - - - Roll - - °/s @@ -60,11 +36,19 @@ - Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + Natural movement filter by Tom Brazier: Cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. - Natural movement filter by Tom Brazier: Cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + Rotation + + + + Position + + + + Instructions: Set all sliders to minimum. Then for each of rotation and position: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. diff --git a/filter-nm/lang/ru_RU.ts b/filter-nm/lang/ru_RU.ts index 9ea3d158..31e5d5cc 100644 --- a/filter-nm/lang/ru_RU.ts +++ b/filter-nm/lang/ru_RU.ts @@ -7,30 +7,6 @@ Dialog - - X - - - - Y - - - - Z - - - - Yaw - - - - Pitch - - - - Roll - - °/s @@ -60,11 +36,19 @@ - Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + Natural movement filter by Tom Brazier: Cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. - Natural movement filter by Tom Brazier: Cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + Rotation + + + + Position + + + + Instructions: Set all sliders to minimum. Then for each of rotation and position: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. diff --git a/filter-nm/lang/stub.ts b/filter-nm/lang/stub.ts index 61c1f5bc..3b960804 100644 --- a/filter-nm/lang/stub.ts +++ b/filter-nm/lang/stub.ts @@ -7,30 +7,6 @@ Dialog - - X - - - - Y - - - - Z - - - - Yaw - - - - Pitch - - - - Roll - - °/s @@ -60,11 +36,19 @@ - Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + Natural movement filter by Tom Brazier: Cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. - Natural movement filter by Tom Brazier: Cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + Rotation + + + + Position + + + + Instructions: Set all sliders to minimum. Then for each of rotation and position: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. diff --git a/filter-nm/lang/zh_CN.ts b/filter-nm/lang/zh_CN.ts index d6490d99..92521e0f 100644 --- a/filter-nm/lang/zh_CN.ts +++ b/filter-nm/lang/zh_CN.ts @@ -7,30 +7,6 @@ Dialog - - X - - - - Y - - - - Z - - - - Yaw - - - - Pitch - - - - Roll - - °/s @@ -60,11 +36,19 @@ - Instructions: Set all sliders to minimum. Then on an axis by axis basis: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. + Natural movement filter by Tom Brazier: Cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. - Natural movement filter by Tom Brazier: Cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still. + Rotation + + + + Position + + + + Instructions: Set all sliders to minimum. Then for each of rotation and position: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still. -- cgit v1.2.3 From fa839e3fc9b92a4642d50c28bc607eb97e9ac1df Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Sat, 10 Jun 2023 16:59:18 +0100 Subject: Change to a quadratic curve for alpha and use a scale where 3 * drift speed results in alpha == 1.0 --- filter-nm/ftnoir_filter_nm.cpp | 10 ++++++---- filter-nm/ftnoir_filter_nm.h | 8 ++++---- filter-nm/ftnoir_nm_filtercontrols.ui | 4 ++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/filter-nm/ftnoir_filter_nm.cpp b/filter-nm/ftnoir_filter_nm.cpp index 5d274790..b222184b 100644 --- a/filter-nm/ftnoir_filter_nm.cpp +++ b/filter-nm/ftnoir_filter_nm.cpp @@ -42,17 +42,19 @@ void filter_nm::filter(const double* input, double* output) const double pos_tau = 1. / *s.pos_responsiveness; double alpha = dt / (dt + pos_tau); last_pos_speed += (pos_speed - last_pos_speed) * alpha; - alpha *= min(1.0, VectorLength(last_pos_speed) / *s.pos_drift_speed); + const double factor_pos = min(1.0, VectorLength(last_pos_speed) / (*s.pos_drift_speed * 3.0)); + alpha *= factor_pos * factor_pos; last_pos_out += (position - last_pos_out) * alpha; const tQuat rot_delta = QuatDivide(rotation, last_rot_in); - const double ms_per_s = 1000.0; // angular speed quaternions need to be small to work so use °/ms - const tQuat rot_speed = Slerp(tQuat(), rot_delta, 1.0 / dt / ms_per_s); + constexpr double ms_per_s = 1000.0; // angular speed quaternions need to be small to work so use °/ms + const tQuat rot_speed = Slerp(tQuat(), rot_delta, 1.0 / ms_per_s / dt ); const double rot_tau = 1. / *s.rot_responsiveness; alpha = dt / (dt + rot_tau); last_rot_speed = Slerp(last_rot_speed, rot_speed, alpha); const double angular_speed = AngleBetween(tQuat(), last_rot_speed) * ms_per_s; - alpha *= min(1.0, angular_speed / *s.rot_drift_speed); + const double factor_rot = min(1.0, angular_speed / (*s.rot_drift_speed * 3.0)); + alpha *= factor_rot * factor_rot; last_rot_out = Slerp(last_rot_out, rotation, alpha); } diff --git a/filter-nm/ftnoir_filter_nm.h b/filter-nm/ftnoir_filter_nm.h index 7bf012a6..84775207 100644 --- a/filter-nm/ftnoir_filter_nm.h +++ b/filter-nm/ftnoir_filter_nm.h @@ -24,10 +24,10 @@ struct settings_nm : opts settings_nm() : opts("nm-filter"), - pos_responsiveness(value(b, "pos-responsiveness", { 15.0, .0, 20.0 })), - rot_responsiveness(value(b, "rot-responsiveness", { 18.0, .0, 20.0 })), - pos_drift_speed(value(b, "pos-drift-speed", { 30.0, 1.0, 200.0 })), - rot_drift_speed(value(b, "rot-drift-speed", { 45.0, 1.0, 400.0 })) + pos_responsiveness(value(b, "pos-responsiveness", { 13.0, .0, 20.0 })), + rot_responsiveness(value(b, "rot-responsiveness", { 16.0, .0, 20.0 })), + pos_drift_speed(value(b, "pos-drift-speed", { 5.0, 0.1, 50.0 })), + rot_drift_speed(value(b, "rot-drift-speed", { 7.0, 0.1, 50.0 })) { } }; diff --git a/filter-nm/ftnoir_nm_filtercontrols.ui b/filter-nm/ftnoir_nm_filtercontrols.ui index ad307daf..7e317e74 100644 --- a/filter-nm/ftnoir_nm_filtercontrols.ui +++ b/filter-nm/ftnoir_nm_filtercontrols.ui @@ -171,7 +171,7 @@ 1 - 400 + 500 Qt::Horizontal @@ -220,7 +220,7 @@ 1 - 200 + 500 Qt::Horizontal -- cgit v1.2.3 From 8da9e2945e0da7a5954de4f38263aaec8ae84955 Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Mon, 12 Jun 2023 08:49:10 +0100 Subject: fix build --- compat/hamilton-tools.h | 1 + 1 file changed, 1 insertion(+) diff --git a/compat/hamilton-tools.h b/compat/hamilton-tools.h index d4604301..885e9f79 100644 --- a/compat/hamilton-tools.h +++ b/compat/hamilton-tools.h @@ -1,5 +1,6 @@ #pragma once +#include #include "export.hpp" #include "compat/math.hpp" -- cgit v1.2.3