summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2017-10-20 17:53:21 +0200
committerStanislaw Halik <sthalik@misaki.pl>2017-10-20 17:53:21 +0200
commit39e209983bd1f04fb0beefef754d7430c8b7fb9f (patch)
treeec41545dda2d33d316adc6466f21138a280db6a8
parent092e2910ae8f6c2e188e930b9540d58e145c9142 (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.cpp43
-rw-r--r--logic/main-settings.cpp39
-rw-r--r--logic/main-settings.hpp45
-rw-r--r--logic/mappings.cpp27
-rw-r--r--logic/mappings.hpp4
-rw-r--r--options/base-value.hpp1
-rw-r--r--spline/CMakeLists.txt4
-rw-r--r--spline/axis-opts.cpp47
-rw-r--r--spline/axis-opts.hpp53
-rw-r--r--spline/spline-widget.cpp33
-rw-r--r--spline/spline.cpp183
-rw-r--r--spline/spline.hpp33
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;