Skip to content

Commit

Permalink
Math: properly test also (s)lerpShortestPath() assertions.
Browse files Browse the repository at this point in the history
And boom, there was a bug.
  • Loading branch information
mosra committed Sep 6, 2018
1 parent d5e6012 commit dfcd33f
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 39 deletions.
2 changes: 1 addition & 1 deletion src/Magnum/Math/Quaternion.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(),
"Math::slerp(): quaternions must be normalized", {});
"Math::slerpShortestPath(): quaternions must be normalized", {});
const T cosHalfAngle = dot(normalizedA, normalizedB);

/* Avoid division by zero */
Expand Down
105 changes: 67 additions & 38 deletions src/Magnum/Math/Test/QuaternionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,15 @@ struct QuaternionTest: Corrade::TestSuite::Tester {
void matrix();

void lerp();
void lerpShortestPath();
void lerp2D();
void lerpNotNormalized();
void lerpShortestPath();
void lerpShortestPathNotNormalized();
void slerp();
void slerpShortestPath();
void slerp2D();
void slerpNotNormalized();
void slerpShortestPath();
void slerpShortestPathNotNormalized();

void transformVector();
void transformVectorNormalized();
Expand Down Expand Up @@ -156,13 +158,15 @@ QuaternionTest::QuaternionTest() {
&QuaternionTest::matrix,

&QuaternionTest::lerp,
&QuaternionTest::lerpShortestPath,
&QuaternionTest::lerp2D,
&QuaternionTest::lerpNotNormalized,
&QuaternionTest::lerpShortestPath,
&QuaternionTest::lerpShortestPathNotNormalized,
&QuaternionTest::slerp,
&QuaternionTest::slerpShortestPath,
&QuaternionTest::slerp2D,
&QuaternionTest::slerpNotNormalized,
&QuaternionTest::slerpShortestPath,
&QuaternionTest::slerpShortestPathNotNormalized,

&QuaternionTest::transformVector,
&QuaternionTest::transformVectorNormalized,
Expand Down Expand Up @@ -501,24 +505,6 @@ void QuaternionTest::lerp() {
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() {
/* Results should be consistent with ComplexTest::lerp() */
Quaternion a = Quaternion::rotation(15.0_degf, Vector3::zAxis());
Expand All @@ -542,6 +528,37 @@ void QuaternionTest::lerpNotNormalized() {
"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() {
Quaternion a = Quaternion::rotation(15.0_degf, Vector3(1.0f/Constants<Float>::sqrt3()));
Quaternion b = Quaternion::rotation(23.0_degf, Vector3::xAxis());
Expand All @@ -563,6 +580,29 @@ void QuaternionTest::slerp() {
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() {
Quaternion a = Quaternion::rotation(0.0_degf, Vector3::zAxis());
Quaternion b = Quaternion::rotation(225.0_degf, Vector3::zAxis());
Expand All @@ -581,27 +621,16 @@ void QuaternionTest::slerpShortestPath() {
CORRADE_COMPARE(slerpShortestPath, (Quaternion{{0.0f, 0.0f, 0.290285f}, -0.95694f}));
}

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() {
void QuaternionTest::slerpShortestPathNotNormalized() {
std::ostringstream out;
Error redirectError{&out};

Quaternion a;
Math::slerp(a*3.0f, a, 0.35f);
Math::slerp(a, a*-3.0f, 0.35f);
Math::slerpShortestPath(a*3.0f, a, 0.35f);
Math::slerpShortestPath(a, a*-3.0f, 0.35f);
CORRADE_COMPARE(out.str(),
"Math::slerp(): quaternions must be normalized\n"
"Math::slerp(): quaternions must be normalized\n");
"Math::slerpShortestPath(): quaternions must be normalized\n"
"Math::slerpShortestPath(): quaternions must be normalized\n");
}

void QuaternionTest::transformVector() {
Expand Down

0 comments on commit dfcd33f

Please sign in to comment.