summaryrefslogtreecommitdiffstats
path: root/src/curveeditor/animationcurve.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/curveeditor/animationcurve.cpp')
-rw-r--r--src/curveeditor/animationcurve.cpp175
1 files changed, 105 insertions, 70 deletions
diff --git a/src/curveeditor/animationcurve.cpp b/src/curveeditor/animationcurve.cpp
index 4818a81..acb64ce 100644
--- a/src/curveeditor/animationcurve.cpp
+++ b/src/curveeditor/animationcurve.cpp
@@ -24,120 +24,155 @@
****************************************************************************/
#include "animationcurve.h"
+#include "detail/curvesegment.h"
-#include <assert.h>
-#include <cmath>
+#include <QLineF>
namespace DesignTools {
-Keyframe::Keyframe()
- : m_position()
- , m_leftHandle()
- , m_rightHandle()
+AnimationCurve::AnimationCurve()
+ : m_frames()
{}
-Keyframe::Keyframe(const QPointF &position)
- : m_position(position)
- , m_leftHandle()
- , m_rightHandle()
-{}
+AnimationCurve::AnimationCurve(const std::vector<Keyframe> &frames)
+ : m_frames(frames)
+ , m_minY(std::numeric_limits<double>::max())
+ , m_maxY(std::numeric_limits<double>::lowest())
+{
+ if (m_frames.size() >= 2) {
+ for (auto e : extrema()) {
-Keyframe::Keyframe(const QPointF &position, const QPointF &leftHandle, const QPointF &rightHandle)
- : m_position(position)
- , m_leftHandle(leftHandle)
- , m_rightHandle(rightHandle)
-{}
+ if (m_minY > e.y())
+ m_minY = e.y();
-bool Keyframe::hasLeftHandle() const
-{
- return !m_leftHandle.isNull();
+ if (m_maxY < e.y())
+ m_maxY = e.y();
+ }
+ }
}
-bool Keyframe::hasRightHandle() const
+bool AnimationCurve::isValid() const
{
- return !m_rightHandle.isNull();
+ return !m_frames.empty();
}
-QPointF Keyframe::position() const
+double AnimationCurve::minimumTime() const
{
- return m_position;
+ if (!m_frames.empty())
+ return m_frames.front().position().x();
+
+ return std::numeric_limits<double>::max();
}
-QPointF Keyframe::leftHandle() const
+double AnimationCurve::maximumTime() const
{
- return m_leftHandle;
+ if (!m_frames.empty())
+ return m_frames.back().position().x();
+
+ return std::numeric_limits<double>::lowest();
}
-QPointF Keyframe::rightHandle() const
+double AnimationCurve::minimumValue() const
{
- return m_rightHandle;
+ return m_minY;
}
-void Keyframe::setPosition(const QPointF &pos)
+double AnimationCurve::maximumValue() const
{
- m_position = pos;
+ return m_maxY;
}
-void Keyframe::setLeftHandle(const QPointF &pos)
+std::vector<Keyframe> AnimationCurve::keyframes() const
{
- m_leftHandle = pos;
+ return m_frames;
}
-void Keyframe::setRightHandle(const QPointF &pos)
+std::vector<QPointF> AnimationCurve::extrema() const
{
- m_rightHandle = pos;
-}
+ std::vector<QPointF> out;
+ CurveSegment segment;
+ segment.setLeft(m_frames.at(0));
-CurveSegment::CurveSegment()
- : m_left()
- , m_right()
-{}
+ for (size_t i = 1; i < m_frames.size(); ++i) {
-CurveSegment::CurveSegment(const Keyframe &left, const Keyframe &right)
- : m_left(left)
- , m_right(right)
-{}
+ segment.setRight(m_frames[i]);
+
+ const auto es = segment.extrema();
+ out.insert(std::end(out), std::begin(es), std::end(es));
+
+ segment.setLeft(m_frames[i]);
+ }
+
+ return out;
+}
-QPointF CurveSegment::evaluate(double t) const
+std::vector<double> AnimationCurve::yForX(double x) const
{
- assert(t >= 0. && t <= 1.);
+ if (m_frames.front().position().x() > x)
+ return std::vector<double>();
+
+ CurveSegment segment;
+ for (auto &frame : m_frames) {
+ if (frame.position().x() > x) {
+ segment.setRight(frame);
+ return segment.yForX(x);
+ }
+ segment.setLeft(frame);
+ }
+ return std::vector<double>();
+}
- const double it = 1.0 - t;
+std::vector<double> AnimationCurve::xForY(double y, uint segment) const
+{
+ if (m_frames.size() > segment + 1) {
+ CurveSegment seg(m_frames[segment], m_frames[segment + 1]);
+ return seg.xForY(y);
+ }
+ return std::vector<double>();
+}
- auto binomialPolynomial = [t, it](double p0, double p1, double p2, double p3) {
- return p0 * std::pow(it, 3.0) + p1 * 3.0 * std::pow(it, 2.0) * t
- + p2 * 3.0 * it * std::pow(t, 2.0) + p3 * std::pow(t, 3.0);
- };
+bool AnimationCurve::intersects(const QPointF &coord, double radius)
+{
+ if (m_frames.size() < 2)
+ return false;
- const double x = binomialPolynomial(
- m_left.position().x(), m_left.rightHandle().x(),
- m_right.leftHandle().x(), m_right.position().x());
+ std::vector<CurveSegment> influencer;
- const double y = binomialPolynomial(
- m_left.position().y(), m_left.rightHandle().y(),
- m_right.leftHandle().y(), m_right.position().y());
+ CurveSegment current;
+ current.setLeft(m_frames.at(0));
- return QPointF(x, y);
-}
+ for (size_t i = 1; i < m_frames.size(); ++i) {
+ Keyframe &frame = m_frames.at(i);
+ current.setRight(frame);
-AnimationCurve::AnimationCurve()
- : m_frames()
-{}
+ if (current.containsX(coord.x() - radius) ||
+ current.containsX(coord.x()) ||
+ current.containsX(coord.x() + radius)) {
+ influencer.push_back(current);
+ }
-AnimationCurve::AnimationCurve(const std::vector<Keyframe> &frames)
- : m_frames(frames)
-{}
+ if (frame.position().x() > coord.x() + radius)
+ break;
-bool AnimationCurve::isValid() const
-{
- return !m_frames.empty();
-}
+ current.setLeft(frame);
+ }
-std::vector<Keyframe> AnimationCurve::keyframes() const
-{
- return m_frames;
+ for (auto &segment : influencer) {
+ for (auto &y : segment.yForX(coord.x())) {
+ QLineF line(coord.x(), y, coord.x(), coord.y());
+ if (line.length() < radius)
+ return true;
+ }
+
+ for (auto &x : segment.xForY(coord.y())) {
+ QLineF line(x, coord.y(), coord.x(), coord.y());
+ if (line.length() < radius)
+ return true;
+ }
+ }
+ return false;
}
} // End namespace DesignTools.