summaryrefslogtreecommitdiffhomepage
path: root/spline/spline.cpp
diff options
context:
space:
mode:
authorStanisław Halik <sthalik@misaki.pl>2017-05-14 16:22:09 +0200
committerGitHub <noreply@github.com>2017-05-14 16:22:09 +0200
commit5c23666b58bb1dd4aea15c0d62a2f716d5be7f52 (patch)
treee6497e9b55c073be209ec673ef05e62bf57a2c8f /spline/spline.cpp
parent4701dd3b0c8323a11cf7d5ad09c579a9864a41bd (diff)
parentc392181211b245e74292424500265323c960c1aa (diff)
Merge branch 'unstable' into unstable
Diffstat (limited to 'spline/spline.cpp')
-rw-r--r--spline/spline.cpp129
1 files changed, 65 insertions, 64 deletions
diff --git a/spline/spline.cpp b/spline/spline.cpp
index 195d68d6..7ca8147c 100644
--- a/spline/spline.cpp
+++ b/spline/spline.cpp
@@ -25,7 +25,7 @@ constexpr int spline::value_count;
spline::spline(qreal maxx, qreal maxy, const QString& name) :
s(nullptr),
- data(value_count, -1.f),
+ data(value_count, -16),
_mutex(QMutex::Recursive),
max_x(maxx),
max_y(maxy),
@@ -50,6 +50,7 @@ spline::spline() : spline(0, 0, "") {}
void spline::set_tracking_active(bool value)
{
+ QMutexLocker l(&_mutex);
activep = value;
}
@@ -69,14 +70,14 @@ void spline::set_max_input(qreal max_input)
{
QMutexLocker l(&_mutex);
max_x = max_input;
- recompute();
+ validp = false;
}
void spline::set_max_output(qreal max_output)
{
QMutexLocker l(&_mutex);
max_y = max_output;
- recompute();
+ validp = false;
}
qreal spline::max_input() const
@@ -113,7 +114,7 @@ float spline::get_value_no_save_internal(double x)
if (max_x > 0)
x = std::fmin(max_x, x);
- float q = float(x * precision(s->points));
+ float q = float(x * bucket_size_coefficient(s->points));
int xi = (int)q;
float yi = get_value_internal(xi);
float yiplus1 = get_value_internal(xi+1);
@@ -139,8 +140,7 @@ float spline::get_value_internal(int x)
float sign = x < 0 ? -1 : 1;
x = std::abs(x);
- float ret;
- ret = data[std::min(unsigned(x), unsigned(value_count)-1u)];
+ float ret = data[std::min(unsigned(x), unsigned(value_count)-1u)];
return ret * sign;
}
@@ -183,13 +183,15 @@ int spline::element_count(const QList<QPointF>& points, double max_x)
bool spline::sort_fn(const QPointF& one, const QPointF& two)
{
- return one.x() <= two.x();
+ return one.x() < two.x();
}
void spline::update_interp_data()
{
points_t points = s->points;
+ ensure_valid(points);
+
int sz = element_count(points, max_x);
if (sz == 0)
@@ -197,11 +199,11 @@ void spline::update_interp_data()
std::stable_sort(points.begin(), points.begin() + sz, sort_fn);
- const double mult = precision(points);
- const double mult_ = mult * 30;
+ const double c = bucket_size_coefficient(points);
+ const double c_interp = c * 30;
for (unsigned i = 0; i < value_count; i++)
- data[i] = -1;
+ data[i] = -16;
if (sz < 2)
{
@@ -209,7 +211,7 @@ void spline::update_interp_data()
{
const double x = points[0].x();
const double y = points[0].y();
- const int max = clamp(int(x * precision(points)), 1, value_count-1);
+ const int max = clamp(iround(x * c), 1, value_count-1);
for (int k = 0; k <= max; k++)
{
if (k < value_count)
@@ -247,20 +249,21 @@ void spline::update_interp_data()
};
// multiplier helps fill in all the x's needed
- const unsigned end = std::min(unsigned(value_count), unsigned(p2_x * mult_));
- const unsigned start = std::max(0u, unsigned(p1_x * mult));
+ const unsigned end = int(c_interp * (p2_x - p1_x)) + 1;
- for (unsigned j = start; j < end; j++)
+ for (unsigned k = 0; k <= end; k++)
{
- const double t = (j - start) / (double) (end - start);
+ const double t = k / double(end);
const double t2 = t*t;
const double t3 = t*t*t;
- const int x = iround(.5 * mult * (cx[0] + cx[1] * t + cx[2] * t2 + cx[3] * t3));
+ const int x = int(.5 * c * (cx[0] + cx[1] * t + cx[2] * t2 + cx[3] * t3));
const float y = float(.5 * (cy[0] + cy[1] * t + cy[2] * t2 + cy[3] * t3));
if (x >= 0 && x < value_count)
- data[unsigned(x)] = y;
+ {
+ data[x] = y;
+ }
}
}
}
@@ -268,7 +271,7 @@ void spline::update_interp_data()
float last = 0;
for (unsigned i = 0; i < unsigned(value_count); i++)
{
- if (data[i] < 0)
+ if (data[i] == -16)
data[i] = last;
last = data[i];
}
@@ -317,7 +320,7 @@ void spline::move_point(int idx, QPointF pt)
{
points[idx] = pt;
// we don't allow points to be reordered, but sort due to possible caller logic error
- //std::stable_sort(points.begin(), points.end(), sort_fn);
+ std::stable_sort(points.begin(), points.end(), sort_fn);
s->points = points;
validp = false;
}
@@ -332,7 +335,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, max_x);
}
void spline::reload()
@@ -341,15 +344,10 @@ void spline::reload()
s->b->reload();
}
-void spline::save(QSettings& settings)
-{
- QMutexLocker foo(&_mutex);
- s->b->save_deferred(settings);
-}
-
void spline::save()
{
- save(*group::ini_file());
+ QMutexLocker foo(&_mutex);
+ s->b->save();
}
void spline::set_bundle(bundle b)
@@ -368,38 +366,35 @@ void spline::set_bundle(bundle b)
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
+ 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
+ // spline isn't a QObject and the connection context is incorrect
- QMutexLocker l(&_mutex);
- recompute();
- emit s->recomputed();
- },
- Qt::QueuedConnection);
- }
+ QMutexLocker l(&_mutex);
+ validp = false;
- recompute();
+ emit s->recomputed();
+ },
+ Qt::QueuedConnection);
+ }
- emit s->recomputed();
+ validp = false;
}
}
-void spline::recompute()
+void spline::ensure_valid(const QList<QPointF>& the_points)
{
QMutexLocker foo(&_mutex);
- QList<QPointF> list = s->points;
+ QList<QPointF> list = the_points;
// storing to s->points fires bundle::changed and that leads to an infinite loop
- // only store if we can't help it
+ // thus, only store if we can't help it
std::stable_sort(list.begin(), list.end(), sort_fn);
- if (list != s->points)
- s->points = list;
-
const int sz = list.size();
QList<QPointF> ret_list;
@@ -410,49 +405,55 @@ void spline::recompute()
QPointF& pt(list[i]);
const bool overlap = progn(
- for (int j = 0; j < i; j++)
- {
- QPointF& pt2(list[j]);
- const double dist_sq = (pt.x() - pt2.x())*(pt.x() - pt2.x());
- static constexpr double overlap = .6;
- if (dist_sq < overlap * overlap)
- return true;
- }
- return false;
- );
+ for (int j = 0; j < i; j++)
+ {
+ const QPointF& pt2(list[j]);
+ const QPointF tmp(pt - pt2);
+ const double dist_sq = QPointF::dotProduct(tmp, tmp);
+ const double overlap = max_x / 500.;
+ if (dist_sq < overlap * overlap)
+ return true;
+ }
+ return false;
+ );
if (!overlap)
ret_list.push_back(pt);
}
- if (ret_list != s->points)
+ if (ret_list != the_points)
s->points = ret_list;
last_input_value = QPointF(0, 0);
activep = false;
- validp = false;
}
// the return value is only safe to use with no spline::set_bundle calls
-mem<spline::settings> spline::get_settings()
+std::shared_ptr<spline::settings> spline::get_settings()
{
QMutexLocker foo(&_mutex);
return s;
}
-mem<const spline::settings> spline::get_settings() const
+std::shared_ptr<const spline::settings> spline::get_settings() const
{
QMutexLocker foo(&_mutex);
return s;
}
-double spline::precision(const QList<QPointF>& points) const
+double spline::bucket_size_coefficient(const QList<QPointF>& points) const
{
- // this adjusts the memoized range to the largest X value. empty space doesn't take value_count discrete points.
+ static constexpr double eps = 1e-4;
+
+ if (unlikely(max_x < 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);
- if (sz)
- return clamp(value_count / clamp(points[sz - 1].x(), 1., max_x), 0., double(value_count));
+ const double last_x = sz ? points[sz - 1].x() : max_x;
- return value_count / clamp(max_x, 1., double(value_count));
+ return clamp((value_count-1) / clamp(last_x, eps, max_x), 0., (value_count-1));
}
namespace spline_detail {