summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp
diff options
context:
space:
mode:
authorThomas Hartmann <Thomas.Hartmann@nokia.com>2011-11-10 12:09:29 +0100
committerQt by Nokia <qt-info@nokia.com>2011-11-11 09:16:47 +0100
commitebfe3a4217c8b9c040faeb77906dfe9ccdfd5408 (patch)
tree099cd622f2d60d5dd49af0da421713e3fe4ae193 /tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp
parente82b120410820e978b87b0a0f3b99718f3671fb1 (diff)
Adding test for custom bezier easing curves
I added unit tests _fast_cbrt() taken from qeasingcurve.cpp Change-Id: Id3afd26efac92f594d6358dc2e11f94e8c524da2 Reviewed-by: Joerg Bornemann <joerg.bornemann@nokia.com>
Diffstat (limited to 'tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp')
-rw-r--r--tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp222
1 files changed, 222 insertions, 0 deletions
diff --git a/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp b/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp
index 107f9769b1..41590f1875 100644
--- a/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp
+++ b/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp
@@ -58,6 +58,12 @@ private slots:
void operators();
void properties();
void metaTypes();
+ void bezierSpline_data();
+ void bezierSpline();
+ void tcbSpline_data();
+ void tcbSpline();
+ void testCbrtDouble();
+ void testCbrtFloat();
};
void tst_QEasingCurve::type()
@@ -544,5 +550,221 @@ void tst_QEasingCurve::metaTypes()
QVERIFY(qMetaTypeId<QEasingCurve>() == QMetaType::QEasingCurve);
}
+void tst_QEasingCurve::bezierSpline_data()
+{
+ QTest::addColumn<QString>("definition");
+ QTest::addColumn<IntList>("at");
+ QTest::addColumn<RealList>("expected");
+
+ QTest::newRow("EasingCurve") << QString::fromLatin1("0.2,0 0.6,0.09 0.7,1.0 0.7,0.97 0.74,0.96 0.74,0.95 0.81,0.97 0.9,0.97 1,1")
+ << (IntList() << 0 << 70 << 74 << 100)
+ << (RealList() << 0.0000 << 1.0000 << 0.9500 << 1.0000);
+
+ //This curve is likely to be numerical instable
+ QTest::newRow("NastyCurve") << QString::fromLatin1("0.2,0.2 0.126667,0.646667 0.2,0.8 0.624,0.984 0.930667,0.946667 1,1")
+ << (IntList() << 0 << 20 << 30 << 50 << 75 << 100)
+ << (RealList() << 0.0000 << 0.8000 << 0.8402 << 0.9029 << 0.9515 << 1.0000);
+
+ QTest::newRow("ComplexCurve") << QString::fromLatin1("0,0.47174849 0.17393079,0.35634291 0.18950309,0.47179766 0.2487779,0.91126755 "
+ "0.27029205,-0.11275513 0.33421971,0.12062718 0.41170105,-0.10157488 0.4140625,0.16796875 "
+ "0.4140625,0.16796875 0.4140625,0.16796875 0.59658877,0.36978503 0.67931151,0.89255893 0.711253,0.44658283 "
+ "0.88203125,0.43671875 0.88203125,0.43671875 0.86087213,0.78786873 0.99609375,0.4921875 1,1")
+ << (IntList() << 0 << 15 << 20 << 30 << 40 << 70 << 50 << 80 << 100)
+ << (RealList() << 0.0000 << 0.4134 << 0.5367 << 0.1107 << 0.0505 << 0.7299 << 0.3030 << 0.4886 << 1.0000);
+}
+
+static inline void setupBezierSpline(QEasingCurve *easingCurve, const QString &string)
+{
+ QStringList pointStr = string.split(QLatin1Char(' '));
+
+ QVector<QPointF> points;
+ foreach (const QString &str, pointStr) {
+ QStringList coordStr = str.split(QLatin1Char(','));
+ QPointF point(coordStr.first().toDouble(), coordStr.last().toDouble());
+ points.append(point);
+ }
+
+ QVERIFY(points.count() % 3 == 0);
+
+ for (int i = 0; i < points.count() / 3; i++) {
+ QPointF c1 = points.at(i * 3);
+ QPointF c2 = points.at(i * 3 + 1);
+ QPointF p1 = points.at(i * 3 + 2);
+ easingCurve->addCubicBezierSegment(c1, c2, p1);
+ }
+}
+
+void tst_QEasingCurve::bezierSpline()
+{
+ QFETCH(QString, definition);
+ QFETCH(IntList, at);
+ QFETCH(RealList, expected);
+
+ QEasingCurve bezierEasingCurve(QEasingCurve::BezierSpline);
+ setupBezierSpline(&bezierEasingCurve, definition);
+
+ const qreal errorBound = 0.002;
+ for (int i = 0; i < at.count(); ++i) {
+ const qreal ex = expected.at(i);
+ const qreal value = bezierEasingCurve.valueForProgress(at.at(i)/qreal(100));
+ const qreal error = qAbs(ex - value);
+ if (error > errorBound)
+ QCOMPARE(value, ex);
+ QVERIFY(error <= errorBound);
+ }
+}
+
+void tst_QEasingCurve::tcbSpline_data()
+{
+ QTest::addColumn<QString>("definition");
+ QTest::addColumn<IntList>("at");
+ QTest::addColumn<RealList>("expected");
+
+ QTest::newRow("NegativeCurved") << QString::fromLatin1("0.0,0.0,0,0,0 0.4,0.8,0.0,1,0.0 1.0,1.0,0.0,0.0,0")
+ << (IntList() << 0 << 66 << 73 << 100)
+ << (RealList() << 0.0000 << 0.9736 << 0.9774 << 1.0000);
+
+ //This curve is likely to be numerical instable
+ QTest::newRow("Corner") << QString::fromLatin1("0.0,0.0,0,0,0 0.4,0.8,0.0,-1,0.0 1.0,1.0,0.0,0.0,0")
+ << (IntList() << 0 << 20 << 30 << 50 << 75 << 100)
+ << (RealList() << 0.0000 << 0.3999 << 0.5996 << 0.8334 << 0.9166 << 1.0000);
+
+ QTest::newRow("RoundCurve") << QString::fromLatin1("0.0,0.0,0,0,0 0.4,0.8,0.0,0,0.0 1.0,1.0,0.0,0.0,0")
+ << (IntList() << 0 << 15 << 20 << 30 << 40 << 70 << 50 << 80 << 100)
+ << (RealList() << 0.0000 << 0.3478 << 0.4663 << 0.6664 << 0.8000 << 0.9399 << 0.8746 << 0.9567 << 1.0000);
+
+ QTest::newRow("Bias") << QString::fromLatin1("0.0,0.0,0,0,0 0.4,0.8,0.1,0,1.0 1.0,1.0,0.0,0.0,0")
+ << (IntList() << 0 << 15 << 20 << 30 << 40 << 70 << 50 << 80 << 100)
+ << (RealList() << 0.0000 << 0.2999 << 0.3998 << 0.5997 << 0.8000 << 0.9676 << 0.9136 << 0.9725 << 1.0000);
+}
+
+static inline void setupTCBSpline(QEasingCurve *easingCurve, const QString &string)
+{
+ QStringList pointStr = string.split(QLatin1Char(' '));
+
+ foreach (const QString &str, pointStr) {
+ QStringList coordStr = str.split(QLatin1Char(','));
+ Q_ASSERT(coordStr.count() == 5);
+ QPointF point(coordStr.first().toDouble(), coordStr.at(1).toDouble());
+ qreal t = coordStr.at(2).toDouble();
+ qreal c = coordStr.at(3).toDouble();
+ qreal b = coordStr.at(4).toDouble();
+ easingCurve->addTCBSegment(point, t, c ,b);
+ }
+}
+
+void tst_QEasingCurve::tcbSpline()
+{
+ QFETCH(QString, definition);
+ QFETCH(IntList, at);
+ QFETCH(RealList, expected);
+
+ QEasingCurve tcbEasingCurve(QEasingCurve::TCBSpline);
+ setupTCBSpline(&tcbEasingCurve, definition);
+
+ const qreal errorBound = 0.002;
+ for (int i = 0; i < at.count(); ++i) {
+ const qreal ex = expected.at(i);
+ const qreal value = tcbEasingCurve.valueForProgress(at.at(i)/qreal(100));
+ const qreal error = qAbs(ex - value);
+ if (error > errorBound)
+ QCOMPARE(value, ex);
+ QVERIFY(error <= errorBound);
+ }
+}
+
+/*This is single precision code for a cubic root used inside the spline easing curve.
+ This code is tested here explicitly. See: qeasingcurve.cpp */
+
+float static inline _fast_cbrt(float x)
+{
+ union {
+ float f;
+ quint32 i;
+ } ux;
+
+ const unsigned int B1 = 709921077;
+
+ ux.f = x;
+ ux.i = (ux.i / 3 + B1);
+
+ return ux.f;
+}
+
+/*This is double precision code for a cubic root used inside the spline easing curve.
+ This code is tested here explicitly. See: qeasingcurve.cpp */
+
+double static inline _fast_cbrt(double d)
+{
+ union {
+ double d;
+ quint32 pt[2];
+ } ut, ux;
+
+ const unsigned int B1 = 715094163;
+
+
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ const int h0 = 1;
+#else
+ const int h0 = 0;
+#endif
+ ut.d = 0.0;
+ ux.d = d;
+
+ quint32 hx = ux.pt[h0]; //high word of d
+ ut.pt[h0] = hx/3 + B1;
+
+ return ut.d;
+}
+
+void tst_QEasingCurve::testCbrtDouble()
+{
+ const qreal errorBound = 0.0001;
+
+ for (int i = 0; i < 100000; i++) {
+ double d = double(i) / 1000.0;
+ double t = _fast_cbrt(d);
+
+ const double t_cubic = t * t * t;
+ t = t * (t_cubic + d + d) / (t_cubic + t_cubic + d);
+
+ double expected = pow(d, 1.0/3.0);
+
+ const qreal error = qAbs(expected - t);
+
+ if (!(error < errorBound)) {
+ qWarning() << d;
+ qWarning() << error;
+ }
+
+ QVERIFY(error < errorBound);
+ }
+}
+
+void tst_QEasingCurve::testCbrtFloat()
+{
+ const qreal errorBound = 0.0005;
+
+ for (int i = 1; i < 100000; i++) {
+ float f = float(i) / 1000.0f;
+ float t = _fast_cbrt(f);
+
+ const float t_cubic = t * t * t;
+ t = t * (t_cubic + f + f) / (t_cubic + t_cubic + f);
+
+ float expected = pow(f, 1.0/3.0);
+
+ const qreal error = qAbs(expected - t);
+
+ if (!(error < errorBound)) {
+ qWarning() << f;
+ qWarning() << error;
+ }
+
+ QVERIFY(error < errorBound);
+ }
+}
+
QTEST_MAIN(tst_QEasingCurve)
#include "tst_qeasingcurve.moc"