diff options
Diffstat (limited to 'src/curveeditor/animationcurve.cpp')
-rw-r--r-- | src/curveeditor/animationcurve.cpp | 175 |
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. |