diff options
-rw-r--r-- | src/gui/math3d/qquaternion.cpp | 50 | ||||
-rw-r--r-- | src/gui/math3d/qquaternion.h | 9 | ||||
-rw-r--r-- | tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp | 20 |
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. |