summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/math3d/qquaternion.cpp50
-rw-r--r--src/gui/math3d/qquaternion.h9
-rw-r--r--tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp20
3 files changed, 79 insertions, 0 deletions
diff --git a/src/gui/math3d/qquaternion.cpp b/src/gui/math3d/qquaternion.cpp
index 8e59e8a2f1..9c8fa3310d 100644
--- a/src/gui/math3d/qquaternion.cpp
+++ b/src/gui/math3d/qquaternion.cpp
@@ -363,8 +363,21 @@ QVector3D QQuaternion::rotatedVector(const QVector3D& vector) const
#ifndef QT_NO_VECTOR3D
/*!
+ \fn void QQuaternion::toAxisAndAngle(QVector3D *axis, float *angle) const
+ \since 5.5
+ \overload
+
+ Extracts a 3D axis \a axis and a rotating angle \a angle (in degrees)
+ that corresponds to this quaternion.
+
+ \sa fromAxisAndAngle()
+*/
+
+/*!
Creates a normalized quaternion that corresponds to rotating through
\a angle degrees about the specified 3D \a axis.
+
+ \sa toAxisAndAngle()
*/
QQuaternion QQuaternion::fromAxisAndAngle(const QVector3D& axis, float angle)
{
@@ -382,8 +395,45 @@ QQuaternion QQuaternion::fromAxisAndAngle(const QVector3D& axis, float angle)
#endif
/*!
+ \since 5.5
+
+ Extracts a 3D axis (\a x, \a y, \a z) and a rotating angle \a angle (in degrees)
+ that corresponds to this quaternion.
+
+ \sa fromAxisAndAngle()
+*/
+void QQuaternion::toAxisAndAngle(float *x, float *y, float *z, float *angle) const
+{
+ Q_ASSERT(x && y && z && angle);
+
+ // The quaternion representing the rotation is
+ // q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)
+
+ float length = xp * xp + yp * yp + zp * zp;
+ if (!qFuzzyIsNull(length)) {
+ *x = xp;
+ *y = yp;
+ *z = zp;
+ if (!qFuzzyIsNull(length - 1.0f)) {
+ length = sqrtf(length);
+ *x /= length;
+ *y /= length;
+ *z /= length;
+ }
+ *angle = 2.0f * acosf(wp);
+ } else {
+ // angle is 0 (mod 2*pi), so any axis will fit
+ *x = *y = *z = *angle = 0.0f;
+ }
+
+ *angle = qRadiansToDegrees(*angle);
+}
+
+/*!
Creates a normalized quaternion that corresponds to rotating through
\a angle degrees about the 3D axis (\a x, \a y, \a z).
+
+ \sa toAxisAndAngle()
*/
QQuaternion QQuaternion::fromAxisAndAngle
(float x, float y, float z, float angle)
diff --git a/src/gui/math3d/qquaternion.h b/src/gui/math3d/qquaternion.h
index d4ad3df597..eb835ef806 100644
--- a/src/gui/math3d/qquaternion.h
+++ b/src/gui/math3d/qquaternion.h
@@ -115,8 +115,10 @@ public:
operator QVariant() const;
#ifndef QT_NO_VECTOR3D
+ inline void toAxisAndAngle(QVector3D *axis, float *angle) const;
static QQuaternion fromAxisAndAngle(const QVector3D& axis, float angle);
#endif
+ void toAxisAndAngle(float *x, float *y, float *z, float *angle) const;
static QQuaternion fromAxisAndAngle
(float x, float y, float z, float angle);
@@ -299,6 +301,13 @@ inline QVector3D QQuaternion::vector() const
return QVector3D(xp, yp, zp);
}
+inline void QQuaternion::toAxisAndAngle(QVector3D *axis, float *angle) const
+{
+ float aX, aY, aZ;
+ toAxisAndAngle(&aX, &aY, &aZ, angle);
+ *axis = QVector3D(aX, aY, aZ);
+}
+
#endif
inline void QQuaternion::setVector(float aX, float aY, float aZ)
diff --git a/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp b/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp
index f1e91da372..59dcd7a015 100644
--- a/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp
+++ b/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp
@@ -721,11 +721,31 @@ void tst_QQuaternion::fromAxisAndAngle()
QVERIFY(qFuzzyCompare(answer.z(), result.z()));
QVERIFY(qFuzzyCompare(answer.scalar(), result.scalar()));
+ {
+ QVector3D answerAxis;
+ float answerAngle;
+ answer.toAxisAndAngle(&answerAxis, &answerAngle);
+ QVERIFY(qFuzzyCompare(answerAxis.x(), vector.x()));
+ QVERIFY(qFuzzyCompare(answerAxis.y(), vector.y()));
+ QVERIFY(qFuzzyCompare(answerAxis.z(), vector.z()));
+ QVERIFY(qFuzzyCompare(answerAngle, angle));
+ }
+
answer = QQuaternion::fromAxisAndAngle(x1, y1, z1, angle);
QVERIFY(qFuzzyCompare(answer.x(), result.x()));
QVERIFY(qFuzzyCompare(answer.y(), result.y()));
QVERIFY(qFuzzyCompare(answer.z(), result.z()));
QVERIFY(qFuzzyCompare(answer.scalar(), result.scalar()));
+
+ {
+ float answerAxisX, answerAxisY, answerAxisZ;
+ float answerAngle;
+ answer.toAxisAndAngle(&answerAxisX, &answerAxisY, &answerAxisZ, &answerAngle);
+ QVERIFY(qFuzzyCompare(answerAxisX, vector.x()));
+ QVERIFY(qFuzzyCompare(answerAxisY, vector.y()));
+ QVERIFY(qFuzzyCompare(answerAxisZ, vector.z()));
+ QVERIFY(qFuzzyCompare(answerAngle, angle));
+ }
}
// Test quaternion convertion to and from rotation matrix.