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; |