diff options
| author | Stanislaw Halik <sthalik@misaki.pl> | 2017-10-20 17:53:21 +0200 | 
|---|---|---|
| committer | Stanislaw Halik <sthalik@misaki.pl> | 2017-10-20 17:53:21 +0200 | 
| commit | 39e209983bd1f04fb0beefef754d7430c8b7fb9f (patch) | |
| tree | ec41545dda2d33d316adc6466f21138a280db6a8 | |
| parent | 092e2910ae8f6c2e188e930b9540d58e145c9142 (diff) | |
logic, spline: more spline work/fixes
- mapping window clamps are now value<max_clamp> in
  spline
- clamp won't mess up saved spline content
- clean up artifacts on spline widget
| -rw-r--r-- | gui/mapping-window.cpp | 43 | ||||
| -rw-r--r-- | logic/main-settings.cpp | 39 | ||||
| -rw-r--r-- | logic/main-settings.hpp | 45 | ||||
| -rw-r--r-- | logic/mappings.cpp | 27 | ||||
| -rw-r--r-- | logic/mappings.hpp | 4 | ||||
| -rw-r--r-- | options/base-value.hpp | 1 | ||||
| -rw-r--r-- | spline/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | spline/axis-opts.cpp | 47 | ||||
| -rw-r--r-- | spline/axis-opts.hpp | 53 | ||||
| -rw-r--r-- | spline/spline-widget.cpp | 33 | ||||
| -rw-r--r-- | spline/spline.cpp | 183 | ||||
| -rw-r--r-- | spline/spline.hpp | 33 | 
12 files changed, 268 insertions, 244 deletions
| diff --git a/gui/mapping-window.cpp b/gui/mapping-window.cpp index 0726186a..629bcd5b 100644 --- a/gui/mapping-window.cpp +++ b/gui/mapping-window.cpp @@ -56,14 +56,14 @@ MapWidget::MapWidget(Mappings& m) : m(m), widgets{}      tie_setting(s.a_y.altp, ui.ty_altp);      tie_setting(s.a_z.altp, ui.tz_altp); -    tie_setting(s.a_yaw.clamp_x, ui.max_yaw_rotation); -    tie_setting(s.a_pitch.clamp_x, ui.max_pitch_rotation); -    tie_setting(s.a_roll.clamp_x, ui.max_roll_rotation); -    tie_setting(s.a_x.clamp_x, ui.max_x_translation); -    tie_setting(s.a_y.clamp_x, ui.max_y_translation); -    tie_setting(s.a_z.clamp_x, ui.max_z_translation); - -    tie_setting(s.a_pitch.clamp_y, ui.max_pitch_output); +    tie_setting(s.a_yaw.clamp_x_, ui.max_yaw_rotation); +    tie_setting(s.a_pitch.clamp_x_, ui.max_pitch_rotation); +    tie_setting(s.a_roll.clamp_x_, ui.max_roll_rotation); +    tie_setting(s.a_x.clamp_x_, ui.max_x_translation); +    tie_setting(s.a_y.clamp_x_, ui.max_y_translation); +    tie_setting(s.a_z.clamp_x_, ui.max_z_translation); + +    tie_setting(s.a_pitch.clamp_y_, ui.max_pitch_output);  }  void MapWidget::load() @@ -123,10 +123,9 @@ void MapWidget::load()              qfc.force_redraw();          } -        connect(&axis.opts.clamp_x, base_value::signal_fun<int>(), +        connect(&axis.opts.clamp_x_, base_value::signal_fun<int>(),                  &qfc, [i, &conf, &qfc](int value) { -            conf.set_max_input(value); -            qfc.reload_spline(); +            //qfc.reload_spline();              qfc.set_x_step(value + 1e-2 >= 90 ? 10 : 5);              if (i >= 3) @@ -140,30 +139,10 @@ void MapWidget::load()          // force signal to avoid duplicating the slot's logic          qfc.setConfig(&conf); -        axis.opts.clamp_x.valueChanged(axis.opts.clamp_x); +        axis.opts.clamp_x_.valueChanged(axis.opts.clamp_x_);          widgets[i % 6][altp ? 1 : 0] = &qfc;      } - -    { -        value<axis_opts::max_clamp>& val = s.a_pitch.clamp_y; - -        Map& axis = m(Pitch); - -        connect(&val, base_value::signal_fun<int>(), this, [&](int x) { -            x = std::abs(x); - -            spline* splines[] { &axis.spline_main, &axis.spline_alt }; - -            for (spline* spl : splines) -                spl->set_max_output(x); - -            ui.ryconfig->setConfig(&axis.spline_main); -            ui.ryconfig_alt->setConfig(&axis.spline_alt); -        }); - -        axis.opts.clamp_y.valueChanged(axis.opts.clamp_y); -    }  }  void MapWidget::closeEvent(QCloseEvent*) diff --git a/logic/main-settings.cpp b/logic/main-settings.cpp index b1b9a132..e2d1b41f 100644 --- a/logic/main-settings.cpp +++ b/logic/main-settings.cpp @@ -3,12 +3,12 @@  main_settings::main_settings() :      b(make_bundle("opentrack-ui")),      b_map(make_bundle("opentrack-mappings")), -    a_x(b, b_map, "x", TX), -    a_y(b, b_map, "y", TY), -    a_z(b, b_map, "z", TZ), -    a_yaw(b, b_map, "yaw", Yaw), -    a_pitch(b, b_map, "pitch", Pitch), -    a_roll(b, b_map, "roll", Roll), +    a_x("x", TX), +    a_y("y", TY), +    a_z("z", TZ), +    a_yaw("yaw", Yaw), +    a_pitch("pitch", Pitch), +    a_roll("roll", Roll),      all_axis_opts { &a_x, &a_y, &a_z, &a_yaw, &a_pitch, &a_roll },      tcomp_p(b, "compensate-translation", false),      tcomp_disable_tx(b, "compensate-translation-disable-x-axis", false), @@ -59,30 +59,3 @@ key_opts::key_opts(bundle b, const QString& name) :      guid(b, QString("guid-%1").arg(name), ""),      button(b, QString("button-%1").arg(name), -1)  {} - -using max_clamp = axis_opts::max_clamp; - -static max_clamp get_max_x(Axis k) -{ -    if (k == Pitch) -        return max_clamp::r90; -    if (k >= Yaw) -        return max_clamp::r180; -    return max_clamp::t30; -} - -axis_opts::axis_opts(bundle b_settings_window, bundle b_mapping_window, QString pfx, Axis idx) : -    b_settings_window(b_settings_window), -    b_mapping_window(b_mapping_window), -    zero(b_settings_window, n(pfx, "zero-pos"), 0), -    src(b_settings_window, n(pfx, "source-index"), idx), -    invert(b_settings_window, n(pfx, "invert-sign"), false), -    altp(b_mapping_window, n(pfx, "alt-axis-sign"), false), -    clamp_x(b_mapping_window, n(pfx, "max-value"), get_max_x(idx)), -    clamp_y(b_mapping_window, n(pfx, "max-output-value"), idx >= Yaw ? o_r90 : o_t75) -{} - -QString axis_opts::n(QString pfx, QString name) -{ -    return QString("%1-%2").arg(pfx, name); -} diff --git a/logic/main-settings.hpp b/logic/main-settings.hpp index 4b29157f..29f401ab 100644 --- a/logic/main-settings.hpp +++ b/logic/main-settings.hpp @@ -10,53 +10,12 @@  #include <QString>  #include "options/options.hpp" -#include "api/plugin-api.hpp" -  using namespace options; +#include "api/plugin-api.hpp" +#include "spline/axis-opts.hpp"  #include "export.hpp" -namespace axis_clamp_opts -{ - -} // ns axis-clamp-opts - -struct OTR_LOGIC_EXPORT axis_opts final -{ -    enum max_clamp -    { -        r180 = 180, -        r90 = 90, -        r60 = 60, -        r45 = 45, -        r30 = 30, -        r25 = 25, -        r20 = 20, -        r15 = 15, -        r10 = 10, - -        t100 = 100, -        t30 = 30, -        t20 = 20, -        t15 = 15, -        t10 = 10, - -        o_r180 = -180, -        o_r90 = -90, -        o_t75 = -75, -    }; - -    // note, these two bundles can be the same value with no issues -    bundle b_settings_window, b_mapping_window; -    value<double> zero; -    value<int> src; -    value<bool> invert, altp; -    value<max_clamp> clamp_x, clamp_y; -    axis_opts(bundle b_settings_window, bundle b_mapping_window, QString pfx, Axis idx); -private: -    static inline QString n(QString pfx, QString name); -}; -  struct OTR_LOGIC_EXPORT key_opts  {      value<QString> keycode, guid; diff --git a/logic/mappings.cpp b/logic/mappings.cpp index 9e81bb01..8144f9b4 100644 --- a/logic/mappings.cpp +++ b/logic/mappings.cpp @@ -2,18 +2,13 @@  #include <utility> -Map::Map(QString primary, QString secondary, int max_x, int max_y, axis_opts& opts) : +Map::Map(const QString& spline_name, const QString& alt_spline_name, axis_opts& opts) :      opts(opts), -    name1(primary), -    name2(secondary), -    spline_main(max_x, max_y, primary), -    spline_alt(max_x, max_y, secondary) +    name(spline_name), +    alt_name(alt_spline_name), +    spline_main(spline_name, opts.prefix(), opts.axis()), +    spline_alt(alt_spline_name, opts.prefix(), opts.axis())  { -    spline_main.set_max_input(max_x); -    spline_alt.set_max_input(max_x); - -    spline_main.set_max_output(max_y); -    spline_alt.set_max_output(max_y);  }  void Map::save() @@ -30,11 +25,11 @@ void Map::load()  Mappings::Mappings(std::vector<axis_opts*> opts) :      axes { -        Map("spline-X", "alt-spline-X", 100, 75, *opts[TX]), -        Map("spline-Y", "alt-spline-Y", 100, 75, *opts[TY]), -        Map("spline-Z", "alt-spline-Z", 100, 75, *opts[TZ]), -        Map("spline-yaw", "alt-spline-yaw", 180, 180, *opts[Yaw]), -        Map("spline-pitch", "alt-spline-pitch", 180, std::abs((int)opts[Pitch]->clamp_y), *opts[Pitch]), -        Map("spline-roll", "alt-spline-roll", 180, 180, *opts[Roll]) +        Map("spline-X", "alt-spline-X", *opts[TX]), +        Map("spline-Y", "alt-spline-Y", *opts[TY]), +        Map("spline-Z", "alt-spline-Z", *opts[TZ]), +        Map("spline-yaw", "alt-spline-yaw", *opts[Yaw]), +        Map("spline-pitch", "alt-spline-pitch", *opts[Pitch]), +        Map("spline-roll", "alt-spline-roll", *opts[Roll])      }  {} diff --git a/logic/mappings.hpp b/logic/mappings.hpp index b3587749..4b71e9c5 100644 --- a/logic/mappings.hpp +++ b/logic/mappings.hpp @@ -15,13 +15,13 @@ using namespace options;  struct OTR_LOGIC_EXPORT Map final  { -    Map(QString primary, QString secondary, int max_x, int max_y, axis_opts& opts); +    Map(const QString& spline_name, const QString& alt_spline_name, axis_opts& opts);      void save();      void load();      axis_opts& opts; -    QString name1, name2; +    QString name, alt_name;      spline spline_main, spline_alt;  }; diff --git a/options/base-value.hpp b/options/base-value.hpp index dfb22670..7bf83619 100644 --- a/options/base-value.hpp +++ b/options/base-value.hpp @@ -29,6 +29,7 @@ class OTR_OPTIONS_EXPORT base_value : public QObject      template<typename t>      using signal_sig = void(base_value::*)(cv_qualified<t>) const;  public: +    bundle get_bundle() { return b; }      QString name() const { return self_name; }      base_value(bundle b, const QString& name, comparator cmp, std::type_index type_idx);      ~base_value() override; diff --git a/spline/CMakeLists.txt b/spline/CMakeLists.txt index d252004b..7d427601 100644 --- a/spline/CMakeLists.txt +++ b/spline/CMakeLists.txt @@ -1,2 +1,2 @@ -otr_module(spline NO-COMPAT BIN) -target_link_libraries(opentrack-spline opentrack-options opentrack-compat) +otr_module(spline BIN) +target_link_libraries(opentrack-spline) diff --git a/spline/axis-opts.cpp b/spline/axis-opts.cpp new file mode 100644 index 00000000..52fe20f5 --- /dev/null +++ b/spline/axis-opts.cpp @@ -0,0 +1,47 @@ +#include "axis-opts.hpp" + +using max_clamp = axis_opts::max_clamp; + +static max_clamp get_max_x(Axis k) +{ +    if (k == Axis(-1)) +        return max_clamp::x1000; +    if (k == Pitch) +        return max_clamp::r90; +    if (k >= Yaw) +        return max_clamp::r180; +    return max_clamp::t30; +} + +static max_clamp get_max_y(Axis k) +{ +    if (k == Axis(-1)) +        return max_clamp::x1000; +    if (k == Axis::Pitch) +        return max_clamp::o_r90; +    if (k >= Axis::Yaw) +        return max_clamp::o_r180; +    return max_clamp::o_t75; +} + +axis_opts::axis_opts(QString pfx, Axis idx) : +    b_settings_window(make_bundle("opentrack-ui")), +    b_mapping_window(make_bundle("opentrack-mappings")), +    zero(b_settings_window, n(pfx, "zero-pos"), 0), +    src(b_settings_window, n(pfx, "source-index"), idx), +    invert(b_settings_window, n(pfx, "invert-sign"), false), +    altp(b_mapping_window, n(pfx, "alt-axis-sign"), false), +    clamp_x_(b_mapping_window, n(pfx, "max-value"), get_max_x(idx)), +    clamp_y_(b_mapping_window, n(pfx, "max-output-value"), get_max_y(idx)), +    prefix_(pfx), +    axis_(idx) +{} + +QString const& axis_opts::prefix() const { return prefix_; } + +Axis axis_opts::axis() const { return axis_; } + +QString axis_opts::n(QString pfx, QString name) +{ +    return QString("%1-%2").arg(pfx, name); +} diff --git a/spline/axis-opts.hpp b/spline/axis-opts.hpp new file mode 100644 index 00000000..ad94236c --- /dev/null +++ b/spline/axis-opts.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include "options/options.hpp" +using namespace options; +#include "api/plugin-api.hpp" + +#include "export.hpp" + +struct OTR_SPLINE_EXPORT axis_opts final +{ +    enum max_clamp +    { +        r180 = 180, +        r90 = 90, +        r60 = 60, +        r45 = 45, +        r30 = 30, +        r25 = 25, +        r20 = 20, +        r15 = 15, +        r10 = 10, + +        t100 = 100, +        t30 = 30, +        t20 = 20, +        t15 = 15, +        t10 = 10, + +        o_r180 = -180, +        o_r90 = -90, +        o_t75 = -75, + +        x1000 = 1000, +    }; + +    // note, these two bundles can be the same value with no issues +    bundle b_settings_window, b_mapping_window; +    value<double> zero; +    value<int> src; +    value<bool> invert, altp; +    value<max_clamp> clamp_x_, clamp_y_; +    double max_clamp_x() const { return std::fabs(clamp_x_.to<double>()); } +    double max_clamp_y() const { return std::fabs(clamp_y_.to<double>()); } +    axis_opts(QString pfx, Axis idx); + +    QString const& prefix() const; +    Axis axis() const; +private: +    static inline QString n(QString pfx, QString name); + +    QString prefix_; +    Axis axis_; +}; diff --git a/spline/spline-widget.cpp b/spline/spline-widget.cpp index 2aa5e6ac..aac4ef9c 100644 --- a/spline/spline-widget.cpp +++ b/spline/spline-widget.cpp @@ -60,12 +60,15 @@ void spline_widget::setConfig(spline* spl)      if (spl)      {          update_range(); -        _config->ensure_valid(_config->get_points()); +        { +            QList<QPointF> pts = _config->get_points(); +            _config->ensure_valid(pts); +        }          std::shared_ptr<spline::settings> s = spl->get_settings();          connection = connect(s.get(), &spline::settings::recomputed,                               this, [this]() { reload_spline(); }, -        Qt::QueuedConnection); +                             Qt::QueuedConnection);      }  } @@ -104,10 +107,12 @@ void spline_widget::drawBackground()      painter.fillRect(rect(), palette().background().color()); -    QColor bg_color(112, 154, 209); -    if (!isEnabled() && !_preview_only) -        bg_color = QColor(176,176,180); -    painter.fillRect(pixel_bounds, bg_color); +    { +        QColor bg_color(112, 154, 209); +        if (!isEnabled() && !_preview_only) +            bg_color = QColor(176,176,180); +        painter.fillRect(pixel_bounds, bg_color); +    }      QFont font;      font.setPointSize(8); @@ -300,6 +305,16 @@ void spline_widget::paintEvent(QPaintEvent *e)      QPointF last;      if (_config->get_last_value(last) && isEnabled())          drawPoint(p, point_to_pixel(last), QColor(255, 0, 0, 120)); + +    const QColor bg = palette().background().color(); + +    const QRect r1(pixel_bounds.left(), 0, width() - pixel_bounds.left(), pixel_bounds.top()), +                r2(pixel_bounds.right(), 0, width() - pixel_bounds.right(), height()); + +    // prevent topward artifacts the lazy way +    p.fillRect(r1, bg); +    // same for rightward artifacts +    p.fillRect(r2, bg);  }  void spline_widget::drawPoint(QPainter& painter, const QPointF& pos, const QColor& colBG, const QColor& border) @@ -508,9 +523,13 @@ void spline_widget::mouseReleaseEvent(QMouseEvent *e)  void spline_widget::reload_spline()  {      if (_config) -        _config->ensure_valid(_config->get_points()); +    { +        QList<QPointF> pts = _config->get_points(); +        _config->ensure_valid(pts); +    }      // don't recompute here as the value's about to be recomputed in the callee      update_range(); +    update();  }  int spline_widget::get_closeness_limit() diff --git a/spline/spline.cpp b/spline/spline.cpp index f28cc98d..ef1e9c58 100644 --- a/spline/spline.cpp +++ b/spline/spline.cpp @@ -13,6 +13,7 @@  #include <cmath>  #include <memory>  #include <cinttypes> +#include <utility>  #include <QObject>  #include <QMutexLocker> @@ -25,16 +26,16 @@  constexpr int spline::value_count; -spline::spline(qreal maxx, qreal maxy, const QString& name) : +spline::spline(const QString& name, const QString& axis_name, Axis axis) :      s(nullptr),      data(value_count, -16),      _mutex(QMutex::Recursive), -    max_x(maxx), -    max_y(maxy), +    ctx(std::make_shared<QObject>()), +    axis(axis),      activep(false),      validp(false)  { -    set_bundle(options::make_bundle(name)); +    set_bundle(options::make_bundle(name), axis_name, axis);  }  spline::~spline() @@ -44,11 +45,15 @@ spline::~spline()      if (connection)      {          QObject::disconnect(connection); +        QObject::disconnect(conn_maxx); +        QObject::disconnect(conn_maxy);          connection = QMetaObject::Connection(); +        conn_maxx = QMetaObject::Connection(); +        conn_maxy = QMetaObject::Connection();      }  } -spline::spline() : spline(0, 0, "") {} +spline::spline() : spline("", "", Axis(-1)) {}  void spline::set_tracking_active(bool value)  { @@ -58,6 +63,7 @@ void spline::set_tracking_active(bool value)  bundle spline::get_bundle()  { +    QMutexLocker l(&_mutex); // avoid logic errors due to changes in value<t> data      return s->b;  } @@ -68,32 +74,6 @@ void spline::clear()      validp = false;  } -void spline::set_max_input(qreal max_input) -{ -    QMutexLocker l(&_mutex); -    max_x = max_input; -    validp = false; -} - -void spline::set_max_output(qreal max_output) -{ -    QMutexLocker l(&_mutex); -    max_y = max_output; -    validp = false; -} - -qreal spline::max_input() const -{ -    QMutexLocker l(&_mutex); -    return max_x; -} - -qreal spline::max_output() const -{ -    QMutexLocker l(&_mutex); -    return max_y; -} -  float spline::get_value(double x)  {      QMutexLocker foo(&_mutex); @@ -113,9 +93,6 @@ float spline::get_value_no_save_internal(double x)  {      QMutexLocker foo(&_mutex); -    if (max_x > 0) -        x = std::fmin(max_x, x); -      float  q  = float(x * bucket_size_coefficient(s->points));      int    xi = (int)q;      float  yi = get_value_internal(xi); @@ -149,23 +126,20 @@ float spline::get_value_internal(int x)      const float sign = signum(x);      x = std::abs(x);      const float ret_ = data[std::min(unsigned(x), unsigned(value_count)-1u)]; -    float ret = sign * std::fmax(0, ret_); -    if (max_y > 0) -        ret = fmin(max_y, ret); -    return ret; +    return sign * clamp(ret_, 0, 1000);  }  void spline::add_lone_point()  {      points_t points; -    points.push_back(QPointF(max_x, max_y)); +    points.push_back(QPointF(s->opts.clamp_x_, s->opts.clamp_y_));      s->points = points;  } -QPointF spline::ensure_in_bounds(const QList<QPointF>& points, double max_x, int i) +QPointF spline::ensure_in_bounds(const QList<QPointF>& points, int i)  { -    const int sz = element_count(points, max_x); +    const int sz = points.size();      if (i < 0 || sz == 0)          return QPointF(0, 0); @@ -176,20 +150,16 @@ QPointF spline::ensure_in_bounds(const QList<QPointF>& points, double max_x, int      return points[sz - 1];  } -int spline::element_count(const QList<QPointF>& points, double max_x) +int spline::element_count(const QList<QPointF>& points, double max_input)  { -    if (!(max_x > 0)) -        return points.size(); -    else +    const unsigned sz = points.size(); +    for (unsigned k = 0; k < sz; k++)      { -        const unsigned sz = points.size(); -        for (unsigned i = 0; i < sz; i++) -        { -            if (!(points[i].x() <= max_x)) -                return i; -        } -        return points.size(); +        const QPointF& pt = points[k]; +        if (max_input > 1e-4 && pt.x() - 1e-2 > max_input) +            return k;      } +    return sz;  }  bool spline::sort_fn(const QPointF& one, const QPointF& two) @@ -200,13 +170,13 @@ bool spline::sort_fn(const QPointF& one, const QPointF& two)  void spline::update_interp_data()  {      points_t points = s->points; -      ensure_valid(points); +    const int sz = points.size(); -    int sz = element_count(points, max_x); +    const double maxx = max_input();      if (sz == 0) -        points.prepend(QPointF(max_x, max_y)); +        points.prepend(QPointF(maxx, max_output()));      std::stable_sort(points.begin(), points.begin() + sz, sort_fn); @@ -218,7 +188,7 @@ void spline::update_interp_data()      if (sz < 2)      { -        if (points[0].x() - 1e-2 <= max_x) +        if (points[0].x() - 1e-2 < maxx)          {              const double x = points[0].x();              const double y = points[0].y(); @@ -232,15 +202,15 @@ void spline::update_interp_data()      }      else      { -        if (points[0].x() > 1e-2 && points[0].x() <= max_x) +        if (points[0].x() > 1e-2 && points[0].x() <= maxx)              points.push_front(QPointF(0, 0));          for (int i = 0; i < sz; i++)          { -            const QPointF p0 = ensure_in_bounds(points, max_x, i - 1); -            const QPointF p1 = ensure_in_bounds(points, max_x, i + 0); -            const QPointF p2 = ensure_in_bounds(points, max_x, i + 1); -            const QPointF p3 = ensure_in_bounds(points, max_x, i + 2); +            const QPointF p0 = ensure_in_bounds(points, i - 1); +            const QPointF p1 = ensure_in_bounds(points, i + 0); +            const QPointF p2 = ensure_in_bounds(points, i + 1); +            const QPointF p3 = ensure_in_bounds(points, i + 2);              const double p0_x = p0.x(), p1_x = p1.x(), p2_x = p2.x(), p3_x = p3.x();              const double p0_y = p0.y(), p1_y = p1.y(), p2_y = p2.y(), p3_y = p3.y(); @@ -293,7 +263,7 @@ void spline::remove_point(int i)      QMutexLocker foo(&_mutex);      points_t points = s->points; -    const int sz = element_count(points, max_x); +    const int sz = element_count(points, max_input());      if (i >= 0 && i < sz)      { @@ -325,7 +295,7 @@ void spline::move_point(int idx, QPointF pt)      points_t points = s->points; -    const int sz = element_count(points, max_x); +    const int sz = element_count(points, max_input());      if (idx >= 0 && idx < sz)      { @@ -346,7 +316,7 @@ QList<QPointF> spline::get_points() const  int spline::get_point_count() const  {      QMutexLocker foo(&_mutex); -    return element_count(s->points, max_x); +    return element_count(s->points, s->opts.clamp_x_);  }  void spline::reload() @@ -361,7 +331,18 @@ void spline::save()      s->b->save();  } -void spline::set_bundle(bundle b) +void spline::invalidate_settings() +{ +    // we're holding the mutex to allow signal disconnection in spline dtor +    // before this slot gets called for the next time + +    QMutexLocker l(&_mutex); +    validp = false; + +    emit s->recomputed(); +} + +void spline::set_bundle(bundle b, const QString& axis_name, Axis axis)  {      QMutexLocker l(&_mutex); @@ -369,34 +350,44 @@ void spline::set_bundle(bundle b)      // the sentinel settings/bundle objects don't need any further branching once created      if (!s || s->b != b)      { -        s = std::make_shared<settings>(b); +        s = std::make_shared<settings>(b, axis_name, axis);          if (connection) +        {              QObject::disconnect(connection); +            QObject::disconnect(conn_maxx); +            QObject::disconnect(conn_maxy); +        }          if (b)          {              connection = QObject::connect(b.get(), &bundle_::changed, -            s.get(), [&]() -            { -                    // we're holding the mutex to allow signal disconnection in spline dtor -                    // before this slot gets called for the next time - -                    // spline isn't a QObject and the connection context is incorrect - -                    QMutexLocker l(&_mutex); -                    validp = false; +                                          s.get(), [&]() { invalidate_settings(); }); -                    emit s->recomputed(); -                }, -            Qt::QueuedConnection); +            // this isn't strictly necessary for the spline but helps the widget +            conn_maxx = QObject::connect(&s->opts.clamp_x_, base_value::signal_fun<int>(), +                                         ctx.get(), [&](double) { invalidate_settings(); }); +            conn_maxy = QObject::connect(&s->opts.clamp_y_, base_value::signal_fun<int>(), +                                         ctx.get(), [&](double) { invalidate_settings(); });          }          validp = false;      }  } -void spline::ensure_valid(const QList<QPointF>& the_points) +double spline::max_input() const +{ +    QMutexLocker l(&_mutex); +    return s ? s->opts.clamp_x_.to<double>() : 0; +} + +double spline::max_output() const +{ +    QMutexLocker l(&_mutex); +    return s ? std::fabs(s->opts.clamp_y_.to<double>()) : 0; +} + +void spline::ensure_valid(QList<QPointF>& the_points)  {      QMutexLocker foo(&_mutex); @@ -411,6 +402,8 @@ void spline::ensure_valid(const QList<QPointF>& the_points)      QList<QPointF> ret_list;      ret_list.reserve(sz); +    const double maxx = max_input(), maxy = max_output(); +      for (int i = 0; i < sz; i++)      {          QPointF& pt(list[i]); @@ -421,29 +414,22 @@ void spline::ensure_valid(const QList<QPointF>& the_points)                  const QPointF& pt2(list[j]);                  const QPointF tmp(pt - pt2);                  const double dist_sq = QPointF::dotProduct(tmp, tmp); -                const double overlap = max_x / 500.; +                const double overlap = maxx / 500.;                  if (dist_sq < overlap * overlap)                      return true;              }              return false;          ); -        const bool over_limit = progn( -            bool ret = false; -            if (pt.y() - 1e-2 > max_y) -            { -                pt.setY(max_y); -                ret = true; -            } -            return ret; -        ); - -        if (!overlap && !over_limit) +        if (!overlap)              ret_list.push_back(pt);      }      if (ret_list != the_points) +    {          s->points = ret_list; +        the_points = std::move(ret_list); +    }      last_input_value = QPointF(0, 0);      activep = false; @@ -466,23 +452,26 @@ double spline::bucket_size_coefficient(const QList<QPointF>& points) const  {      static constexpr double eps = 1e-4; -    if (unlikely(max_x < eps)) +    const double maxx = max_input(); + +    if (maxx < eps)          return 0;      // needed to fill the buckets up to the last control point.      // space between that point and max_x doesn't matter. -    const int sz = element_count(points, max_x); -    const double last_x = sz ? points[sz - 1].x() : max_x; +    const int sz = element_count(points, maxx); +    const double last_x = sz ? points[sz - 1].x() : maxx; -    return clamp((value_count-1) / clamp(last_x, eps, max_x), 0., (value_count-1)); +    return clamp((value_count-1) / clamp(last_x, eps, maxx), 0., (value_count-1));  }  namespace spline_detail { -settings::settings(bundle b): +settings::settings(bundle b, const QString& axis_name, Axis idx):      b(b ? b : make_bundle("")), -    points(b, "points", QList<QPointF>()) +    points(b, "points", {}), +    opts(axis_name, idx)  {}  settings::~settings() diff --git a/spline/spline.hpp b/spline/spline.hpp index cb2dc654..334e70d0 100644 --- a/spline/spline.hpp +++ b/spline/spline.hpp @@ -13,11 +13,14 @@  #include "compat/util.hpp"  using namespace options; +#include "axis-opts.hpp" +  #include "export.hpp"  #include <vector>  #include <limits>  #include <memory> +#include <functional>  #include <QObject>  #include <QPointF> @@ -29,10 +32,12 @@ namespace spline_detail {  class OTR_SPLINE_EXPORT settings final : public QObject  {      Q_OBJECT +  public:      bundle b;      value<QList<QPointF>> points; -    settings(bundle b); +    axis_opts opts; +    settings(bundle b, const QString& axis_name, Axis idx);      ~settings() override;  signals:      void recomputed() const; @@ -49,11 +54,11 @@ class OTR_SPLINE_EXPORT spline final      float get_value_no_save_internal(double x);      static bool sort_fn(const QPointF& one, const QPointF& two); -    static QPointF ensure_in_bounds(const QList<QPointF>& points, double max_x, int i); -    static int element_count(const QList<QPointF>& points, double max_x); +    static QPointF ensure_in_bounds(const QList<QPointF>& points, int i); +    static int element_count(const QList<QPointF>& points, double max_input);      std::shared_ptr<spline_detail::settings> s; -    QMetaObject::Connection connection; +    QMetaObject::Connection connection, conn_maxx, conn_maxy;      std::vector<float> data;      using interp_data_t = decltype(data); @@ -62,21 +67,27 @@ class OTR_SPLINE_EXPORT spline final      MyMutex _mutex;      QPointF last_input_value; -    qreal max_x, max_y; // XXX TODO move to value<double> -sh 20171020 +    std::shared_ptr<QObject> ctx; + +    Axis axis; +      bool activep;      bool validp;  public:      using settings = spline_detail::settings; +    void invalidate_settings(); +      void reload();      void save(); -    void set_bundle(bundle b); +    void set_bundle(bundle b, const QString& axis_name, Axis axis); + +    double max_input() const; +    double max_output() const; -    qreal max_input() const; -    qreal max_output() const;      spline(); -    spline(qreal maxx, qreal maxy, const QString& name); +    spline(const QString& name, const QString& axis_name, Axis axis);      ~spline();      spline& operator=(const spline&) = default; @@ -92,12 +103,10 @@ public:      void add_point(double x, double y);      void move_point(int idx, QPointF pt);      QList<QPointF> get_points() const; -    void set_max_input(qreal MaxInput); -    void set_max_output(qreal MaxOutput);      void set_tracking_active(bool value);      bundle get_bundle(); -    void ensure_valid(const QList<QPointF>& the_points); +    void ensure_valid(QList<QPointF>& the_points);      std::shared_ptr<settings> get_settings();      std::shared_ptr<const settings> get_settings() const; | 
