From 17ce3e1e69de7bd3fe06008202ae9fa2f8ff272a Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Thu, 8 Dec 2016 06:14:38 +0100 Subject: tracker/tobii: flush changes, gain is broken --- tracker-tobii-eyex/CMakeLists.txt | 6 +- tracker-tobii-eyex/tobii-eyex-dialog.cpp | 25 ++++ tracker-tobii-eyex/tobii-eyex-dialog.ui | 210 +++++++++++++++---------------- tracker-tobii-eyex/tobii-eyex.cpp | 173 ++++++++++++------------- tracker-tobii-eyex/tobii-eyex.hpp | 22 +++- 5 files changed, 228 insertions(+), 208 deletions(-) diff --git a/tracker-tobii-eyex/CMakeLists.txt b/tracker-tobii-eyex/CMakeLists.txt index cfbe0160..20f4badd 100644 --- a/tracker-tobii-eyex/CMakeLists.txt +++ b/tracker-tobii-eyex/CMakeLists.txt @@ -1,7 +1,7 @@ if(WIN32) set(SDK_TOBII_EYEX "" CACHE PATH "") if(SDK_TOBII_EYEX) - opentrack_boilerplate(opentrack-tracker-tobii-eyex NO-INSTALL) + opentrack_boilerplate(opentrack-tracker-tobii-eyex) target_link_libraries(opentrack-tracker-tobii-eyex opentrack-spline-widget) set(tobii-libdir ${SDK_TOBII_EYEX}/lib/x86/) set(tobii-dll ${tobii-libdir}/Tobii.EyeX.Client.dll) @@ -13,9 +13,7 @@ if(WIN32) set(tobii-incdir ${SDK_TOBII_EYEX}/include/eyex) target_include_directories(opentrack-tracker-tobii-eyex SYSTEM PUBLIC ${tobii-incdir}) - if(FALSE) - install(FILES ${tobii-dll} DESTINATION ${opentrack-hier-pfx} ${opentrack-perms}) - endif() + install(FILES ${tobii-dll} DESTINATION ${opentrack-hier-pfx} ${opentrack-perms}) if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") file(TO_CMAKE_PATH "$ENV{SystemRoot}" sysroot) if (IS_DIRECTORY "${sysroot}/SysWOW64") diff --git a/tracker-tobii-eyex/tobii-eyex-dialog.cpp b/tracker-tobii-eyex/tobii-eyex-dialog.cpp index bb9ffcea..7f69fa16 100644 --- a/tracker-tobii-eyex/tobii-eyex-dialog.cpp +++ b/tracker-tobii-eyex/tobii-eyex-dialog.cpp @@ -11,6 +11,31 @@ tobii_eyex_dialog::tobii_eyex_dialog() ui.tracking_mode->addItem("Absolute", tobii_absolute); tie_setting(s.mode, ui.tracking_mode); + + ui.relative_mode_gain->setConfig(&rs.acc_mode_spline); + ui.relative_mode_gain->set_preview_only(true); + + tie_setting(rs.dz_len, ui.deadzone); + tie_setting(rs.expt_slope, ui.exponent); + tie_setting(rs.expt_len, ui.exponent_len); + tie_setting(rs.expt_norm, ui.exponent_norm); + + tie_setting(rs.log_slope, ui.log_base); + tie_setting(rs.log_len, ui.log_len); + tie_setting(rs.log_norm, ui.log_norm); + + connect(rs.b.get(), &bundle_::changed, this, [this]() { rs.make_spline(); }, Qt::QueuedConnection); + + // todo add specialization for label with traits +#if 0 + tie_setting(rs.dz_len, ui.deadzone_label); + tie_setting(rs.expt_slope, ui.exponent_label); + tie_setting(rs.expt_len, ui.exponent_len_label); + tie_setting(rs.expt_norm, ui.exponent_norm_label); + tie_setting(rs.log_slope, ui.log_base_label); + tie_setting(rs.log_len, ui.log_len_label); + tie_setting(rs.log_norm, ui.log_norm_label); +#endif } void tobii_eyex_dialog::do_ok() diff --git a/tracker-tobii-eyex/tobii-eyex-dialog.ui b/tracker-tobii-eyex/tobii-eyex-dialog.ui index 1a85f417..7a8c92aa 100644 --- a/tracker-tobii-eyex/tobii-eyex-dialog.ui +++ b/tracker-tobii-eyex/tobii-eyex-dialog.ui @@ -179,8 +179,8 @@ 3 - - + + 0 @@ -188,7 +188,7 @@ - Speed + Deadzone @@ -208,21 +208,8 @@ - - - - - 0 - 0 - - - - Deadzone - - - - - + + 24 @@ -256,21 +243,27 @@ - - + + - + 0 0 - - Exponent + + Qt::Horizontal + + + QSlider::TicksAbove + + + 25 - - + + 24 @@ -285,27 +278,34 @@ - - + + - + 0 0 - - Qt::Horizontal + + Speed - - QSlider::TicksAbove + + + + + + + 0 + 0 + - - 25 + + Log segment length - - + + 0 @@ -313,7 +313,7 @@ - Exponential length + Exponent @@ -333,8 +333,21 @@ - - + + + + + 0 + 0 + + + + Exponent segment length + + + + + 0 @@ -352,8 +365,8 @@ - - + + 0 @@ -361,12 +374,12 @@ - Linear coefficient + Log slope - - + + 24 @@ -381,8 +394,8 @@ - - + + 0 @@ -400,21 +413,27 @@ - - + + - + 0 0 - - Linear length + + Qt::Horizontal + + + QSlider::TicksAbove + + + 25 - + 24 @@ -429,56 +448,40 @@ - - + + - + 0 0 - - Qt::Horizontal - - - QSlider::TicksAbove - - - 25 + + Exponent norm - - + + - + 0 0 - - Logarithm base - - - - - - - - 24 - 0 - + + Qt::Horizontal - - 0 + + QSlider::TicksAbove - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + 25 - - + + 0 @@ -496,21 +499,24 @@ - - - - - 0 - 0 - + + + + + 24 + 0 + - Logarithm coefficient + 0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + 24 @@ -526,7 +532,7 @@ - + 0 @@ -544,22 +550,16 @@ - - + + - + 0 0 - - Qt::Horizontal - - - QSlider::TicksAbove - - - 25 + + Log norm diff --git a/tracker-tobii-eyex/tobii-eyex.cpp b/tracker-tobii-eyex/tobii-eyex.cpp index 74c31240..1a2f922b 100644 --- a/tracker-tobii-eyex/tobii-eyex.cpp +++ b/tracker-tobii-eyex/tobii-eyex.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include #include @@ -36,51 +38,80 @@ static inline tobii_eyex_tracker& to_self(TX_USERPARAM param) return *reinterpret_cast(param); } -template -static constexpr t clamp(t datum, t min, t max) +// there's an underflow in spline code, can't use 1e0 +static constexpr const double spline_max = 1e2; + +void rel_settings::make_spline_(part* functors, unsigned len) { - return ((datum > max) ? max : ((datum < min) ? min : datum)); + acc_mode_spline.removeAllPoints(); + + double lastx = 0, lasty = 0; + + using std::accumulate; + + const double inv_norm_y = 1./accumulate(functors, functors + len, 1e-4, [](double acc, const part& functor) { return acc + functor.norm; }); + const double inv_norm_x = 1./accumulate(functors, functors + len, 1e-4, [](double acc, const part& functor) { return acc + functor.len; }); + + for (unsigned k = 0; k < len; k++) + { + part& fun = functors[k]; + + const double xscale = fun.len * spline_max * inv_norm_x; + const double maxx = fun.f(1); + const double yscale = fun.norm * spline_max * inv_norm_y * (maxx < 1e-3 ? 0 : 1./maxx); + + for (unsigned i = 0; i <= fun.nparts; i++) + { + const double x = lastx + (fun.nparts == 0 ? 1 : i) / (1.+fun.nparts) * xscale; + const double y = lasty + clamp(fun.f(x) * yscale, 0, spline_max); + qDebug() << k << i << x << y; + acc_mode_spline.addPoint(x, y); + } + + lastx += xscale; + lasty += yscale; + } } -void rel_settings::draw_spline() +/* + def plot(f): + rng = arange(-1 + .01, 1, 1e-4) + plt.plot(rng, map(f, rng)) +*/ + +double rel_settings::gain(double value) { - spline& spline = acc_mode_spline; + return acc_mode_spline.get_value_no_save(value * spline_max) / spline_max; +} - spline.removeAllPoints(); +void rel_settings::make_spline() +{ + const double log_c = 1./std::log(log_slope()); - static constexpr float std_norm_expt = 1.f/3; - const float norm_expt = std_norm_expt * float(expt_norm->cur()); - static constexpr float std_norm_lin = 2.f/3; - const float norm_lin = clamp((1-norm_expt) * lin_norm->cur() * std_norm_lin, 0., 1.); + part functors[] + { + { 1, dz_len(), 0, [](double) { return 0; } }, + { 5, expt_len(), expt_norm(), [=](double x) { return std::pow(x, expt_slope()); } }, + { 7, 1 - dz_len() - expt_len() - log_len(), std::max(0., 1 - expt_norm() - log_norm()), [](double x) { return x; } }, + { 7, log_len(), log_norm(), [=](double x) { return std::log(1+x)*log_c; } }, + }; + make_spline_(functors, std::distance(std::begin(functors), std::end(functors))); } rel_settings::rel_settings() : opts("tobii-eyex-relative-mode"), - speed(b, "speed", s(5, .1, 10)), - dz_end_pt(b, "deadzone-length", s(4, 0, 15)), - expt_slope(b, "exponent-slope", s(1.5, 1.25, 3)), - expt_norm(b, "exponent-norm", s(1, .25, 4)), - lin_norm(b, "linear-norm", s(1, .25, 4)), + speed(b, "speed", s(3, .1, 10)), + dz_len(b, "deadzone-length", s(.04, 0, .2)), + expt_slope(b, "exponent-slope", s(1.75, 1.25, 3)), + expt_len(b, "exponent-length", s(.25, 0, .5)), + expt_norm(b, "exponent-norm", s(.3, .1, .5)), + log_slope(b, "log-slope", s(2.75, 1.25, 10)), + log_len(b, "log-len", s(.1, 0, .2)), + log_norm(b, "log-norm", s(.1, .05, .3)), acc_mode_spline(100, 100, "") { - QObject::connect(&dz_end_pt, - static_cast(&base_value::valueChanged), - this, - &rel_settings::draw_spline); - QObject::connect(&expt_slope, - static_cast(&base_value::valueChanged), - this, - &rel_settings::draw_spline); - QObject::connect(&expt_norm, - static_cast(&base_value::valueChanged), - this, - &rel_settings::draw_spline); - QObject::connect(&lin_norm, - static_cast(&base_value::valueChanged), - this, - &rel_settings::draw_spline); - draw_spline(); + make_spline(); } tobii_eyex_tracker::tobii_eyex_tracker() : @@ -287,67 +318,16 @@ void tobii_eyex_tracker::start_tracker(QFrame*) dbg_verbose("api initialized"); } -// the gain function was prototyped in python with jupyter qtconsole. -// you can use qtconsole's inline matplotlib support to see the gain function. -// the `piecewise' function assumes monotonic growth or constant value for all functions. -/* - -from math import * -from itertools import izip -import matplotlib -import matplotlib.pyplot as plt - -try: - import IPython - IPython.get_ipython().magic(u'matplotlib inline') -except: - pass - -def frange(from_, to_, step_=1e-4): - i = from_ - while True: - yield i - i += step_ - if i >= to_: - break - -def plot_fn(fn, from_=0., to_=1., step=None): - if step is None: - step = max(1e-4, (to_-from_)*1e-4) - xs = [i for i in frange(from_, to_, step)] - plt.plot(xs, map(fn, xs)) - -def piecewise(x, funs, bounds): - y = 0. - last_bound = 0. - norm = 0. - for fun in funs: - norm += fun(1.) - for fun, bound in izip(funs, bounds): - if x > bound: - y += fun(1.) - else: - b = bound - last_bound - x_ = (x - last_bound) / b - y += fun(x_) - break - last_bound = bound - return y / norm - -def f(x): return x**1.75 -def g(x): return 1.75*1.75*x -def h(x): return log(1+x)/log(2.5) -def zero(x): return 0. - -plot_fn(lambda x: piecewise(x, [zero, f, g, h], [.05, .25, .7, 1.])) - -*/ - tobii_eyex_tracker::num tobii_eyex_tracker::gain(num x_) { return 1; } +static inline double signum(double x) +{ + return !(x < 0) - (x < 0); +} + void tobii_eyex_tracker::data(double* data) { TX_REAL px, py, dw, dh, x_, y_; @@ -378,20 +358,21 @@ void tobii_eyex_tracker::data(double* data) { const double dt = t.elapsed_seconds(); t.start(); - // XXX TODO make slider - static constexpr double v = 300; - const double x = gain(x_); - const double y = gain(y_); + using std::fabs; + + static constexpr double max_yaw = 45, max_pitch = 30; + static constexpr double c_yaw = 3; + static constexpr double c_pitch = c_yaw * max_pitch / max_yaw; - const double yaw_delta = (x * v) * dt; - const double pitch_delta = (y * -v) * dt; + const double yaw_delta = gain(fabs(x_)) * signum(x_) * c_yaw * dt; + const double pitch_delta = gain(fabs(y_)) * signum(y_) * c_pitch * dt; yaw += yaw_delta; pitch += pitch_delta; - yaw = clamp(yaw, -180., 180.); - pitch = clamp(pitch, -60., 60.); + yaw = clamp(yaw, -max_yaw, max_yaw); + pitch = clamp(pitch, -max_pitch, max_pitch); } if (do_center) diff --git a/tracker-tobii-eyex/tobii-eyex.hpp b/tracker-tobii-eyex/tobii-eyex.hpp index aeac4d89..68acb25c 100644 --- a/tracker-tobii-eyex/tobii-eyex.hpp +++ b/tracker-tobii-eyex/tobii-eyex.hpp @@ -18,9 +18,11 @@ using namespace options; #include "spline-widget/spline.hpp" #include "spline-widget/spline-widget.hpp" +#include #include #include #include +#include enum tobii_mode { @@ -31,13 +33,27 @@ enum tobii_mode class rel_settings final : public QObject, public opts { Q_OBJECT + + using functor = std::function; + + struct part + { + int nparts; + double len, norm; + functor f; + }; + + void make_spline_(part* functors, unsigned len); + public: using s = slider_value; - value speed, dz_end_pt, expt_slope, expt_norm, lin_norm; + value speed, dz_len, expt_slope, expt_len, expt_norm, log_slope, log_len, log_norm; spline acc_mode_spline; rel_settings(); -private slots: - void draw_spline(); + double gain(double value); + +public slots: + void make_spline(); }; struct settings final : public opts -- cgit v1.2.3