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 /spline/spline.cpp | |
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
Diffstat (limited to 'spline/spline.cpp')
-rw-r--r-- | spline/spline.cpp | 183 |
1 files changed, 86 insertions, 97 deletions
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() |