diff options
| author | Stanislaw Halik <sthalik@misaki.pl> | 2016-12-08 06:14:38 +0100 | 
|---|---|---|
| committer | Stanislaw Halik <sthalik@misaki.pl> | 2016-12-08 06:14:38 +0100 | 
| commit | 17ce3e1e69de7bd3fe06008202ae9fa2f8ff272a (patch) | |
| tree | 5fcff66e72954bda7bd0d35625a730226416ad30 | |
| parent | 8b7357b77fe2b3eddc59cc159da1ed26f92a1d2b (diff) | |
tracker/tobii: flush changes, gain is broken
| -rw-r--r-- | tracker-tobii-eyex/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | tracker-tobii-eyex/tobii-eyex-dialog.cpp | 25 | ||||
| -rw-r--r-- | tracker-tobii-eyex/tobii-eyex-dialog.ui | 210 | ||||
| -rw-r--r-- | tracker-tobii-eyex/tobii-eyex.cpp | 173 | ||||
| -rw-r--r-- | 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 @@              <property name="verticalSpacing">               <number>3</number>              </property> -            <item row="0" column="0"> -             <widget class="QLabel" name="label_11"> +            <item row="1" column="0"> +             <widget class="QLabel" name="label_4">                <property name="sizePolicy">                 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">                  <horstretch>0</horstretch> @@ -188,7 +188,7 @@                 </sizepolicy>                </property>                <property name="text"> -               <string>Speed</string> +               <string>Deadzone</string>                </property>               </widget>              </item> @@ -208,21 +208,8 @@                </property>               </widget>              </item> -            <item row="1" column="0"> -             <widget class="QLabel" name="label_4"> -              <property name="sizePolicy"> -               <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> -                <horstretch>0</horstretch> -                <verstretch>0</verstretch> -               </sizepolicy> -              </property> -              <property name="text"> -               <string>Deadzone</string> -              </property> -             </widget> -            </item> -            <item row="1" column="1"> -             <widget class="QLabel" name="deadzone_label"> +            <item row="2" column="1"> +             <widget class="QLabel" name="exponent_label">                <property name="minimumSize">                 <size>                  <width>24</width> @@ -256,21 +243,27 @@                </property>               </widget>              </item> -            <item row="2" column="0"> -             <widget class="QLabel" name="label_10"> +            <item row="2" column="2"> +             <widget class="QSlider" name="exponent">                <property name="sizePolicy"> -               <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> +               <sizepolicy hsizetype="Expanding" vsizetype="Maximum">                  <horstretch>0</horstretch>                  <verstretch>0</verstretch>                 </sizepolicy>                </property> -              <property name="text"> -               <string>Exponent</string> +              <property name="orientation"> +               <enum>Qt::Horizontal</enum> +              </property> +              <property name="tickPosition"> +               <enum>QSlider::TicksAbove</enum> +              </property> +              <property name="tickInterval"> +               <number>25</number>                </property>               </widget>              </item> -            <item row="2" column="1"> -             <widget class="QLabel" name="exponent_label"> +            <item row="1" column="1"> +             <widget class="QLabel" name="deadzone_label">                <property name="minimumSize">                 <size>                  <width>24</width> @@ -285,27 +278,34 @@                </property>               </widget>              </item> -            <item row="2" column="2"> -             <widget class="QSlider" name="exponent"> +            <item row="0" column="0"> +             <widget class="QLabel" name="label_11">                <property name="sizePolicy"> -               <sizepolicy hsizetype="Expanding" vsizetype="Maximum"> +               <sizepolicy hsizetype="Maximum" vsizetype="Preferred">                  <horstretch>0</horstretch>                  <verstretch>0</verstretch>                 </sizepolicy>                </property> -              <property name="orientation"> -               <enum>Qt::Horizontal</enum> +              <property name="text"> +               <string>Speed</string>                </property> -              <property name="tickPosition"> -               <enum>QSlider::TicksAbove</enum> +             </widget> +            </item> +            <item row="5" column="0"> +             <widget class="QLabel" name="label_8"> +              <property name="sizePolicy"> +               <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> +                <horstretch>0</horstretch> +                <verstretch>0</verstretch> +               </sizepolicy>                </property> -              <property name="tickInterval"> -               <number>25</number> +              <property name="text"> +               <string>Log segment length</string>                </property>               </widget>              </item> -            <item row="3" column="0"> -             <widget class="QLabel" name="label_5"> +            <item row="2" column="0"> +             <widget class="QLabel" name="label_10">                <property name="sizePolicy">                 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">                  <horstretch>0</horstretch> @@ -313,7 +313,7 @@                 </sizepolicy>                </property>                <property name="text"> -               <string>Exponential length</string> +               <string>Exponent</string>                </property>               </widget>              </item> @@ -333,8 +333,21 @@                </property>               </widget>              </item> -            <item row="3" column="2"> -             <widget class="QSlider" name="exponent_len"> +            <item row="3" column="0"> +             <widget class="QLabel" name="label_5"> +              <property name="sizePolicy"> +               <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> +                <horstretch>0</horstretch> +                <verstretch>0</verstretch> +               </sizepolicy> +              </property> +              <property name="text"> +               <string>Exponent segment length</string> +              </property> +             </widget> +            </item> +            <item row="5" column="2"> +             <widget class="QSlider" name="log_len">                <property name="sizePolicy">                 <sizepolicy hsizetype="Expanding" vsizetype="Maximum">                  <horstretch>0</horstretch> @@ -352,8 +365,8 @@                </property>               </widget>              </item> -            <item row="4" column="0"> -             <widget class="QLabel" name="label_7"> +            <item row="6" column="0"> +             <widget class="QLabel" name="label_9">                <property name="sizePolicy">                 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">                  <horstretch>0</horstretch> @@ -361,12 +374,12 @@                 </sizepolicy>                </property>                <property name="text"> -               <string>Linear coefficient</string> +               <string>Log slope</string>                </property>               </widget>              </item> -            <item row="4" column="1"> -             <widget class="QLabel" name="linear_c_label"> +            <item row="6" column="1"> +             <widget class="QLabel" name="log_base_label">                <property name="minimumSize">                 <size>                  <width>24</width> @@ -381,8 +394,8 @@                </property>               </widget>              </item> -            <item row="4" column="2"> -             <widget class="QSlider" name="linear_c"> +            <item row="6" column="2"> +             <widget class="QSlider" name="log_base">                <property name="sizePolicy">                 <sizepolicy hsizetype="Expanding" vsizetype="Maximum">                  <horstretch>0</horstretch> @@ -400,21 +413,27 @@                </property>               </widget>              </item> -            <item row="5" column="0"> -             <widget class="QLabel" name="label_6"> +            <item row="0" column="2"> +             <widget class="QSlider" name="speed">                <property name="sizePolicy"> -               <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> +               <sizepolicy hsizetype="Expanding" vsizetype="Maximum">                  <horstretch>0</horstretch>                  <verstretch>0</verstretch>                 </sizepolicy>                </property> -              <property name="text"> -               <string>Linear length</string> +              <property name="orientation"> +               <enum>Qt::Horizontal</enum> +              </property> +              <property name="tickPosition"> +               <enum>QSlider::TicksAbove</enum> +              </property> +              <property name="tickInterval"> +               <number>25</number>                </property>               </widget>              </item>              <item row="5" column="1"> -             <widget class="QLabel" name="linear_len_label"> +             <widget class="QLabel" name="log_len_label">                <property name="minimumSize">                 <size>                  <width>24</width> @@ -429,56 +448,40 @@                </property>               </widget>              </item> -            <item row="5" column="2"> -             <widget class="QSlider" name="linear_len"> +            <item row="4" column="0"> +             <widget class="QLabel" name="label_6">                <property name="sizePolicy"> -               <sizepolicy hsizetype="Expanding" vsizetype="Maximum"> +               <sizepolicy hsizetype="Maximum" vsizetype="Preferred">                  <horstretch>0</horstretch>                  <verstretch>0</verstretch>                 </sizepolicy>                </property> -              <property name="orientation"> -               <enum>Qt::Horizontal</enum> -              </property> -              <property name="tickPosition"> -               <enum>QSlider::TicksAbove</enum> -              </property> -              <property name="tickInterval"> -               <number>25</number> +              <property name="text"> +               <string>Exponent norm</string>                </property>               </widget>              </item> -            <item row="6" column="0"> -             <widget class="QLabel" name="label_8"> +            <item row="4" column="2"> +             <widget class="QSlider" name="exponent_norm">                <property name="sizePolicy"> -               <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> +               <sizepolicy hsizetype="Expanding" vsizetype="Maximum">                  <horstretch>0</horstretch>                  <verstretch>0</verstretch>                 </sizepolicy>                </property> -              <property name="text"> -               <string>Logarithm base</string> -              </property> -             </widget> -            </item> -            <item row="6" column="1"> -             <widget class="QLabel" name="log_base_label"> -              <property name="minimumSize"> -               <size> -                <width>24</width> -                <height>0</height> -               </size> +              <property name="orientation"> +               <enum>Qt::Horizontal</enum>                </property> -              <property name="text"> -               <string>0</string> +              <property name="tickPosition"> +               <enum>QSlider::TicksAbove</enum>                </property> -              <property name="alignment"> -               <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> +              <property name="tickInterval"> +               <number>25</number>                </property>               </widget>              </item> -            <item row="6" column="2"> -             <widget class="QSlider" name="log_base"> +            <item row="3" column="2"> +             <widget class="QSlider" name="exponent_len">                <property name="sizePolicy">                 <sizepolicy hsizetype="Expanding" vsizetype="Maximum">                  <horstretch>0</horstretch> @@ -496,21 +499,24 @@                </property>               </widget>              </item> -            <item row="7" column="0"> -             <widget class="QLabel" name="label_9"> -              <property name="sizePolicy"> -               <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> -                <horstretch>0</horstretch> -                <verstretch>0</verstretch> -               </sizepolicy> +            <item row="4" column="1"> +             <widget class="QLabel" name="exponent_norm_label"> +              <property name="minimumSize"> +               <size> +                <width>24</width> +                <height>0</height> +               </size>                </property>                <property name="text"> -               <string>Logarithm coefficient</string> +               <string>0</string> +              </property> +              <property name="alignment"> +               <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>                </property>               </widget>              </item>              <item row="7" column="1"> -             <widget class="QLabel" name="log_c_label"> +             <widget class="QLabel" name="log_norm_label">                <property name="minimumSize">                 <size>                  <width>24</width> @@ -526,7 +532,7 @@               </widget>              </item>              <item row="7" column="2"> -             <widget class="QSlider" name="log_c"> +             <widget class="QSlider" name="log_norm">                <property name="sizePolicy">                 <sizepolicy hsizetype="Expanding" vsizetype="Maximum">                  <horstretch>0</horstretch> @@ -544,22 +550,16 @@                </property>               </widget>              </item> -            <item row="0" column="2"> -             <widget class="QSlider" name="speed"> +            <item row="7" column="0"> +             <widget class="QLabel" name="label_12">                <property name="sizePolicy"> -               <sizepolicy hsizetype="Expanding" vsizetype="Maximum"> +               <sizepolicy hsizetype="Maximum" vsizetype="Preferred">                  <horstretch>0</horstretch>                  <verstretch>0</verstretch>                 </sizepolicy>                </property> -              <property name="orientation"> -               <enum>Qt::Horizontal</enum> -              </property> -              <property name="tickPosition"> -               <enum>QSlider::TicksAbove</enum> -              </property> -              <property name="tickInterval"> -               <number>25</number> +              <property name="text"> +               <string>Log norm</string>                </property>               </widget>              </item> 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 <vector>  #include <algorithm>  #include <iterator> +#include <utility> +#include <numeric>  #include <QDebug>  #include <QMutexLocker>  #include <QMessageBox> @@ -36,51 +38,80 @@ static inline tobii_eyex_tracker& to_self(TX_USERPARAM param)      return *reinterpret_cast<tobii_eyex_tracker*>(param);  } -template<typename t> -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<void(base_value::*)(const slider_value&) const>(&base_value::valueChanged), -                     this, -                     &rel_settings::draw_spline); -    QObject::connect(&expt_slope, -                     static_cast<void(base_value::*)(const slider_value&) const>(&base_value::valueChanged), -                     this, -                     &rel_settings::draw_spline); -    QObject::connect(&expt_norm, -                     static_cast<void(base_value::*)(const slider_value&) const>(&base_value::valueChanged), -                     this, -                     &rel_settings::draw_spline); -    QObject::connect(&lin_norm, -                     static_cast<void(base_value::*)(const slider_value&) const>(&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 <functional>  #include <atomic>  #include <QObject>  #include <QMutex> +#include <QTimer>  enum tobii_mode  { @@ -31,13 +33,27 @@ enum tobii_mode  class rel_settings final : public QObject, public opts  {      Q_OBJECT + +    using functor = std::function<double(double)>; + +    struct part +    { +        int nparts; +        double len, norm; +        functor f; +    }; + +    void make_spline_(part* functors, unsigned len); +  public:      using s = slider_value; -    value<slider_value> speed, dz_end_pt, expt_slope, expt_norm, lin_norm; +    value<slider_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 | 
