summaryrefslogtreecommitdiffhomepage
path: root/spline/spline.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'spline/spline.cpp')
-rw-r--r--spline/spline.cpp97
1 files changed, 70 insertions, 27 deletions
diff --git a/spline/spline.cpp b/spline/spline.cpp
index 21044b34..466a9a7f 100644
--- a/spline/spline.cpp
+++ b/spline/spline.cpp
@@ -42,8 +42,10 @@ void spline::set_tracking_active(bool value) const
std::shared_ptr<settings> S;
{
QMutexLocker l(&mtx);
- S = s;
+ if (value == activep)
+ return;
activep = value;
+ S = s;
}
emit S->recomputed();
}
@@ -98,10 +100,10 @@ bool spline::get_last_value(QPointF& point)
double spline::get_value_internal(int x) const
{
- const float sign = signum(x);
+ const auto sign = (f)signum(x);
x = std::abs(x);
- const float ret_ = data[std::min(unsigned(x), value_count - 1)];
- return (double)(sign * clamp(ret_, 0, 1000));
+ const auto ret_ = data[std::min(unsigned(x), value_count - 1)];
+ return (double)(sign * std::clamp(ret_, (f)0, (f)1000));
}
void spline::ensure_in_bounds(const QList<QPointF>& points, int i, f& x, f& y)
@@ -129,7 +131,7 @@ void spline::ensure_in_bounds(const QList<QPointF>& points, int i, f& x, f& y)
int spline::element_count(const QList<QPointF>& points, double max_input)
{
- const unsigned sz = (unsigned)points.size();
+ const int sz = points.size();
for (int k = sz-1; k >= 0; k--)
{
const QPointF& pt = points[k];
@@ -139,7 +141,7 @@ int spline::element_count(const QList<QPointF>& points, double max_input)
return sz;
}
-bool spline::sort_fn(const QPointF& one, const QPointF& two)
+bool spline::sort_fn(QPointF one, QPointF two)
{
return one.x() < two.x();
}
@@ -148,14 +150,14 @@ void spline::update_interp_data() const
{
points_t list = points;
ensure_valid(list);
- const int sz = list.size();
+ int sz = list.size();
if (list.isEmpty())
list.prepend({ max_input(), max_output() });
const double c = bucket_size_coefficient(list);
const double c_ = c * c_interp;
- const float cf = (float)c, c_f = (float)c_;
+ const f cf = (f)c, c_f = (f)c_;
for (unsigned i = 0; i < value_count; i++)
data[i] = magic_fill_value;
@@ -165,15 +167,34 @@ void spline::update_interp_data() const
const QPointF& pt = list[0];
const double x = pt.x();
const double y = pt.y();
- const unsigned max = clamp(uround(x * c), 0, value_count-1);
+ const unsigned max = std::clamp((unsigned)iround(x * c), 1u, value_count-1);
for (unsigned k = 0; k <= max; k++)
- data[k] = float(y * k / max); // no need for bresenham
+ data[k] = f(y * k / max); // no need for bresenham
+ }
+ else if (sz == 2 && list[0].y() < 1e-6)
+ {
+ unsigned start = std::clamp((unsigned)iround(list[0].x() * c), 1u, value_count-1);
+ unsigned end = std::clamp((unsigned)iround(list[1].x() * c), 2u, value_count-1);
+ unsigned max = end - start;
+ for (unsigned x = 0; x < start; x++)
+ data[x] = 0;
+ for (unsigned x = 0; x < max; x++)
+ data[start + x] = (f)(list[1].y() * x / max);
}
else
{
- if (list[0].x() > 1e-2)
- list.push_front({});
+ if (list[0].x() > 1e-6)
+ {
+ double zero_pos = 0;
+ while (list.size() > 1 && list[0].y() <= 1e-6)
+ {
+ zero_pos = list[0].x();
+ list.pop_front();
+ }
+ list.push_front({zero_pos, 0});
+ sz = list.size();
+ }
// now this is hella expensive due to `c_interp'
for (int i = 0; i < sz; i++)
@@ -210,21 +231,32 @@ void spline::update_interp_data() const
const f t2 = t*t;
const f t3 = t*t*t;
- const unsigned x = unsigned(f(.5) * cf * (cx[0] + cx[1] * t + cx[2] * t2 + cx[3] * t3));
- const float y = (float)(f(.5) * (cy[0] + cy[1] * t + cy[2] * t2 + cy[3] * t3));
-
- int ret = std::fpclassify(y);
- if (ret == FP_NAN || ret == FP_INFINITE)
+ const auto x = (unsigned)(f(.5) * cf * (cx[0] + cx[1] * t + cx[2] * t2 + cx[3] * t3));
+ const auto y = (f)(f(.5) * (cy[0] + cy[1] * t + cy[2] * t2 + cy[3] * t3));
+
+ switch (int ret = std::fpclassify(y))
+ {
+ case FP_INFINITE:
+ case FP_NAN:
+ case FP_SUBNORMAL:
+ eval_once(qDebug() << "spline: fpclassify" << y
+ << "returned" << ret
+ << "for bundle" << s->b->name());
continue;
-
- if (x < value_count)
- data[x] = y;
+ case FP_ZERO:
+ case FP_NORMAL:
+ if (x < value_count)
+ data[x] = y;
+ break;
+ default:
+ unreachable();
+ }
}
}
}
- float maxy = (float)max_output();
- float last = 0;
+ auto maxy = (f)max_output();
+ auto last = (f)0;
#ifdef __clang__
# pragma clang diagnostic push
@@ -235,10 +267,21 @@ void spline::update_interp_data() const
{
if (data[i] == magic_fill_value)
data[i] = last;
- data[i] = clamp(data[i], 0, maxy);
+ data[i] = std::clamp(data[i], (f)0, (f)maxy);
last = data[i];
}
+ // make sure empty places stay empty (see #1341)
+ if (auto it = std::find_if(list.cbegin(), list.cend(),
+ [](QPointF x) { return x.x() >= (f)1e-6 && x.y() >= (f)1e-6; });
+ it != list.cend() && it != list.cbegin())
+ {
+ it--;
+ unsigned max = std::clamp((unsigned)iround(it->x() * c), 0u, value_count-1);
+
+ for (unsigned x = 0; x < max; x++)
+ data[x] = 0;
+ }
#ifdef __clang__
# pragma clang diagnostic pop
#endif
@@ -361,11 +404,11 @@ void spline::set_bundle(bundle b, const QString& axis_name, Axis axis)
S = s;
conn_points = QObject::connect(&s->points, value_::value_changed<QList<QPointF>>(),
- ctx.get(), [this] { invalidate_settings(); }, Qt::DirectConnection);
+ &*ctx, [this] { invalidate_settings(); }, Qt::DirectConnection);
conn_maxx = QObject::connect(&s->opts.clamp_x_, value_::value_changed<int>(),
- ctx.get(), [this](double) { invalidate_settings(); }, Qt::DirectConnection);
+ &*ctx, [this](double) { invalidate_settings(); }, Qt::DirectConnection);
conn_maxy = QObject::connect(&s->opts.clamp_y_, value_::value_changed<int>(),
- ctx.get(), [this](double) { invalidate_settings(); }, Qt::DirectConnection);
+ &*ctx, [this](double) { invalidate_settings(); }, Qt::DirectConnection);
}
emit S->recomputed();
@@ -472,7 +515,7 @@ double spline::bucket_size_coefficient(const QList<QPointF>& points) const
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, maxx), 0., (value_count-1));
+ return std::clamp((value_count-1) / std::clamp(last_x, eps, maxx), 0., (value_count-1.));
}
void spline::disconnect_signals()