Browse Source

Math: proper implementation of Vector::isZero() for integers.

The thing is:

 * Doing std::abs() and comparing to some epsilon value is crazy thing
   to do with integers.
 * When using unsigned integers, Clang rightfully complained that
   calling std::abs() on these is a sign of insanity. This fixes it too.
pull/183/head^2
Vladimír Vondruš 10 years ago
parent
commit
a4fbea42d0
  1. 14
      src/Magnum/Math/Test/VectorTest.cpp
  2. 6
      src/Magnum/Math/TypeTraits.h
  3. 16
      src/Magnum/Math/Vector.h

14
src/Magnum/Math/Test/VectorTest.cpp

@ -68,7 +68,8 @@ struct VectorTest: Corrade::TestSuite::Tester {
void constructCopy();
void convert();
void isZero();
void isZeroFloat();
void isZeroInteger();
void isNormalized();
void data();
@ -125,7 +126,8 @@ VectorTest::VectorTest() {
&VectorTest::constructCopy,
&VectorTest::convert,
&VectorTest::isZero,
&VectorTest::isZeroFloat,
&VectorTest::isZeroInteger,
&VectorTest::isNormalized,
&VectorTest::data,
@ -256,11 +258,17 @@ void VectorTest::convert() {
CORRADE_VERIFY(!(std::is_convertible<Vector3, Vec3>::value));
}
void VectorTest::isZero() {
void VectorTest::isZeroFloat() {
CORRADE_VERIFY(!Vector3(0.01f, 0.0f, 0.0f).isZero());
CORRADE_VERIFY(Vector3(0.0f, Math::TypeTraits<float>::epsilon()/2.0f, 0.0f).isZero());
CORRADE_VERIFY(Vector3(0.0f, 0.0f, 0.0f).isZero());
}
void VectorTest::isZeroInteger() {
CORRADE_VERIFY(!(Math::Vector<3, Int>{0, 1, 0}.isZero()));
CORRADE_VERIFY((Math::Vector<3, Int>{0, 0, 0}.isZero()));
}
void VectorTest::isNormalized() {
CORRADE_VERIFY(!Vector3(1.0f, 2.0f, -1.0f).isNormalized());
CORRADE_VERIFY(Vector3(0.0f, 1.0f, 0.0f).isNormalized());

6
src/Magnum/Math/TypeTraits.h

@ -198,12 +198,6 @@ template<> struct TypeTraits<long double>: Implementation::TypeTraitsFloatingPoi
namespace Implementation {
/* Proper comparison should be with epsilon^2, but the value is not
representable in given precision. Comparing to epsilon instead. */
template<class T> inline bool isZeroSquared(T lengthSquared) {
return std::abs(lengthSquared) < TypeTraits<T>::epsilon();
}
/* Comparing squared length to 1 is not sufficient to compare within range
[1 - epsilon, 1 + epsilon], as e.g. Quaternion with dot() = 1 + 1e-7 when
converted to matrix has column vectors with dot() = 1 + 1e-6, which is just

16
src/Magnum/Math/Vector.h

@ -54,6 +54,20 @@ namespace Implementation {
template<class T, class U> T lerp(const T& a, const T& b, U t) {
return T((U(1) - t)*a + t*b);
}
template<bool integral> struct IsZero;
template<> struct IsZero<false> {
template<std::size_t size, class T> bool operator()(const Vector<size, T>& vec) const {
/* Proper comparison should be with epsilon^2, but the value is not
representable in given precision. Comparing to epsilon instead. */
return std::abs(vec.dot()) < TypeTraits<T>::epsilon();
}
};
template<> struct IsZero<true> {
template<std::size_t size, class T> bool operator()(const Vector<size, T>& vec) const {
return vec == Vector<size, T>{};
}
};
}
/** @relatesalso Vector
@ -262,7 +276,7 @@ template<std::size_t size, class T> class Vector {
* @see @ref dot(), @ref normalized()
*/
bool isZero() const {
return Implementation::isZeroSquared(dot());
return Implementation::IsZero<std::is_integral<T>::value>{}(*this);
}
/**

Loading…
Cancel
Save