Skip to content

Commit

Permalink
Math: fuzzy compare for division-by-zero in quaternion s(c)lerp.
Browse files Browse the repository at this point in the history
Also remove a totally unneeded conversion.
  • Loading branch information
mosra committed Sep 3, 2018
1 parent 880bf7a commit eadf898
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 4 deletions.
4 changes: 2 additions & 2 deletions src/Magnum/Math/DualQuaternion.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ template<class T> inline DualQuaternion<T> sclerp(const DualQuaternion<T>& norma

/* Avoid division by zero: interpolate just the translation part */
/** @todo could this be optimized somehow? */
if(std::abs(cosHalfAngle) >= T(1))
if(std::abs(cosHalfAngle) >= T(1) - TypeTraits<T>::epsilon())
return DualQuaternion<T>::translation(Implementation::lerp(normalizedA.translation(), normalizedB.translation(), t))*DualQuaternion<T>{normalizedA.real()};

/* l + εm = q_A^**q_B */
Expand Down Expand Up @@ -151,7 +151,7 @@ template<class T> inline DualQuaternion<T> sclerpShortestPath(const DualQuaterni

/* Avoid division by zero: interpolate just the translation part */
/** @todo could this be optimized somehow? */
if(std::abs(cosHalfAngle) >= T(1))
if(std::abs(cosHalfAngle) >= T(1) - TypeTraits<T>::epsilon())
return DualQuaternion<T>::translation(Implementation::lerp(normalizedA.translation(), normalizedB.translation(), t))*DualQuaternion<T>{normalizedA.real()};

/* l + εm = q_A^**q_B, multiplying with -1 ensures shortest path when dot < 0 */
Expand Down
6 changes: 4 additions & 2 deletions src/Magnum/Math/Quaternion.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ template<class T> inline Quaternion<T> slerp(const Quaternion<T>& normalizedA, c
const T cosHalfAngle = dot(normalizedA, normalizedB);

/* Avoid division by zero */
if(std::abs(cosHalfAngle) >= T(1)) return Quaternion<T>{normalizedA};
if(std::abs(cosHalfAngle) >= T(1) - TypeTraits<T>::epsilon())
return normalizedA;

const T a = std::acos(cosHalfAngle);
return (std::sin((T(1) - t)*a)*normalizedA + std::sin(t*a)*normalizedB)/std::sin(a);
Expand Down Expand Up @@ -206,7 +207,8 @@ template<class T> inline Quaternion<T> slerpShortestPath(const Quaternion<T>& no
const T cosHalfAngle = dot(normalizedA, normalizedB);

/* Avoid division by zero */
if(std::abs(cosHalfAngle) >= T(1)) return Quaternion<T>{normalizedA};
if(std::abs(cosHalfAngle) >= T(1) - TypeTraits<T>::epsilon())
return normalizedA;

const Quaternion<T> shortestNormalizedA = cosHalfAngle < 0 ? -normalizedA : normalizedA;

Expand Down

0 comments on commit eadf898

Please sign in to comment.