Browse Source

Math: using Rad for Quaternion and DualQuaternion functions.

pull/7/head
Vladimír Vondruš 13 years ago
parent
commit
c293630c7c
  1. 6
      src/Math/DualQuaternion.h
  2. 20
      src/Math/Quaternion.h
  3. 39
      src/Math/Test/DualQuaternionTest.cpp
  4. 48
      src/Math/Test/QuaternionTest.cpp

6
src/Math/DualQuaternion.h

@ -46,9 +46,9 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @f] * @f]
* @see rotationAngle(), rotationAxis(), Quaternion::rotation(), * @see rotationAngle(), rotationAxis(), Quaternion::rotation(),
* Matrix4::rotation(), Vector3::xAxis(), Vector3::yAxis(), * Matrix4::rotation(), Vector3::xAxis(), Vector3::yAxis(),
* Vector3::zAxis(), deg(), rad() * Vector3::zAxis()
*/ */
inline static DualQuaternion<T> rotation(T angle, const Vector3<T>& normalizedAxis) { inline static DualQuaternion<T> rotation(Rad<T> angle, const Vector3<T>& normalizedAxis) {
return {Quaternion<T>::rotation(angle, normalizedAxis), {{}, T(0)}}; return {Quaternion<T>::rotation(angle, normalizedAxis), {{}, T(0)}};
} }
@ -112,7 +112,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @f] * @f]
* @see rotationAxis(), rotation(), Quaternion::rotationAngle() * @see rotationAxis(), rotation(), Quaternion::rotationAngle()
*/ */
inline T rotationAngle() const { inline Math::Rad<T> rotationAngle() const {
return this->real().rotationAngle(); return this->real().rotationAngle();
} }

20
src/Math/Quaternion.h

@ -55,16 +55,16 @@ template<class T> class Quaternion {
} }
/** /**
* @brief Angle between normalized quaternions (in radians) * @brief Angle between normalized quaternions
* *
* Expects that both quaternions are normalized. @f[ * Expects that both quaternions are normalized. @f[
* \theta = acos \left( \frac{p \cdot q}{|p| \cdot |q|} \right) * \theta = acos \left( \frac{p \cdot q}{|p| \cdot |q|} \right)
* @f] * @f]
*/ */
inline static T angle(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB) { inline static Rad<T> angle(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB) {
CORRADE_ASSERT(MathTypeTraits<T>::equals(normalizedA.dot(), T(1)) && MathTypeTraits<T>::equals(normalizedB.dot(), T(1)), CORRADE_ASSERT(MathTypeTraits<T>::equals(normalizedA.dot(), T(1)) && MathTypeTraits<T>::equals(normalizedB.dot(), T(1)),
"Math::Quaternion::angle(): quaternions must be normalized", std::numeric_limits<T>::quiet_NaN()); "Math::Quaternion::angle(): quaternions must be normalized", Rad<T>(std::numeric_limits<T>::quiet_NaN()));
return angleInternal(normalizedA, normalizedB); return Rad<T>(angleInternal(normalizedA, normalizedB));
} }
/** /**
@ -116,13 +116,13 @@ template<class T> class Quaternion {
* @f] * @f]
* @see rotationAngle(), rotationAxis(), DualQuaternion::rotation(), * @see rotationAngle(), rotationAxis(), DualQuaternion::rotation(),
* Matrix4::rotation(), Vector3::xAxis(), Vector3::yAxis(), * Matrix4::rotation(), Vector3::xAxis(), Vector3::yAxis(),
* Vector3::zAxis(), deg(), rad() * Vector3::zAxis()
*/ */
inline static Quaternion<T> rotation(T angle, const Vector3<T>& normalizedAxis) { inline static Quaternion<T> rotation(Rad<T> angle, const Vector3<T>& normalizedAxis) {
CORRADE_ASSERT(MathTypeTraits<T>::equals(normalizedAxis.dot(), T(1)), CORRADE_ASSERT(MathTypeTraits<T>::equals(normalizedAxis.dot(), T(1)),
"Math::Quaternion::rotation(): axis must be normalized", {}); "Math::Quaternion::rotation(): axis must be normalized", {});
return {normalizedAxis*std::sin(angle/2), std::cos(angle/2)}; return {normalizedAxis*std::sin(T(angle)/2), std::cos(T(angle)/2)};
} }
/** /**
@ -177,11 +177,11 @@ template<class T> class Quaternion {
* @f] * @f]
* @see rotationAxis(), rotation() * @see rotationAxis(), rotation()
*/ */
inline T rotationAngle() const { inline Rad<T> rotationAngle() const {
CORRADE_ASSERT(MathTypeTraits<T>::equals(dot(), T(1)), CORRADE_ASSERT(MathTypeTraits<T>::equals(dot(), T(1)),
"Math::Quaternion::rotationAngle(): quaternion must be normalized", "Math::Quaternion::rotationAngle(): quaternion must be normalized",
std::numeric_limits<T>::quiet_NaN()); Rad<T>(std::numeric_limits<T>::quiet_NaN()));
return T(2)*std::acos(_scalar); return Rad<T>(T(2)*std::acos(_scalar));
} }
/** /**

39
src/Math/Test/DualQuaternionTest.cpp

@ -50,6 +50,8 @@ class DualQuaternionTest: public Corrade::TestSuite::Tester {
void debug(); void debug();
}; };
typedef Math::Deg<float> Deg;
typedef Math::Rad<float> Rad;
typedef Math::Dual<float> Dual; typedef Math::Dual<float> Dual;
typedef Math::Matrix4<float> Matrix4; typedef Math::Matrix4<float> Matrix4;
typedef Math::DualQuaternion<float> DualQuaternion; typedef Math::DualQuaternion<float> DualQuaternion;
@ -169,15 +171,14 @@ void DualQuaternionTest::rotation() {
std::ostringstream o; std::ostringstream o;
Error::setOutput(&o); Error::setOutput(&o);
float angle = deg(120.0f);
Vector3 axis(1.0f/Constants<float>::sqrt3()); Vector3 axis(1.0f/Constants<float>::sqrt3());
CORRADE_COMPARE(DualQuaternion::rotation(angle, axis*2.0f), DualQuaternion()); CORRADE_COMPARE(DualQuaternion::rotation(Deg(120.0f), axis*2.0f), DualQuaternion());
CORRADE_COMPARE(o.str(), "Math::Quaternion::rotation(): axis must be normalized\n"); CORRADE_COMPARE(o.str(), "Math::Quaternion::rotation(): axis must be normalized\n");
DualQuaternion q = DualQuaternion::rotation(angle, axis); DualQuaternion q = DualQuaternion::rotation(Deg(120.0f), axis);
CORRADE_COMPARE(q, DualQuaternion({Vector3(0.5f, 0.5f, 0.5f), 0.5f}, {{}, 0.0f})); CORRADE_COMPARE(q, DualQuaternion({Vector3(0.5f, 0.5f, 0.5f), 0.5f}, {{}, 0.0f}));
CORRADE_COMPARE(q.rotationAngle(), angle); CORRADE_COMPARE_AS(q.rotationAngle(), Deg(120.0f), Deg);
CORRADE_COMPARE(q.rotationAxis(), axis); CORRADE_COMPARE(q.rotationAxis(), axis);
} }
@ -190,21 +191,21 @@ void DualQuaternionTest::translation() {
void DualQuaternionTest::combinedTransformParts() { void DualQuaternionTest::combinedTransformParts() {
Vector3 translation = Vector3(-1.0f, 2.0f, 3.0f); Vector3 translation = Vector3(-1.0f, 2.0f, 3.0f);
DualQuaternion a = DualQuaternion::translation(translation)*DualQuaternion::rotation(deg(23.0f), Vector3::xAxis()); DualQuaternion a = DualQuaternion::translation(translation)*DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis());
DualQuaternion b = DualQuaternion::rotation(deg(23.0f), Vector3::xAxis())*DualQuaternion::translation(translation); DualQuaternion b = DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis())*DualQuaternion::translation(translation);
CORRADE_COMPARE(a.rotationAxis(), Vector3::xAxis()); CORRADE_COMPARE(a.rotationAxis(), Vector3::xAxis());
CORRADE_COMPARE(b.rotationAxis(), Vector3::xAxis()); CORRADE_COMPARE(b.rotationAxis(), Vector3::xAxis());
CORRADE_COMPARE(a.rotationAngle(), deg(23.0f)); CORRADE_COMPARE_AS(a.rotationAngle(), Deg(23.0f), Rad);
CORRADE_COMPARE(b.rotationAngle(), deg(23.0f)); CORRADE_COMPARE_AS(b.rotationAngle(), Deg(23.0f), Rad);
CORRADE_COMPARE(a.translation(), translation); CORRADE_COMPARE(a.translation(), translation);
CORRADE_COMPARE(b.translation(), Quaternion::rotation(deg(23.0f), Vector3::xAxis()).rotateVectorNormalized(translation)); CORRADE_COMPARE(b.translation(), Quaternion::rotation(Deg(23.0f), Vector3::xAxis()).rotateVectorNormalized(translation));
} }
void DualQuaternionTest::matrix() { void DualQuaternionTest::matrix() {
DualQuaternion q = DualQuaternion::rotation(deg(23.0f), Vector3::xAxis())*DualQuaternion::translation({-1.0f, 2.0f, 3.0f}); DualQuaternion q = DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis())*DualQuaternion::translation({-1.0f, 2.0f, 3.0f});
Matrix4 m = Matrix4::rotationX(deg(23.0f))*Matrix4::translation({-1.0f, 2.0f, 3.0f}); Matrix4 m = Matrix4::rotationX(Deg(23.0f))*Matrix4::translation({-1.0f, 2.0f, 3.0f});
/* Verify that negated dual quaternion gives the same transformation */ /* Verify that negated dual quaternion gives the same transformation */
CORRADE_COMPARE(q.matrix(), m); CORRADE_COMPARE(q.matrix(), m);
@ -212,10 +213,10 @@ void DualQuaternionTest::matrix() {
} }
void DualQuaternionTest::transformPoint() { void DualQuaternionTest::transformPoint() {
DualQuaternion a = DualQuaternion::translation({-1.0f, 2.0f, 3.0f})*DualQuaternion::rotation(deg(23.0f), Vector3::xAxis()); DualQuaternion a = DualQuaternion::translation({-1.0f, 2.0f, 3.0f})*DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis());
DualQuaternion b = DualQuaternion::rotation(deg(23.0f), Vector3::xAxis())*DualQuaternion::translation({-1.0f, 2.0f, 3.0f}); DualQuaternion b = DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis())*DualQuaternion::translation({-1.0f, 2.0f, 3.0f});
Matrix4 m = Matrix4::translation({-1.0f, 2.0f, 3.0f})*Matrix4::rotationX(deg(23.0f)); Matrix4 m = Matrix4::translation({-1.0f, 2.0f, 3.0f})*Matrix4::rotationX(Deg(23.0f));
Matrix4 n = Matrix4::rotationX(deg(23.0f))*Matrix4::translation({-1.0f, 2.0f, 3.0f}); Matrix4 n = Matrix4::rotationX(Deg(23.0f))*Matrix4::translation({-1.0f, 2.0f, 3.0f});
Vector3 v(0.0f, -3.6f, 0.7f); Vector3 v(0.0f, -3.6f, 0.7f);
Vector3 transformedA = (a*Dual(2)).transformPoint(v); Vector3 transformedA = (a*Dual(2)).transformPoint(v);
@ -228,10 +229,10 @@ void DualQuaternionTest::transformPoint() {
} }
void DualQuaternionTest::transformPointNormalized() { void DualQuaternionTest::transformPointNormalized() {
DualQuaternion a = DualQuaternion::translation({-1.0f, 2.0f, 3.0f})*DualQuaternion::rotation(deg(23.0f), Vector3::xAxis()); DualQuaternion a = DualQuaternion::translation({-1.0f, 2.0f, 3.0f})*DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis());
DualQuaternion b = DualQuaternion::rotation(deg(23.0f), Vector3::xAxis())*DualQuaternion::translation({-1.0f, 2.0f, 3.0f}); DualQuaternion b = DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis())*DualQuaternion::translation({-1.0f, 2.0f, 3.0f});
Matrix4 m = Matrix4::translation({-1.0f, 2.0f, 3.0f})*Matrix4::rotationX(deg(23.0f)); Matrix4 m = Matrix4::translation({-1.0f, 2.0f, 3.0f})*Matrix4::rotationX(Deg(23.0f));
Matrix4 n = Matrix4::rotationX(deg(23.0f))*Matrix4::translation({-1.0f, 2.0f, 3.0f}); Matrix4 n = Matrix4::rotationX(Deg(23.0f))*Matrix4::translation({-1.0f, 2.0f, 3.0f});
Vector3 v(0.0f, -3.6f, 0.7f); Vector3 v(0.0f, -3.6f, 0.7f);
std::ostringstream o; std::ostringstream o;

48
src/Math/Test/QuaternionTest.cpp

@ -58,6 +58,8 @@ class QuaternionTest: public Corrade::TestSuite::Tester {
void debug(); void debug();
}; };
typedef Math::Deg<float> Deg;
typedef Math::Rad<float> Rad;
typedef Math::Matrix<3, float> Matrix3; typedef Math::Matrix<3, float> Matrix3;
typedef Math::Matrix4<float> Matrix4; typedef Math::Matrix4<float> Matrix4;
typedef Math::Quaternion<float> Quaternion; typedef Math::Quaternion<float> Quaternion;
@ -227,48 +229,48 @@ void QuaternionTest::rotation() {
std::ostringstream o; std::ostringstream o;
Error::setOutput(&o); Error::setOutput(&o);
float angle = deg(120.0f);
Vector3 axis(1.0f/Constants<float>::sqrt3()); Vector3 axis(1.0f/Constants<float>::sqrt3());
CORRADE_COMPARE(Quaternion::rotation(deg(-74.0f), {-1.0f, 2.0f, 2.0f}), Quaternion()); CORRADE_COMPARE(Quaternion::rotation(Deg(-74.0f), {-1.0f, 2.0f, 2.0f}), Quaternion());
CORRADE_COMPARE(o.str(), "Math::Quaternion::rotation(): axis must be normalized\n"); CORRADE_COMPARE(o.str(), "Math::Quaternion::rotation(): axis must be normalized\n");
Quaternion q = Quaternion::rotation(angle, axis); Quaternion q = Quaternion::rotation(Deg(120.0f), axis);
CORRADE_COMPARE(q, Quaternion(Vector3(0.5f, 0.5f, 0.5f), 0.5f)); CORRADE_COMPARE(q, Quaternion(Vector3(0.5f, 0.5f, 0.5f), 0.5f));
CORRADE_COMPARE(q.rotationAngle(), angle); CORRADE_COMPARE_AS(q.rotationAngle(), Deg(120.0f), Deg);
CORRADE_COMPARE(q.rotationAxis(), axis); CORRADE_COMPARE(q.rotationAxis(), axis);
CORRADE_COMPARE(q.rotationAxis().length(), 1.0f); CORRADE_COMPARE(q.rotationAxis().length(), 1.0f);
/* Verify negative angle */ /* Verify negative angle */
Quaternion q2 = Quaternion::rotation(deg(-120.0f), axis); Quaternion q2 = Quaternion::rotation(Deg(-120.0f), axis);
CORRADE_COMPARE(q2, Quaternion(Vector3(-0.5f, -0.5f, -0.5f), 0.5f)); CORRADE_COMPARE(q2, Quaternion(Vector3(-0.5f, -0.5f, -0.5f), 0.5f));
CORRADE_COMPARE(q2.rotationAngle(), deg(120.0f)); CORRADE_COMPARE_AS(q2.rotationAngle(), Deg(120.0f), Deg);
CORRADE_COMPARE(q2.rotationAxis(), -axis); CORRADE_COMPARE(q2.rotationAxis(), -axis);
/* Default-constructed quaternion has zero angle and NaN axis */ /* Default-constructed quaternion has zero angle and NaN axis */
CORRADE_COMPARE(Quaternion().rotationAngle(), deg(0.0f)); CORRADE_COMPARE_AS(Quaternion().rotationAngle(), Deg(0.0f), Deg);
CORRADE_VERIFY(Quaternion().rotationAxis() != Quaternion().rotationAxis()); CORRADE_VERIFY(Quaternion().rotationAxis() != Quaternion().rotationAxis());
} }
void QuaternionTest::angle() { void QuaternionTest::angle() {
std::ostringstream o; std::ostringstream o;
Corrade::Utility::Error::setOutput(&o); Corrade::Utility::Error::setOutput(&o);
CORRADE_COMPARE(Quaternion::angle(Quaternion({1.0f, 2.0f, -3.0f}, -4.0f).normalized(), {{4.0f, -3.0f, 2.0f}, -1.0f}), auto angle = Quaternion::angle(Quaternion({1.0f, 2.0f, -3.0f}, -4.0f).normalized(), {{4.0f, -3.0f, 2.0f}, -1.0f});
std::numeric_limits<Vector3::Type>::quiet_NaN()); CORRADE_VERIFY(angle != angle);
CORRADE_COMPARE(o.str(), "Math::Quaternion::angle(): quaternions must be normalized\n"); CORRADE_COMPARE(o.str(), "Math::Quaternion::angle(): quaternions must be normalized\n");
o.str(""); o.str("");
CORRADE_COMPARE(Quaternion::angle({{1.0f, 2.0f, -3.0f}, -4.0f}, Quaternion({4.0f, -3.0f, 2.0f}, -1.0f).normalized()), angle = Quaternion::angle({{1.0f, 2.0f, -3.0f}, -4.0f}, Quaternion({4.0f, -3.0f, 2.0f}, -1.0f).normalized());
std::numeric_limits<Vector3::Type>::quiet_NaN()); CORRADE_VERIFY(angle != angle);
CORRADE_COMPARE(o.str(), "Math::Quaternion::angle(): quaternions must be normalized\n"); CORRADE_COMPARE(o.str(), "Math::Quaternion::angle(): quaternions must be normalized\n");
CORRADE_COMPARE(Quaternion::angle(Quaternion({1.0f, 2.0f, -3.0f}, -4.0f).normalized(), Quaternion({4.0f, -3.0f, 2.0f}, -1.0f).normalized()), CORRADE_COMPARE(Quaternion::angle(Quaternion({1.0f, 2.0f, -3.0f}, -4.0f).normalized(),
rad(1.704528f)); Quaternion({4.0f, -3.0f, 2.0f}, -1.0f).normalized()),
Rad(1.704528f));
} }
void QuaternionTest::matrix() { void QuaternionTest::matrix() {
Quaternion q = Quaternion::rotation(deg(37.0f), Vector3(1.0f/Constants<float>::sqrt3())); Quaternion q = Quaternion::rotation(Deg(37.0f), Vector3(1.0f/Constants<float>::sqrt3()));
Matrix3 m = Matrix4::rotation(deg(37.0f), Vector3(1.0f/Constants<float>::sqrt3())).rotationScaling(); Matrix3 m = Matrix4::rotation(Deg(37.0f), Vector3(1.0f/Constants<float>::sqrt3())).rotationScaling();
/* Verify that negated quaternion gives the same rotation */ /* Verify that negated quaternion gives the same rotation */
CORRADE_COMPARE(q.matrix(), m); CORRADE_COMPARE(q.matrix(), m);
@ -276,8 +278,8 @@ void QuaternionTest::matrix() {
} }
void QuaternionTest::lerp() { void QuaternionTest::lerp() {
Quaternion a = Quaternion::rotation(deg(15.0f), Vector3(1.0f/Constants<float>::sqrt3())); Quaternion a = Quaternion::rotation(Deg(15.0f), Vector3(1.0f/Constants<float>::sqrt3()));
Quaternion b = Quaternion::rotation(deg(23.0f), Vector3::xAxis()); Quaternion b = Quaternion::rotation(Deg(23.0f), Vector3::xAxis());
std::ostringstream o; std::ostringstream o;
Corrade::Utility::Error::setOutput(&o); Corrade::Utility::Error::setOutput(&o);
@ -298,8 +300,8 @@ void QuaternionTest::lerp() {
} }
void QuaternionTest::slerp() { void QuaternionTest::slerp() {
Quaternion a = Quaternion::rotation(deg(15.0f), Vector3(1.0f/Constants<float>::sqrt3())); Quaternion a = Quaternion::rotation(Deg(15.0f), Vector3(1.0f/Constants<float>::sqrt3()));
Quaternion b = Quaternion::rotation(deg(23.0f), Vector3::xAxis()); Quaternion b = Quaternion::rotation(Deg(23.0f), Vector3::xAxis());
std::ostringstream o; std::ostringstream o;
Corrade::Utility::Error::setOutput(&o); Corrade::Utility::Error::setOutput(&o);
@ -320,8 +322,8 @@ void QuaternionTest::slerp() {
} }
void QuaternionTest::rotateVector() { void QuaternionTest::rotateVector() {
Quaternion a = Quaternion::rotation(deg(23.0f), Vector3::xAxis()); Quaternion a = Quaternion::rotation(Deg(23.0f), Vector3::xAxis());
Matrix4 m = Matrix4::rotationX(deg(23.0f)); Matrix4 m = Matrix4::rotationX(Deg(23.0f));
Vector3 v(5.0f, -3.6f, 0.7f); Vector3 v(5.0f, -3.6f, 0.7f);
Vector3 rotated = a.rotateVector(v); Vector3 rotated = a.rotateVector(v);
@ -330,8 +332,8 @@ void QuaternionTest::rotateVector() {
} }
void QuaternionTest::rotateVectorNormalized() { void QuaternionTest::rotateVectorNormalized() {
Quaternion a = Quaternion::rotation(deg(23.0f), Vector3::xAxis()); Quaternion a = Quaternion::rotation(Deg(23.0f), Vector3::xAxis());
Matrix4 m = Matrix4::rotationX(deg(23.0f)); Matrix4 m = Matrix4::rotationX(Deg(23.0f));
Vector3 v(5.0f, -3.6f, 0.7f); Vector3 v(5.0f, -3.6f, 0.7f);
std::ostringstream o; std::ostringstream o;

Loading…
Cancel
Save