Browse Source

Math: properly test also (s)lerpShortestPath() assertions.

And boom, there was a bug.
pull/284/head
Vladimír Vondruš 8 years ago
parent
commit
dfcd33ffe8
  1. 2
      src/Magnum/Math/Quaternion.h
  2. 105
      src/Magnum/Math/Test/QuaternionTest.cpp

2
src/Magnum/Math/Quaternion.h

@ -203,7 +203,7 @@ otherwise, the interpolation is performed as: @f[
*/ */
template<class T> inline Quaternion<T> slerpShortestPath(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB, T t) { template<class T> inline Quaternion<T> slerpShortestPath(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB, T t) {
CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(),
"Math::slerp(): quaternions must be normalized", {}); "Math::slerpShortestPath(): quaternions must be normalized", {});
const T cosHalfAngle = dot(normalizedA, normalizedB); const T cosHalfAngle = dot(normalizedA, normalizedB);
/* Avoid division by zero */ /* Avoid division by zero */

105
src/Magnum/Math/Test/QuaternionTest.cpp

@ -91,13 +91,15 @@ struct QuaternionTest: Corrade::TestSuite::Tester {
void matrix(); void matrix();
void lerp(); void lerp();
void lerpShortestPath();
void lerp2D(); void lerp2D();
void lerpNotNormalized(); void lerpNotNormalized();
void lerpShortestPath();
void lerpShortestPathNotNormalized();
void slerp(); void slerp();
void slerpShortestPath();
void slerp2D(); void slerp2D();
void slerpNotNormalized(); void slerpNotNormalized();
void slerpShortestPath();
void slerpShortestPathNotNormalized();
void transformVector(); void transformVector();
void transformVectorNormalized(); void transformVectorNormalized();
@ -156,13 +158,15 @@ QuaternionTest::QuaternionTest() {
&QuaternionTest::matrix, &QuaternionTest::matrix,
&QuaternionTest::lerp, &QuaternionTest::lerp,
&QuaternionTest::lerpShortestPath,
&QuaternionTest::lerp2D, &QuaternionTest::lerp2D,
&QuaternionTest::lerpNotNormalized, &QuaternionTest::lerpNotNormalized,
&QuaternionTest::lerpShortestPath,
&QuaternionTest::lerpShortestPathNotNormalized,
&QuaternionTest::slerp, &QuaternionTest::slerp,
&QuaternionTest::slerpShortestPath,
&QuaternionTest::slerp2D, &QuaternionTest::slerp2D,
&QuaternionTest::slerpNotNormalized, &QuaternionTest::slerpNotNormalized,
&QuaternionTest::slerpShortestPath,
&QuaternionTest::slerpShortestPathNotNormalized,
&QuaternionTest::transformVector, &QuaternionTest::transformVector,
&QuaternionTest::transformVectorNormalized, &QuaternionTest::transformVectorNormalized,
@ -501,24 +505,6 @@ void QuaternionTest::lerp() {
CORRADE_COMPARE(lerpShortestPath, expected); CORRADE_COMPARE(lerpShortestPath, expected);
} }
void QuaternionTest::lerpShortestPath() {
Quaternion a = Quaternion::rotation(0.0_degf, Vector3::zAxis());
Quaternion b = Quaternion::rotation(225.0_degf, Vector3::zAxis());
Quaternion slerp = Math::lerp(a, b, 0.25f);
Quaternion slerpShortestPath = Math::lerpShortestPath(a, b, 0.25f);
CORRADE_VERIFY(slerp.isNormalized());
CORRADE_VERIFY(slerpShortestPath.isNormalized());
CORRADE_COMPARE(slerp.axis(), Vector3::zAxis());
CORRADE_COMPARE(slerpShortestPath.axis(), Vector3::zAxis());
CORRADE_COMPARE(slerp.angle(), 38.8848_degf);
CORRADE_COMPARE(slerpShortestPath.angle(), 329.448_degf);
CORRADE_COMPARE(slerp, (Quaternion{{0.0f, 0.0f, 0.332859f}, 0.942977f}));
CORRADE_COMPARE(slerpShortestPath, (Quaternion{{0.0f, 0.0f, 0.26347f}, -0.964667f}));
}
void QuaternionTest::lerp2D() { void QuaternionTest::lerp2D() {
/* Results should be consistent with ComplexTest::lerp() */ /* Results should be consistent with ComplexTest::lerp() */
Quaternion a = Quaternion::rotation(15.0_degf, Vector3::zAxis()); Quaternion a = Quaternion::rotation(15.0_degf, Vector3::zAxis());
@ -542,6 +528,37 @@ void QuaternionTest::lerpNotNormalized() {
"Math::lerp(): quaternions must be normalized\n"); "Math::lerp(): quaternions must be normalized\n");
} }
void QuaternionTest::lerpShortestPath() {
Quaternion a = Quaternion::rotation(0.0_degf, Vector3::zAxis());
Quaternion b = Quaternion::rotation(225.0_degf, Vector3::zAxis());
Quaternion lerp = Math::lerp(a, b, 0.25f);
Quaternion lerpShortestPath = Math::lerpShortestPath(a, b, 0.25f);
CORRADE_VERIFY(lerp.isNormalized());
CORRADE_VERIFY(lerpShortestPath.isNormalized());
CORRADE_COMPARE(lerp.axis(), Vector3::zAxis());
CORRADE_COMPARE(lerpShortestPath.axis(), Vector3::zAxis());
CORRADE_COMPARE(lerp.angle(), 38.8848_degf);
CORRADE_COMPARE(lerpShortestPath.angle(), 329.448_degf);
CORRADE_COMPARE(lerp, (Quaternion{{0.0f, 0.0f, 0.332859f}, 0.942977f}));
CORRADE_COMPARE(lerpShortestPath, (Quaternion{{0.0f, 0.0f, 0.26347f}, -0.964667f}));
}
void QuaternionTest::lerpShortestPathNotNormalized() {
std::ostringstream out;
Error redirectError{&out};
Quaternion a;
Math::lerpShortestPath(a*3.0f, a, 0.35f);
Math::lerpShortestPath(a, a*-3.0f, 0.35f);
/* lerpShortestPath() is calling lerp(), so the message is from there */
CORRADE_COMPARE(out.str(),
"Math::lerp(): quaternions must be normalized\n"
"Math::lerp(): quaternions must be normalized\n");
}
void QuaternionTest::slerp() { void QuaternionTest::slerp() {
Quaternion a = Quaternion::rotation(15.0_degf, Vector3(1.0f/Constants<Float>::sqrt3())); Quaternion a = Quaternion::rotation(15.0_degf, Vector3(1.0f/Constants<Float>::sqrt3()));
Quaternion b = Quaternion::rotation(23.0_degf, Vector3::xAxis()); Quaternion b = Quaternion::rotation(23.0_degf, Vector3::xAxis());
@ -563,6 +580,29 @@ void QuaternionTest::slerp() {
CORRADE_COMPARE(Math::slerpShortestPath(a, -a, 0.25f), a); CORRADE_COMPARE(Math::slerpShortestPath(a, -a, 0.25f), a);
} }
void QuaternionTest::slerp2D() {
/* Result angle should be equivalent to ComplexTest::slerp() */
Quaternion a = Quaternion::rotation(15.0_degf, Vector3::zAxis());
Quaternion b = Quaternion::rotation(57.0_degf, Vector3::zAxis());
Quaternion slerp = Math::slerp(a, b, 0.35f);
CORRADE_VERIFY(slerp.isNormalized());
CORRADE_COMPARE(slerp.angle(), 29.7_degf); /* 15 + (57-15)*0.35 */
CORRADE_COMPARE(slerp, (Quaternion{{0.0f, 0.0f, 0.256289f}, 0.9666f}));
}
void QuaternionTest::slerpNotNormalized() {
std::ostringstream out;
Error redirectError{&out};
Quaternion a;
Math::slerp(a*3.0f, a, 0.35f);
Math::slerp(a, a*-3.0f, 0.35f);
CORRADE_COMPARE(out.str(),
"Math::slerp(): quaternions must be normalized\n"
"Math::slerp(): quaternions must be normalized\n");
}
void QuaternionTest::slerpShortestPath() { void QuaternionTest::slerpShortestPath() {
Quaternion a = Quaternion::rotation(0.0_degf, Vector3::zAxis()); Quaternion a = Quaternion::rotation(0.0_degf, Vector3::zAxis());
Quaternion b = Quaternion::rotation(225.0_degf, Vector3::zAxis()); Quaternion b = Quaternion::rotation(225.0_degf, Vector3::zAxis());
@ -581,27 +621,16 @@ void QuaternionTest::slerpShortestPath() {
CORRADE_COMPARE(slerpShortestPath, (Quaternion{{0.0f, 0.0f, 0.290285f}, -0.95694f})); CORRADE_COMPARE(slerpShortestPath, (Quaternion{{0.0f, 0.0f, 0.290285f}, -0.95694f}));
} }
void QuaternionTest::slerp2D() { void QuaternionTest::slerpShortestPathNotNormalized() {
/* Result angle should be equivalent to ComplexTest::slerp() */
Quaternion a = Quaternion::rotation(15.0_degf, Vector3::zAxis());
Quaternion b = Quaternion::rotation(57.0_degf, Vector3::zAxis());
Quaternion slerp = Math::slerp(a, b, 0.35f);
CORRADE_VERIFY(slerp.isNormalized());
CORRADE_COMPARE(slerp.angle(), 29.7_degf); /* 15 + (57-15)*0.35 */
CORRADE_COMPARE(slerp, (Quaternion{{0.0f, 0.0f, 0.256289f}, 0.9666f}));
}
void QuaternionTest::slerpNotNormalized() {
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
Quaternion a; Quaternion a;
Math::slerp(a*3.0f, a, 0.35f); Math::slerpShortestPath(a*3.0f, a, 0.35f);
Math::slerp(a, a*-3.0f, 0.35f); Math::slerpShortestPath(a, a*-3.0f, 0.35f);
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"Math::slerp(): quaternions must be normalized\n" "Math::slerpShortestPath(): quaternions must be normalized\n"
"Math::slerp(): quaternions must be normalized\n"); "Math::slerpShortestPath(): quaternions must be normalized\n");
} }
void QuaternionTest::transformVector() { void QuaternionTest::transformVector() {

Loading…
Cancel
Save