summaryrefslogtreecommitdiffhomepage
path: root/spline-widget/spline.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'spline-widget/spline.cpp')
-rw-r--r--spline-widget/spline.cpp315
1 files changed, 127 insertions, 188 deletions
diff --git a/spline-widget/spline.cpp b/spline-widget/spline.cpp
index 48b508ef..da67f0d4 100644
--- a/spline-widget/spline.cpp
+++ b/spline-widget/spline.cpp
@@ -10,31 +10,29 @@
#include <QMutexLocker>
#include <QCoreApplication>
#include <QPointF>
-#include <QList>
-#include <QtAlgorithms>
-#include <QtAlgorithms>
#include <QSettings>
-#include <QPixmap>
#include <QString>
#include <algorithm>
#include <cmath>
#include <QDebug>
+constexpr int spline::value_count;
+
void spline::setTrackingActive(bool blnActive)
{
activep = blnActive;
}
-spline::spline() : spline(0, 0)
+spline::spline() : spline(0, 0, "")
{
}
void spline::removeAllPoints()
{
- QMutexLocker foo(&_mutex);
- cur.input.clear();
- reload();
+ QMutexLocker l(&_mutex);
+ s->points = points_t();
+ update_interp_data();
}
void spline::setMaxInput(qreal max_input)
@@ -61,30 +59,28 @@ qreal spline::maxOutput() const
return max_y;
}
-spline::spline(qreal maxx, qreal maxy) :
+// todo try non-recursive mtx
+spline::spline(qreal maxx, qreal maxy, const QString& name) :
+ data(value_count, -1.f),
_mutex(QMutex::Recursive),
- max_x(0),
- max_y(0),
+ max_x(maxx),
+ max_y(maxy),
activep(false)
{
- setMaxInput(maxx);
- setMaxOutput(maxy);
- if (cur.input.size() == 0)
- cur.input.push_back(QPointF(maxx, maxy));
- reload();
+ set_bundle(options::make_bundle(name));
}
-float spline::getValue(float x)
+float spline::getValue(double x)
{
QMutexLocker foo(&_mutex);
- float q = x * precision();
+ float q = float(x * precision(s->points));
int xi = (int)q;
float yi = getValueInternal(xi);
float yiplus1 = getValueInternal(xi+1);
float f = (q-xi);
float ret = yiplus1 * f + yi * (1.0f - f); // at least do a linear interpolation.
last_input_value.setX(std::fabs(x));
- last_input_value.setY(std::fabs(ret));
+ last_input_value.setY(double(std::fabs(ret)));
return ret;
}
@@ -100,244 +96,187 @@ float spline::getValueInternal(int x)
float sign = x < 0 ? -1 : 1;
x = abs(x);
float ret;
- unsigned sz = cur.data.size();
- if (sz == 0)
- ret = 0;
- else
- ret = cur.data[std::min(unsigned(x), sz-1u)];
+ ret = data[std::min(unsigned(x), unsigned(value_count)-1u)];
return ret * sign;
}
-static QPointF ensureInBounds(const QList<QPointF>& points, int i)
+void spline::add_lone_point()
+{
+ points_t points;
+ points.push_back(QPointF(max_x, max_y));
+
+ s->points = points;
+}
+
+QPointF spline::ensure_in_bounds(const QList<QPointF>& points, int i)
{
- int siz = points.size();
- if (siz == 0 || i < 0)
+ const int sz = points.size();
+
+ if (i < 0 || sz == 0)
return QPointF(0, 0);
- if (siz > i)
+ if (i < sz)
return points[i];
- return points[siz - 1];
+ return points[sz - 1];
}
-static bool sortFn(const QPointF& one, const QPointF& two)
+bool spline::sort_fn(const QPointF& one, const QPointF& two)
{
return one.x() < two.x();
}
-void spline::reload()
+void spline::update_interp_data()
{
- if (cur.input.size())
- {
- std::stable_sort(cur.input.begin(), cur.input.end(), sortFn);
+ points_t points = s->points;
- QList<QPointF> input = cur.input;
- auto& data = cur.data;
+ if (points.size() == 0)
+ points.append(QPointF(max_x, max_y));
- data = std::vector<float>(value_count);
- const float mult = precision();
- const unsigned mult_ = unsigned(mult * 30);
+ std::stable_sort(points.begin(), points.end(), sort_fn);
- const unsigned sz = data.size();
+ const double mult = precision(points);
+ const double mult_ = mult * 30;
- for (unsigned i = 0; i < sz; i++)
- data[i] = -1;
+ for (unsigned i = 0; i < value_count; i++)
+ data[i] = -1;
- if (input.size() == 1 && input[0].x() > 1e-2)
+ if (points.size() == 1)
+ {
+ const double x = points[0].x();
+ const double y = points[0].y();
+ const int max = clamp(int(x * precision(points)), 0, value_count-1);
+ for (int k = 0; k <= max; k++)
{
- const float x = float(input[0].x());
- const float y = float(input[0].y());
- const unsigned max = unsigned(x * mult);
- for (unsigned k = 0; k < max; k++) {
- if (k < sz)
- data[k] = y * k / max;
- }
+ if (k < value_count)
+ data[unsigned(k)] = float(y * k / max);
}
- else if (input[0].x() > 1e-2)
- input.prepend(QPointF(0, 0));
+ }
+ else
+ {
+ if (points[0].x() > 1e-2)
+ points.push_front(QPointF(0, 0));
- for (int i = 0; i < int(sz); i++)
+ for (int i = 0; i < points.size(); i++)
{
- const QPointF p0 = ensureInBounds(input, i - 1);
- const QPointF p1 = ensureInBounds(input, i);
- const QPointF p2 = ensureInBounds(input, i + 1);
- const QPointF p3 = ensureInBounds(input, i + 2);
+ const QPointF p0 = ensure_in_bounds(points, i - 1);
+ const QPointF p1 = ensure_in_bounds(points, i);
+ const QPointF p2 = ensure_in_bounds(points, i + 1);
+ const QPointF p3 = ensure_in_bounds(points, i + 2);
- const float p0_x = p0.x(), p1_x = p1.x(), p2_x = p2.x(), p3_x = p3.x();
- const float p0_y = p0.y(), p1_y = p1.y(), p2_y = p2.y(), p3_y = p3.y();
+ 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();
// multiplier helps fill in all the x's needed
- const unsigned end = std::min(sz, unsigned(p2_x * mult_));
- const unsigned start = unsigned(p1_x * mult);
+ const unsigned end = std::min(unsigned(value_count), unsigned(p2_x * mult_));
+ const unsigned start = std::max(0u, unsigned(p1_x * mult));
for (unsigned j = start; j < end; j++)
{
- const float t = (j - start) / (float) (end - start);
- const float t2 = t*t;
- const float t3 = t*t*t;
-
- const int x = .5f * ((2 * p1_x) +
- (-p0_x + p2_x) * t +
- (2 * p0_x - 5 * p1_x + 4 * p2_x - p3_x) * t2 +
- (-p0_x + 3 * p1_x - 3 * p2_x + p3_x) * t3)
- * mult;
-
- const float y = .5f * ((2 * p1_y) +
- (-p0_y + p2_y) * t +
- (2 * p0_y - 5 * p1_y + 4 * p2_y - p3_y) * t2 +
- (-p0_y + 3 * p1_y - 3 * p2_y + p3_y) * t3);
-
- if (x >= 0 && x < (int)sz)
- data[x] = y;
+ const double t = (j - start) / (double) (end - start);
+ const double t2 = t*t;
+ const double t3 = t*t*t;
+
+ const int x = int(.5 * ((2 * p1_x) +
+ (-p0_x + p2_x) * t +
+ (2 * p0_x - 5 * p1_x + 4 * p2_x - p3_x) * t2 +
+ (-p0_x + 3 * p1_x - 3 * p2_x + p3_x) * t3)
+ * mult);
+
+ const float y = float(.5 * ((2 * p1_y) +
+ (-p0_y + p2_y) * t +
+ (2 * p0_y - 5 * p1_y + 4 * p2_y - p3_y) * t2 +
+ (-p0_y + 3 * p1_y - 3 * p2_y + p3_y) * t3));
+
+ if (x >= 0 && x < value_count)
+ data[unsigned(x)] = y;
}
}
+ }
- float last = 0;
- for (unsigned i = 0; i < sz; i++)
- {
- if (data[i] < 0)
- data[i] = last;
- last = data[i];
- }
+ float last = 0;
+ for (unsigned i = 0; i < unsigned(value_count); i++)
+ {
+ if (data[i] < 0)
+ data[i] = last;
+ last = data[i];
}
- else
- cur.data.clear();
}
void spline::removePoint(int i)
{
QMutexLocker foo(&_mutex);
- if (i >= 0 && i < cur.input.size())
+
+ points_t points = s->points;
+
+ if (i >= 0 && i < points.size())
{
- cur.input.removeAt(i);
- reload();
+ points.erase(points.begin() + i);
+ s->points = points;
+ update_interp_data();
}
}
void spline::addPoint(QPointF pt)
{
QMutexLocker foo(&_mutex);
- cur.input.append(pt);
- reload();
- std::stable_sort(cur.input.begin(), cur.input.end(), sortFn);
+
+ points_t points = s->points;
+ points.push_back(pt);
+ std::stable_sort(points.begin(), points.end(), sort_fn);
+ s->points = points;
+ update_interp_data();
}
void spline::movePoint(int idx, QPointF pt)
{
QMutexLocker foo(&_mutex);
- if (idx >= 0 && idx < cur.input.size())
+
+ points_t points = s->points;
+
+ if (idx >= 0 && idx < points.size())
{
- cur.input[idx] = pt;
+ points[idx] = pt;
// we don't allow points to be reordered, but sort due to possible caller logic error
- std::stable_sort(cur.input.begin(), cur.input.end(), sortFn);
- reload();
+ std::stable_sort(points.begin(), points.end(), sort_fn);
+ s->points = points;
+ update_interp_data();
}
}
-const QList<QPointF> spline::getPoints()
+QList<QPointF> spline::getPoints() const
{
QMutexLocker foo(&_mutex);
- return cur.input;
+ return s->points;
}
-void spline::invalidate_unsaved_settings()
+void spline::reload()
{
- QMutexLocker foo(&_mutex);
- cur = saved;
- reload();
+ if (s && s->b)
+ s->b->reload();
}
-void spline::loadSettings(QSettings& settings, const QString& title)
+void spline::save()
{
- QMutexLocker foo(&_mutex);
- QPointF newPoint;
- QList<QPointF> points;
- settings.beginGroup(QString("Curves-%1").arg(title));
-
- int max = settings.value("point-count", 0).toInt();
-
- for (int i = 0; i < max; i++)
- {
- newPoint = QPointF(settings.value(QString("point-%1-x").arg(i), 0).toDouble(),
- settings.value(QString("point-%1-y").arg(i), 0).toDouble());
- if (newPoint.x() > max_x)
- newPoint.setX(max_x);
- if (newPoint.y() > max_y)
- newPoint.setY(max_y);
- points.append(newPoint);
- }
-
- settings.endGroup();
-
- if (max == 0)
- points.append(QPointF(maxInput(), maxOutput()));
-
- cur.input = points;
- reload();
- saved = cur;
+ if (s && s->b)
+ s->b->save();
}
-bool spline::State::operator==(const State& other) const
+void spline::set_bundle(bundle b)
{
- if (input.size() != other.input.size())
- return false;
-
- const int sz = input.size();
-
- using std::fabs;
+ if (b)
+ s = std::unique_ptr<settings>(new settings(b));
+ else
+ s = std::unique_ptr<settings>(new settings(options::make_bundle("")));
- for (int i = 0; i < sz; i++)
- {
- const qreal eps = 1e-3;
+ last_input_value = QPointF(0, 0);
+ activep = false;
- if (fabs(input[i].x() - other.input[i].x()) > eps ||
- fabs(input[i].y() - other.input[i].y()) > eps)
- {
- return false;
- }
- }
- return true;
+ update_interp_data();
}
-void spline::saveSettings(QSettings& settings, const QString& title)
+int spline::precision(const QList<QPointF>& points) const
{
- QMutexLocker foo(&_mutex);
-
- if (cur == saved)
- return;
+ if (points.size())
+ return int(value_count / clamp(points[points.size() - 1].x(), 1, max_x));
- qDebug() << "spline-widget: saving" << title;
-
- settings.beginGroup(QStringLiteral("Curves-%1").arg(title));
-
- if (cur.input.size() == 0)
- cur.input.push_back(QPointF(max_x, max_y));
-
- const int max = cur.input.size();
- settings.setValue("point-count", max);
-
- for (int i = 0; i < max; i++)
- {
- settings.setValue(QString("point-%1-x").arg(i), cur.input[i].x());
- settings.setValue(QString("point-%1-y").arg(i), cur.input[i].y());
- }
-
- for (int i = max; true; i++)
- {
- QString x = QString("point-%1-x").arg(i);
- if (!settings.contains(x))
- break;
- settings.remove(x);
- settings.remove(QString("point-%1-y").arg(i));
- }
-
- saved = cur;
-
- settings.endGroup();
-}
-
-
-int spline::precision() const
-{
- if (cur.input.size())
- return (value_count-1) / std::max<float>(1.f, (cur.input[cur.input.size() - 1].x()));
- return 1;
+ return value_count / clamp(int(max_x), 1, value_count);
}