]> git.sesse.net Git - kdenlive/commitdiff
Bezier Spline:
authorTill Theato <root@ttill.de>
Mon, 3 Jan 2011 14:23:08 +0000 (14:23 +0000)
committerTill Theato <root@ttill.de>
Mon, 3 Jan 2011 14:23:08 +0000 (14:23 +0000)
- 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
src/beziercurve/beziersplineeditor.h
src/beziercurve/cubicbezierspline.cpp
src/beziercurve/cubicbezierspline.h

index a5a5484c18d5695b583701d8a55ec5337fc61483..99e468779fd2a2629be30a6ba003fc66ecf3c8ad 100644 (file)
@@ -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) {
index 604969ba28ba5bfa383677bde1412d6a17a56e5f..cccb47aa91f18f3a485b3b08a5e3fc0379a947e2 100644 (file)
@@ -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;
 
index b30f27a8230bda5034830d1f007af1b4de1bcc4f..f188860db8098da3cfa296cb07038fcad77b5d03 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <KDebug>
 
+/** @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 <BPoint> 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"<<m_spline.constBegin().key()<<"up"<<m_spline.constEnd().key();
-
     if (!cont)
         m_i = m_spline.constBegin();
     if (m_i != m_spline.constBegin())
@@ -236,13 +225,21 @@ void CubicBezierSpline::update()
             t += step;
         }
     }
-    /*QMap<double, double>::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"
index 4ddd0ce807869001d5d386504e57a4e9bc72b2ea..dc25fb90d6afb779093c181a96178ce3529dcbae 100644 (file)
@@ -59,6 +59,7 @@ private:
     void validatePoints();
     void keepSorted();
     void update();
+    int indexOf(const BPoint &p);
 
     QList <BPoint> m_points;
     QMap <double, double> m_spline;