From 913d6d99a798de8b32e387f49cdb010b638274f6 Mon Sep 17 00:00:00 2001 From: Till Theato Date: Mon, 3 Jan 2011 14:23:08 +0000 Subject: [PATCH] Bezier Spline: - allow moving a point beyond its neighbors - restore handles when moving a point close to one of its neighbors and then away again (all in one drag) - cleanup svn path=/trunk/kdenlive/; revision=5247 --- src/beziercurve/beziersplineeditor.cpp | 109 ++++++++++++------------- src/beziercurve/beziersplineeditor.h | 5 +- src/beziercurve/cubicbezierspline.cpp | 37 ++++----- src/beziercurve/cubicbezierspline.h | 1 + 4 files changed, 75 insertions(+), 77 deletions(-) diff --git a/src/beziercurve/beziersplineeditor.cpp b/src/beziercurve/beziersplineeditor.cpp index a5a5484c..99e46877 100644 --- a/src/beziercurve/beziersplineeditor.cpp +++ b/src/beziercurve/beziersplineeditor.cpp @@ -270,7 +270,6 @@ void BezierSplineEditor::mousePressEvent(QMouseEvent* event) po.h2 = QPointF(x+0.05, y+0.05); m_currentPointIndex = m_spline.addPoint(po); m_currentPointType = PTypeP; - /*if (!d->jumpOverExistingPoints(newPoint, -1)) return;*/ } else { m_currentPointIndex = closestPointIndex; m_currentPointType = selectedPoint; @@ -289,8 +288,11 @@ void BezierSplineEditor::mousePressEvent(QMouseEvent* event) p = point.h2; } - m_grabOriginalX = p.x(); - m_grabOriginalY = p.y(); + m_grabPOriginal = point; + if (m_currentPointIndex > 0) + m_grabPPrevious = m_spline.points()[m_currentPointIndex - 1]; + if (m_currentPointIndex < m_spline.points().count() - 1) + m_grabPNext = m_spline.points()[m_currentPointIndex + 1]; m_grabOffsetX = p.x() - x; m_grabOffsetY = p.y() - y; @@ -306,8 +308,6 @@ void BezierSplineEditor::mousePressEvent(QMouseEvent* event) } m_spline.setPoint(m_currentPointIndex, point); - //d->m_draggedAwayPointIndex = -1; - m_mode = ModeDrag; emit currentPoint(point); @@ -336,40 +336,24 @@ void BezierSplineEditor::mouseMoveEvent(QMouseEvent* event) double x = (event->pos().x() - offset) / (double)(wWidth); double y = 1.0 - (event->pos().y() - offset) / (double)(wHeight); - if (m_mode == ModeNormal) { // If no point is selected set the the cursor shape if on top + if (m_mode == ModeNormal) { + // If no point is selected set the the cursor shape if on top point_types type; int nearestPointIndex = nearestPointInRange(QPointF(x, y), wWidth, wHeight, &type); - + if (nearestPointIndex < 0) setCursor(Qt::ArrowCursor); else setCursor(Qt::CrossCursor); - } else { // Else, drag the selected point - /*bool crossedHoriz = event->pos().x() - width() > MOUSE_AWAY_THRES || - event->pos().x() < -MOUSE_AWAY_THRES; - bool crossedVert = event->pos().y() - height() > MOUSE_AWAY_THRES || - event->pos().y() < -MOUSE_AWAY_THRES; - - bool removePoint = (crossedHoriz || crossedVert); - - if (!removePoint && d->m_draggedAwayPointIndex >= 0) { - // point is no longer dragged away so reinsert it - QPointF newPoint(d->m_draggedAwayPoint); - d->m_grab_point_index = d->m_curve.addPoint(newPoint); - d->m_draggedAwayPointIndex = -1; - } - - if (removePoint && - (d->m_draggedAwayPointIndex >= 0)) - return; - */ - + } else { + // Else, drag the selected point setCursor(Qt::CrossCursor); x += m_grabOffsetX; y += m_grabOffsetY; - - double leftX, rightX; + + double leftX = 0.; + double rightX = 1.; BPoint point = m_spline.points()[m_currentPointIndex]; switch (m_currentPointType) { case PTypeH1: @@ -378,54 +362,68 @@ void BezierSplineEditor::mouseMoveEvent(QMouseEvent* event) leftX = -1000; else leftX = m_spline.points()[m_currentPointIndex - 1].p.x(); + x = qBound(leftX, x, rightX); point.h1 = QPointF(x, y); break; + case PTypeP: - if (m_currentPointIndex == 0) { - leftX = 0.0; + if (m_currentPointIndex == 0) rightX = 0.0; - /*if (d->m_curve.points().count() > 1) - * rightX = d->m_curve.points()[d->m_grab_point_index + 1].x() - POINT_AREA; - * else - * rightX = 1.0;*/ - } else if (m_currentPointIndex == m_spline.points().count() - 1) { - leftX = 1.0;//m_spline.points()[m_currentPointIndex - 1].p.x(); - rightX = 1.0; - } else { - //// the 1E-4 addition so we can grab the dot later. - leftX = m_spline.points()[m_currentPointIndex - 1].p.x();// + POINT_AREA; - rightX = m_spline.points()[m_currentPointIndex + 1].p.x();// - POINT_AREA; - } + else if (m_currentPointIndex == m_spline.points().count() - 1) + leftX = 1.0; + x = qBound(leftX, x, rightX); y = qBound(0., y, 1.); - // move handles by same offset - point.h1 += QPointF(x, y) - point.p; - point.h2 += QPointF(x, y) - point.p; + // handles might have changed because we neared another point + // try to restore + point.h1 = m_grabPOriginal.h1; + point.h2 = m_grabPOriginal.h2; + // and then move them by same offset + point.h1 += QPointF(x, y) - m_grabPOriginal.p; + point.h2 += QPointF(x, y) - m_grabPOriginal.p; point.p = QPointF(x, y); break; + case PTypeH2: leftX = point.p.x(); if (m_currentPointIndex == m_spline.points().count() - 1) rightX = 1001; else rightX = m_spline.points()[m_currentPointIndex + 1].p.x(); + x = qBound(leftX, x, rightX); point.h2 = QPointF(x, y); }; - m_spline.setPoint(m_currentPointIndex, point); - - /*if (removePoint && d->m_curve.points().count() > 2) { - d->m_draggedAwayPoint = d->m_curve.points()[d->m_grab_point_index]; - d->m_draggedAwayPointIndex = d->m_grab_point_index; - d->m_curve.removePoint(d->m_grab_point_index); - d->m_grab_point_index = bounds(d->m_grab_point_index, 0, d->m_curve.points().count() - 1); + int index = m_currentPointIndex; + m_currentPointIndex = m_spline.setPoint(m_currentPointIndex, point); + + if (m_currentPointType == PTypeP) { + // we might have changed the handles of other points + // try to restore + if (index == m_currentPointIndex) { + if (m_currentPointIndex > 0) + m_spline.setPoint(m_currentPointIndex - 1, m_grabPPrevious); + if (m_currentPointIndex < m_spline.points().count() -1) + m_spline.setPoint(m_currentPointIndex + 1, m_grabPNext); + } else { + if (m_currentPointIndex < index) { + m_spline.setPoint(index, m_grabPPrevious); + m_grabPNext = m_grabPPrevious; + if (m_currentPointIndex > 0) + m_grabPPrevious = m_spline.points()[m_currentPointIndex - 1]; + } else { + m_spline.setPoint(index, m_grabPNext); + m_grabPPrevious = m_grabPNext; + if (m_currentPointIndex < m_spline.points().count() - 1) + m_grabPNext = m_spline.points()[m_currentPointIndex + 1]; + } + } } - - d->setCurveModified();*/ + emit currentPoint(point); update(); } @@ -444,6 +442,7 @@ int BezierSplineEditor::nearestPointInRange(QPointF p, int wWidth, int wHeight, int i = 0; double distanceSquared; + // find out distance using the Pythagorean theorem foreach(const BPoint & point, m_spline.points()) { distanceSquared = pow(point.h1.x() - p.x(), 2) + pow(point.h1.y() - p.y(), 2); if (distanceSquared < nearestDistanceSquared) { diff --git a/src/beziercurve/beziersplineeditor.h b/src/beziercurve/beziersplineeditor.h index 604969ba..cccb47aa 100644 --- a/src/beziercurve/beziersplineeditor.h +++ b/src/beziercurve/beziersplineeditor.h @@ -71,8 +71,9 @@ private: point_types m_currentPointType; double m_grabOffsetX; double m_grabOffsetY; - double m_grabOriginalX; - double m_grabOriginalY; + BPoint m_grabPOriginal; + BPoint m_grabPNext; + BPoint m_grabPPrevious; //QPointF m_draggedAwayPoint; //int m_draggedAwayPointIndex; diff --git a/src/beziercurve/cubicbezierspline.cpp b/src/beziercurve/cubicbezierspline.cpp index b30f27a8..f188860d 100644 --- a/src/beziercurve/cubicbezierspline.cpp +++ b/src/beziercurve/cubicbezierspline.cpp @@ -20,6 +20,7 @@ #include +/** @brief For sorting a Bezier spline. Whether a is before b. */ static bool pointLessThan(const BPoint &a, const BPoint &b) { return a.p.x() < b.p.x(); @@ -108,7 +109,7 @@ int CubicBezierSpline::setPoint(int ix, const BPoint& point) keepSorted(); validatePoints(); m_validSpline = false; - return m_points.indexOf(point); // in case it changed + return indexOf(point); // in case it changed } QList CubicBezierSpline::points() @@ -128,16 +129,7 @@ int CubicBezierSpline::addPoint(const BPoint& point) keepSorted(); validatePoints(); m_validSpline = false; - if (m_points.indexOf(point) == -1) { - // point changed during validation process - for (int i = 0; i < m_points.count(); ++i) { - // this condition should be sufficient, too - if (m_points.at(i).p == point.p) - return i; - } - } else { - return m_points.indexOf(point); - } + return indexOf(point); } void CubicBezierSpline::setPrecision(int pre) @@ -157,9 +149,6 @@ qreal CubicBezierSpline::value(qreal x, bool cont) { update(); - //x = qBound(m_spline.constBegin().key(), x, m_spline.constEnd().key()); - //kDebug() << "....x" << x<<"bounddown"<::const_iterator i = m_spline.constBegin(); - kDebug()<<"////////////spline/////////////"; - while (i != m_spline.constEnd()) { - kDebug() << i.key() << i.value(); - ++i; +} + +int CubicBezierSpline::indexOf(const BPoint& p) +{ + if (m_points.indexOf(p) == -1) { + // point changed during validation process + for (int i = 0; i < m_points.count(); ++i) { + // this condition should be sufficient, too + if (m_points.at(i).p == p.p) + return i; + } + } else { + return m_points.indexOf(p); } - kDebug()<<"////////////spline/////////////end";*/ + return -1; } #include "cubicbezierspline.moc" diff --git a/src/beziercurve/cubicbezierspline.h b/src/beziercurve/cubicbezierspline.h index 4ddd0ce8..dc25fb90 100644 --- a/src/beziercurve/cubicbezierspline.h +++ b/src/beziercurve/cubicbezierspline.h @@ -59,6 +59,7 @@ private: void validatePoints(); void keepSorted(); void update(); + int indexOf(const BPoint &p); QList m_points; QMap m_spline; -- 2.39.2