diff options
author | Alan Alpert <alan.alpert@nokia.com> | 2011-08-02 11:26:24 +1000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2011-08-05 10:55:30 +0200 |
commit | 4334d07f52dfc1d7fce6ebbad6e9f377ef33dedb (patch) | |
tree | ca1e4d1db6318675e3851bdb130b1cd08940cb95 | |
parent | 1eea4773236a246cf6185f69374c27852905ff5e (diff) |
Use more numerically robust algorithm to compute QBezier::pointAt().
QBezier::pointAt() could potentially return values outside the bezier's
bounds, even when the bezier was a straight horizontal line. For
example, with y = 0.5, it would produce y=0.5 or y=0.49999999999999 for
different values of t, which when rounded cause jittering in a QML
PathView.
Task-number: QTBUG-17007
Task-number: QTBUG-18133
Cherry-pick-of: 8b66982ec7b4b5d2071931c288973dce73dc9875
Change-Id: I4ecac7b9085aaaaaaaaaaaaaaaaaaaaaa7d7b0bc
Reviewed-on: http://codereview.qt.nokia.com/2467
Reviewed-by: Samuel Rødal <samuel.rodal@nokia.com>
-rw-r--r-- | src/gui/painting/qbezier_p.h | 36 | ||||
-rw-r--r-- | tests/auto/qpainterpath/tst_qpainterpath.cpp | 21 |
2 files changed, 39 insertions, 18 deletions
diff --git a/src/gui/painting/qbezier_p.h b/src/gui/painting/qbezier_p.h index 399dd89140..f1f7eb155a 100644 --- a/src/gui/painting/qbezier_p.h +++ b/src/gui/painting/qbezier_p.h @@ -162,27 +162,27 @@ inline void QBezier::coefficients(qreal t, qreal &a, qreal &b, qreal &c, qreal & inline QPointF QBezier::pointAt(qreal t) const { -#if 1 - qreal a, b, c, d; - coefficients(t, a, b, c, d); - return QPointF(a*x1 + b*x2 + c*x3 + d*x4, a*y1 + b*y2 + c*y3 + d*y4); -#else // numerically more stable: + qreal x, y; + qreal m_t = 1. - t; - qreal a = x1*m_t + x2*t; - qreal b = x2*m_t + x3*t; - qreal c = x3*m_t + x4*t; - a = a*m_t + b*t; - b = b*m_t + c*t; - qreal x = a*m_t + b*t; - qreal a = y1*m_t + y2*t; - qreal b = y2*m_t + y3*t; - qreal c = y3*m_t + y4*t; - a = a*m_t + b*t; - b = b*m_t + c*t; - qreal y = a*m_t + b*t; + { + qreal a = x1*m_t + x2*t; + qreal b = x2*m_t + x3*t; + qreal c = x3*m_t + x4*t; + a = a*m_t + b*t; + b = b*m_t + c*t; + x = a*m_t + b*t; + } + { + qreal a = y1*m_t + y2*t; + qreal b = y2*m_t + y3*t; + qreal c = y3*m_t + y4*t; + a = a*m_t + b*t; + b = b*m_t + c*t; + y = a*m_t + b*t; + } return QPointF(x, y); -#endif } inline QPointF QBezier::normalVector(qreal t) const diff --git a/tests/auto/qpainterpath/tst_qpainterpath.cpp b/tests/auto/qpainterpath/tst_qpainterpath.cpp index 3941a11460..33315adc06 100644 --- a/tests/auto/qpainterpath/tst_qpainterpath.cpp +++ b/tests/auto/qpainterpath/tst_qpainterpath.cpp @@ -114,6 +114,8 @@ private slots: void connectPathMoveTo(); void translate(); + + void lineWithinBounds(); }; // Testing get/set functions @@ -1306,6 +1308,25 @@ void tst_QPainterPath::translate() QCOMPARE(complexPath.translated(-offset), untranslatedComplexPath); } + +void tst_QPainterPath::lineWithinBounds() +{ + const int iteration_count = 3; + volatile const qreal yVal = 0.5; + QPointF a(0.0, yVal); + QPointF b(1000.0, yVal); + QPointF c(2000.0, yVal); + QPointF d(3000.0, yVal); + QPainterPath path; + path.moveTo(QPointF(0, yVal)); + path.cubicTo(QPointF(1000.0, yVal), QPointF(2000.0, yVal), QPointF(3000.0, yVal)); + for(int i=0; i<=iteration_count; i++) { + qreal actual = path.pointAtPercent(qreal(i) / iteration_count).y(); + QVERIFY(actual == yVal); // don't use QCOMPARE, don't want fuzzy comparison + } +} + + QTEST_APPLESS_MAIN(tst_QPainterPath) #include "tst_qpainterpath.moc" |