]> git.sesse.net Git - kdenlive/commitdiff
Use QPainterPath's cubicTo to draw cubic bezier spline
authorTill Theato <root@ttill.de>
Tue, 18 Jan 2011 20:53:58 +0000 (20:53 +0000)
committerTill Theato <root@ttill.de>
Tue, 18 Jan 2011 20:53:58 +0000 (20:53 +0000)
svn path=/trunk/kdenlive/; revision=5332

src/beziercurve/beziersplineeditor.cpp
src/beziercurve/bpoint.cpp
src/beziercurve/cubicbezierspline.cpp
src/beziercurve/cubicbezierspline.h

index 6316fbfb91c5830fdaf65d3747a778d19aed2982..4ef7ea12aba79e3d7d405105837a7435a8125519 100644 (file)
@@ -52,9 +52,7 @@ CubicBezierSpline BezierSplineEditor::spline()
 
 void BezierSplineEditor::setSpline(const CubicBezierSpline& spline)
 {
-    int precision = m_spline.getPrecision();
     m_spline = spline;
-    m_spline.setPrecision(precision);
     m_currentPointIndex = -1;
     m_mode = ModeNormal;
     emit currentPoint(BPoint());
@@ -125,6 +123,9 @@ void BezierSplineEditor::paintEvent(QPaintEvent* event)
 
     QPainter p(this);
 
+    /*
+     * Zoom
+     */
     int wWidth = width() - 1;
     int wHeight = height() - 1;
     int offset = 1/8. * m_zoomLevel * (wWidth > wHeight ? wWidth : wHeight);
@@ -180,38 +181,34 @@ void BezierSplineEditor::paintEvent(QPaintEvent* event)
      */
     p.drawLine(QLineF(0, wHeight, wWidth, 0));
 
+
+    /*
+     * Prepare Spline, Points
+     */
+    int max = m_spline.points().count() - 1;
+    if (max < 1)
+        return;
+    BPoint point(m_spline.getPoint(0, wWidth, wHeight, true));
+
     /*
      * Spline
      */
-    double prevY = wHeight - m_spline.value(0.) * wHeight;
-    double prevX = 0.;
-    double curY;
-    double normalizedX = -1;
-    int x;
+    BPoint next;
     
-    p.setPen(QPen(Qt::black, 1, Qt::SolidLine));
-    for (x = 0 ; x < wWidth ; ++x) {
-        normalizedX = x / (double)wWidth;
-        curY = wHeight - m_spline.value(normalizedX, true) * wHeight;
-
-        /*
-         * Keep in mind that QLineF rounds doubles
-         * to ints mathematically, not just rounds down
-         * like in C
-         */
-        p.drawLine(QLineF(prevX, prevY, x, curY));
-        prevX = x;
-        prevY = curY;
+    QPainterPath splinePath(QPointF(point.p.x(), point.p.y()));
+    for (int i = 0; i < max; ++i) {
+        point = m_spline.getPoint(i, wWidth, wHeight, true);
+        next = m_spline.getPoint(i + 1, wWidth, wHeight, true);
+        splinePath.cubicTo(point.h2, next.h1, next.p);
     }
-    p.drawLine(QLineF(prevX, prevY ,
-                      x, wHeight - m_spline.value(1.0, true) * wHeight));
+    p.setPen(QPen(Qt::black, 1, Qt::SolidLine));
+    p.drawPath(splinePath);
+
 
     /*
      * Points + Handles
      */
-    int max = m_spline.points().count() - 1;
     p.setPen(QPen(Qt::red, 1, Qt::SolidLine));
-    BPoint point;
 
     QPolygonF handle = QPolygonF() << QPointF(0, -3) << QPointF(3, 0) << QPointF(0, 3) << QPointF(-3, 0);
 #if QT_VERSION < 0x040600
@@ -219,34 +216,35 @@ void BezierSplineEditor::paintEvent(QPaintEvent* event)
 #endif
 
     for (int i = 0; i <= max; ++i) {
-        point = m_spline.points().at(i);
+        point = m_spline.getPoint(i, wWidth, wHeight, true);
+
         if (i == m_currentPointIndex) {
             // selected point: fill p and handles
             p.setBrush(QBrush(QColor(Qt::red), Qt::SolidPattern));
             // connect p and handles with lines
             if (i != 0)
-                p.drawLine(QLineF(point.h1.x() * wWidth, wHeight - point.h1.y() * wHeight, point.p.x() * wWidth, wHeight - point.p.y() * wHeight));
+                p.drawLine(QLineF(point.h1.x(), point.h1.y(), point.p.x(),point.p.y()));
             if (i != max)
-                p.drawLine(QLineF(point.p.x() * wWidth, wHeight - point.p.y() * wHeight, point.h2.x() * wWidth, wHeight - point.h2.y() * wHeight));
+                p.drawLine(QLineF(point.p.x(), point.p.y(), point.h2.x(), point.h2.y()));
         }
 
-        p.drawEllipse(QRectF(point.p.x() * wWidth - 3,
-                             wHeight - 3 - point.p.y() * wHeight, 6, 6));
+        p.drawEllipse(QRectF(point.p.x() - 3,
+                             point.p.y() - 3, 6, 6));
         if (i != 0 && (i == m_currentPointIndex || m_showAllHandles)) {
 #if QT_VERSION >= 0x040600
-            p.drawConvexPolygon(handle.translated(point.h1.x() * wWidth, wHeight - point.h1.y() * wHeight));
+            p.drawConvexPolygon(handle.translated(point.h1.x(), point.h1.y()));
 #else
             tmp = handle;
-            tmp.translate(point.h1.x() * wWidth, wHeight - point.h1.y() * wHeight);
+            tmp.translate(point.h1.x(), point.h1.y());
             p.drawConvexPolygon(tmp);
 #endif
         }
         if (i != max && (i == m_currentPointIndex || m_showAllHandles)) {
 #if QT_VERSION >= 0x040600
-            p.drawConvexPolygon(handle.translated(point.h2.x() * wWidth, wHeight - point.h2.y() * wHeight));
+            p.drawConvexPolygon(handle.translated(point.h2.x(), point.h2.y()));
 #else
             tmp = handle;
-            tmp.translate(point.h2.x() * wWidth, wHeight - point.h2.y() * wHeight);
+            tmp.translate(point.h2.x(), point.h2.y());
             p.drawConvexPolygon(tmp);
 #endif
         }
@@ -258,7 +256,6 @@ void BezierSplineEditor::paintEvent(QPaintEvent* event)
 
 void BezierSplineEditor::resizeEvent(QResizeEvent* event)
 {
-    m_spline.setPrecision(width() > height() ? width() : height());
     m_pixmapIsDirty = true;
     QWidget::resizeEvent(event);
 }
index 15bb911259be2bf0563f52e8b918326b4a06c572..e879e721f73f962ee2edf76b6441769ef26c0b25 100644 (file)
@@ -86,6 +86,8 @@ void BPoint::setH2(QPointF handle2)
 
 void BPoint::keepInRange(qreal xMin, qreal xMax)
 {
+    Q_UNUSED(xMin);
+    Q_UNUSED(xMax);
 }
 
 void BPoint::autoSetLinked()
index 9a2be6060c26c4ab3eb4b5639f4cc5f95238df5e..175aed213494107ef0414af18a36cf1ad8613201 100644 (file)
@@ -26,9 +26,7 @@ static bool pointLessThan(const BPoint &a, const BPoint &b)
 }
 
 CubicBezierSpline::CubicBezierSpline(QObject* parent) :
-        QObject(parent),
-        m_validSpline(false),
-        m_precision(100)
+        QObject(parent)
 {
     m_points.append(BPoint(QPointF(0, 0), QPointF(0, 0), QPointF(.1, .1)));
     m_points.append(BPoint(QPointF(.9, .9), QPointF(1, 1), QPointF(1, 1)));
@@ -37,23 +35,18 @@ CubicBezierSpline::CubicBezierSpline(QObject* parent) :
 CubicBezierSpline::CubicBezierSpline(const CubicBezierSpline& spline, QObject* parent) :
         QObject(parent)
 {
-    m_precision = spline.m_precision;
     m_points = spline.m_points;
-    m_validSpline = false;
 }
 
 CubicBezierSpline& CubicBezierSpline::operator=(const CubicBezierSpline& spline)
 {
-    m_precision = spline.m_precision;
     m_points = spline.m_points;
-    m_validSpline = false;
     return *this;
 }
 
 void CubicBezierSpline::fromString(const QString& spline)
 {
     m_points.clear();
-    m_validSpline = false;
 
     QStringList bpoints = spline.split('|');
     foreach(const QString &bpoint, bpoints) {
@@ -89,7 +82,6 @@ int CubicBezierSpline::setPoint(int ix, const BPoint& point)
     m_points[ix] = point;
     keepSorted();
     validatePoints();
-    m_validSpline = false;
     return indexOf(point); // in case it changed
 }
 
@@ -101,7 +93,6 @@ QList <BPoint> CubicBezierSpline::points()
 void CubicBezierSpline::removePoint(int ix)
 {
     m_points.removeAt(ix);
-    m_validSpline = false;
 }
 
 int CubicBezierSpline::addPoint(const BPoint& point)
@@ -109,43 +100,19 @@ int CubicBezierSpline::addPoint(const BPoint& point)
     m_points.append(point);
     keepSorted();
     validatePoints();
-    m_validSpline = false;
     return indexOf(point);
 }
 
-void CubicBezierSpline::setPrecision(int pre)
-{
-    if (pre != m_precision) {
-        m_precision = pre;
-        m_validSpline = false;
-    }
-}
-
-int CubicBezierSpline::getPrecision()
+BPoint CubicBezierSpline::getPoint(int ix, int normalisedWidth, int normalisedHeight, bool invertHeight)
 {
-    return m_precision;
-}
-
-qreal CubicBezierSpline::value(qreal x, bool cont)
-{
-    update();
-
-    if (!cont)
-        m_i = m_spline.constBegin();
-    if (m_i != m_spline.constBegin())
-        --m_i;
-
-    double diff = qAbs(x - m_i.key());
-    double y = m_i.value();
-    while (m_i != m_spline.constEnd()) {
-        if (qAbs(x - m_i.key()) > diff)
-            break;
-
-        diff = qAbs(x - m_i.key());
-        y = m_i.value();
-        ++m_i;
+    BPoint p = m_points.at(ix);
+    for (int i = 0; i < 3; ++i) {
+        p[i].rx() *= normalisedWidth;
+        p[i].ry() *= normalisedHeight;
+        if (invertHeight)
+            p[i].ry() = normalisedHeight - p[i].y();
     }
-    return qBound((qreal)0.0, y, (qreal)1.0);
+    return p;
 }
 
 void CubicBezierSpline::validatePoints()
@@ -166,52 +133,6 @@ void CubicBezierSpline::keepSorted()
     qSort(m_points.begin(), m_points.end(), pointLessThan);
 }
 
-QPointF CubicBezierSpline::point(double t, const QList< QPointF >& points)
-{
-    /*
-     * Calculating a point on the bezier curve using the coefficients from Bernstein basis polynomial of degree 3.
-     * Using the De Casteljau algorithm would be slightly faster for when calculating a lot of values
-     * but the difference is far from noticable in this needcase
-     */
-    double c1 = (1-t) * (1-t) * (1-t);
-    double c2 = 3 * t * (1-t) * (1-t);
-    double c3 = 3 * t * t * (1-t);
-    double c4 = t * t * t;
-    
-    return QPointF(points[0].x()*c1 + points[1].x()*c2 + points[2].x()*c3 + points[3].x()*c4,
-                   points[0].y()*c1 + points[1].y()*c2 + points[2].y()*c3 + points[3].y()*c4);
-}
-
-void CubicBezierSpline::update()
-{
-    if (m_validSpline)
-        return;
-
-    m_validSpline = true;
-    m_spline.clear();
-
-    QList <QPointF> points;
-    QPointF p;
-    for (int i = 0; i < m_points.count() - 1; ++i) {
-        points.clear();
-        points << m_points.at(i).p
-                << m_points.at(i).h2
-                << m_points.at(i+1).h1
-                << m_points.at(i+1).p;
-
-        int numberOfValues = (int)((points[3].x() - points[0].x()) * m_precision * 10);
-        if (numberOfValues == 0)
-            numberOfValues = 1;
-        double step = 1 / (double)numberOfValues;
-        double t = 0;
-        while (t <= 1) {
-            p = point(t, points);
-            m_spline.insert(p.x(), p.y());
-            t += step;
-        }
-    }
-}
-
 int CubicBezierSpline::indexOf(const BPoint& p)
 {
     if (m_points.indexOf(p) == -1) {
index d28b0ae8b878be7480ad74446a2cd237c56c96dc..ee21c987f5f7b9e58d116e03f8dfae433f05b210 100644 (file)
@@ -50,11 +50,6 @@ public:
 
     /** @brief Returns a list of the points defining the spline. */
     QList <BPoint> points();
-    /** @brief Finds the closest point in the pre-calculated spline to @param x.
-     * @param x x value
-     * @param cont (default = false) Whether to start searching at the previously requested x and skip all values before it.
-                                     This makes requesting a lot of increasing x's faster. */
-    qreal value(qreal x, bool cont = false);
 
     /** @brief Sets the point at index @param ix to @param point and returns its index (it might have changed during validation). */
     int setPoint(int ix, const BPoint &point);
@@ -63,28 +58,22 @@ public:
     /** @brief Removes the point at @param ix. */
     void removePoint(int ix);
 
-    /** @brief Sets the precision to @param pre.
-     *
-     * The precision influences the number of points that are calculated for the spline:
-     * number of values = precision * 10 */
-    void setPrecision(int pre);
-    int getPrecision();
+    /** @brief Returns the point at @param ix.
+     * @param ix Index of the point
+     * @param normalisedWidth (default = 1) Will be multiplied will all x values to change the range from 0-1 into another one
+     * @param normalisedHeight (default = 1) Will be multiplied will all y values to change the range from 0-1 into another one
+     * @param invertHeight (default = false) true => y = 0 is at the very top
+     */
+    BPoint getPoint(int ix, int normalisedWidth = 1, int normalisedHeight = 1, bool invertHeight = false);
+
+
 
 private:
-    QPointF point(double t, const QList<QPointF> &points);
     void validatePoints();
     void keepSorted();
-    void update();
     int indexOf(const BPoint &p);
 
     QList <BPoint> m_points;
-    /** x, y pairs */
-    QMap <double, double> m_spline;
-    /** iterator used when searching for a value in in continue mode (see @function value). */
-    QMap <double, double>::const_iterator m_i;
-    /** Whether the spline represents the points and the precision. */
-    bool m_validSpline;
-    int m_precision;
 };
 
 #endif