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>
This commit is contained in:
parent
1eea477323
commit
4334d07f52
@ -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
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user