From 95d034a14f78aaefd6990de180f715c8b4d510b1 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Thu, 26 Feb 2015 18:04:43 +0400 Subject: Introduce QQuaternion::fromDirection() ...which constructs a quaternion using specified forward and upward directions, so that the resulting Z axis "faces" a given forward direction. Change-Id: Ib77b8ab5c359a4880b0d946face87026acdc6f0b Reviewed-by: Paul Lemire Reviewed-by: Michael Krasnyk Reviewed-by: Lars Knoll --- .../gui/math3d/qquaternion/tst_qquaternion.cpp | 94 ++++++++++++++++++++++ 1 file changed, 94 insertions(+) (limited to 'tests') diff --git a/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp b/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp index 2c38e4c111..ec7af97f07 100644 --- a/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp +++ b/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp @@ -141,6 +141,9 @@ private slots: void rotationTo_data(); void rotationTo(); + void fromDirection_data(); + void fromDirection(); + void fromEulerAngles_data(); void fromEulerAngles(); @@ -989,6 +992,97 @@ void tst_QQuaternion::rotationTo() QVERIFY(myFuzzyCompare(vec2, from)); } +static QByteArray testnameForAxis(const QVector3D &axis) +{ + QByteArray testname; + if (axis == QVector3D()) { + testname = "null"; + } else { + if (axis.x()) { + testname += axis.x() < 0 ? "-" : "+"; + testname += "X"; + } + if (axis.y()) { + testname += axis.y() < 0 ? "-" : "+"; + testname += "Y"; + } + if (axis.z()) { + testname += axis.z() < 0 ? "-" : "+"; + testname += "Z"; + } + } + return testname; +} + +// Test quaternion convertion to and from orthonormal axes. +void tst_QQuaternion::fromDirection_data() +{ + QTest::addColumn("direction"); + QTest::addColumn("up"); + + QList orientations; + orientations << QQuaternion(); + for (int angle = 45; angle <= 360; angle += 45) { + orientations << QQuaternion::fromAxisAndAngle(QVector3D(1, 0, 0), angle) + << QQuaternion::fromAxisAndAngle(QVector3D(0, 1, 0), angle) + << QQuaternion::fromAxisAndAngle(QVector3D(0, 0, 1), angle) + << QQuaternion::fromAxisAndAngle(QVector3D(1, 0, 0), angle) + * QQuaternion::fromAxisAndAngle(QVector3D(0, 1, 0), angle) + * QQuaternion::fromAxisAndAngle(QVector3D(0, 0, 1), angle); + } + + // othonormal up and dir + foreach (const QQuaternion &q, orientations) { + QVector3D xAxis, yAxis, zAxis; + q.getAxes(&xAxis, &yAxis, &zAxis); + + QTest::newRow("dir: " + testnameForAxis(zAxis) + ", up: " + testnameForAxis(yAxis)) + << zAxis * 10.0f << yAxis * 10.0f; + } + + // collinear up and dir + QTest::newRow("dir: +X, up: +X") << QVector3D(10.0f, 0.0f, 0.0f) << QVector3D(10.0f, 0.0f, 0.0f); + QTest::newRow("dir: +X, up: -X") << QVector3D(10.0f, 0.0f, 0.0f) << QVector3D(-10.0f, 0.0f, 0.0f); + QTest::newRow("dir: +Y, up: +Y") << QVector3D(0.0f, 10.0f, 0.0f) << QVector3D(0.0f, 10.0f, 0.0f); + QTest::newRow("dir: +Y, up: -Y") << QVector3D(0.0f, 10.0f, 0.0f) << QVector3D(0.0f, -10.0f, 0.0f); + QTest::newRow("dir: +Z, up: +Z") << QVector3D(0.0f, 0.0f, 10.0f) << QVector3D(0.0f, 0.0f, 10.0f); + QTest::newRow("dir: +Z, up: -Z") << QVector3D(0.0f, 0.0f, 10.0f) << QVector3D(0.0f, 0.0f, -10.0f); + QTest::newRow("dir: +X+Y+Z, up: +X+Y+Z") << QVector3D(10.0f, 10.0f, 10.0f) << QVector3D(10.0f, 10.0f, 10.0f); + QTest::newRow("dir: +X+Y+Z, up: -X-Y-Z") << QVector3D(10.0f, 10.0f, 10.0f) << QVector3D(-10.0f, -10.0f, -10.0f); + + // invalid up + foreach (const QQuaternion &q, orientations) { + QVector3D xAxis, yAxis, zAxis; + q.getAxes(&xAxis, &yAxis, &zAxis); + + QTest::newRow("dir: " + testnameForAxis(zAxis) + ", up: null") + << zAxis * 10.0f << QVector3D(); + } +} +void tst_QQuaternion::fromDirection() +{ + QFETCH(QVector3D, direction); + QFETCH(QVector3D, up); + + QVector3D expextedZ(direction != QVector3D() ? direction.normalized() : QVector3D(0, 0, 1)); + QVector3D expextedY(up.normalized()); + + QQuaternion result = QQuaternion::fromDirection(direction, up); + QVERIFY(myFuzzyCompare(result, result.normalized())); + + QVector3D xAxis, yAxis, zAxis; + result.getAxes(&xAxis, &yAxis, &zAxis); + + QVERIFY(myFuzzyCompare(zAxis, expextedZ)); + + if (!qFuzzyIsNull(QVector3D::crossProduct(expextedZ, expextedY).lengthSquared())) { + QVector3D expextedX(QVector3D::crossProduct(expextedY, expextedZ)); + + QVERIFY(myFuzzyCompare(yAxis, expextedY)); + QVERIFY(myFuzzyCompare(xAxis, expextedX)); + } +} + // Test quaternion creation from an axis and an angle. void tst_QQuaternion::fromEulerAngles_data() { -- cgit v1.2.3