Browse Source

Math: vector overloads for normalize() and denormalize().

pull/7/head
Vladimír Vondruš 13 years ago
parent
commit
263d8351b6
  1. 45
      src/Math/Functions.h
  2. 10
      src/Math/Test/FunctionsTest.cpp

45
src/Math/Functions.h

@ -144,9 +144,9 @@ template<std::size_t size, class T> Vector<size, T> clamp(const Vector<size, T>&
Converts integral value from full range of given *unsigned* integral type to Converts integral value from full range of given *unsigned* integral type to
value in range @f$ [0, 1] @f$ or from *signed* integral to range @f$ [-1, 1] @f$. value in range @f$ [0, 1] @f$ or from *signed* integral to range @f$ [-1, 1] @f$.
@note For best precision, `FloatingPoint` type should be always larger that @note For best precision, resulting `FloatingPoint` type should be always
resulting `Integral` type (e.g. `double` to `std::int32_t`, `long double` larger that `Integral` type (e.g. `double` from `std::int32_t`, `long double`
to `std::int64_t`). from `std::int64_t` and similarly for vector types).
@attention To ensure the integral type is correctly detected when using @attention To ensure the integral type is correctly detected when using
literals, this function should be called with both template parameters literals, this function should be called with both template parameters
@ -162,14 +162,27 @@ float b = normalize<float, std::int8_t>('\127');
@see denormalize() @see denormalize()
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
template<class FloatingPoint, class Integral> inline constexpr FloatingPoint normalize(Integral value); template<class FloatingPoint, class Integral> inline FloatingPoint normalize(const Integral& value);
#else #else
template<class FloatingPoint, class Integral> inline constexpr typename std::enable_if<std::is_floating_point<FloatingPoint>::value && std::is_integral<Integral>::value && std::is_unsigned<Integral>::value, FloatingPoint>::type normalize(Integral value) { template<class FloatingPoint, class Integral> inline typename std::enable_if<std::is_arithmetic<Integral>::value && std::is_unsigned<Integral>::value, FloatingPoint>::type normalize(Integral value) {
static_assert(std::is_floating_point<FloatingPoint>::value && std::is_integral<Integral>::value,
"Math::normalize(): normalization must be done from integral to floating-point type");
return value/FloatingPoint(std::numeric_limits<Integral>::max()); return value/FloatingPoint(std::numeric_limits<Integral>::max());
} }
template<class FloatingPoint, class Integral> inline typename std::enable_if<std::is_arithmetic<Integral>::value && std::is_signed<Integral>::value, FloatingPoint>::type normalize(Integral value) {
template<class FloatingPoint, class Integral> inline constexpr typename std::enable_if<std::is_floating_point<FloatingPoint>::value && std::is_integral<Integral>::value && std::is_signed<Integral>::value, FloatingPoint>::type normalize(Integral value) { static_assert(std::is_floating_point<FloatingPoint>::value && std::is_integral<Integral>::value,
return std::max(value/FloatingPoint(std::numeric_limits<Integral>::max()), FloatingPoint(-1)); "Math::normalize(): normalization must be done from integral to floating-point type");
return Math::max(value/FloatingPoint(std::numeric_limits<Integral>::max()), FloatingPoint(-1));
}
template<class FloatingPoint, class Integral> inline typename std::enable_if<std::is_unsigned<typename Integral::Type>::value, FloatingPoint>::type normalize(const Integral& value) {
static_assert(std::is_floating_point<typename FloatingPoint::Type>::value && std::is_integral<typename Integral::Type>::value,
"Math::normalize(): normalization must be done from integral to floating-point type");
return FloatingPoint::from(value)/typename FloatingPoint::Type(std::numeric_limits<typename Integral::Type>::max());
}
template<class FloatingPoint, class Integral> inline typename std::enable_if<std::is_signed<typename Integral::Type>::value, FloatingPoint>::type normalize(const Integral& value) {
static_assert(std::is_floating_point<typename FloatingPoint::Type>::value && std::is_integral<typename Integral::Type>::value,
"Math::normalize(): normalization must be done from integral to floating-point type");
return Math::max(FloatingPoint::from(value)/typename FloatingPoint::Type(std::numeric_limits<typename Integral::Type>::max()), FloatingPoint(-1));
} }
#endif #endif
@ -182,16 +195,26 @@ integral type.
@note For best precision, `FloatingPoint` type should be always larger that @note For best precision, `FloatingPoint` type should be always larger that
resulting `Integral` type (e.g. `double` to `std::int32_t`, `long double` resulting `Integral` type (e.g. `double` to `std::int32_t`, `long double`
to `std::int64_t`). to `std::int64_t` and similarly for vector types).
@attention Return value for floating point numbers outside the normalized
range is undefined.
@see normalize() @see normalize()
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
template<class Integral, class FloatingPoint> inline constexpr typename Integral denormalize(FloatingPoint value); template<class Integral, class FloatingPoint> inline Integral denormalize(const FloatingPoint& value);
#else #else
template<class Integral, class FloatingPoint> inline constexpr typename std::enable_if<std::is_floating_point<FloatingPoint>::value && std::is_integral<Integral>::value, Integral>::type denormalize(FloatingPoint value) { template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_arithmetic<FloatingPoint>::value, Integral>::type denormalize(FloatingPoint value) {
static_assert(std::is_floating_point<FloatingPoint>::value && std::is_integral<Integral>::value,
"Math::denormalize(): denormalization must be done from floating-point to integral type");
return value*std::numeric_limits<Integral>::max(); return value*std::numeric_limits<Integral>::max();
} }
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_arithmetic<typename Integral::Type>::value, Integral>::type denormalize(const FloatingPoint& value) {
static_assert(std::is_floating_point<typename FloatingPoint::Type>::value && std::is_integral<typename Integral::Type>::value,
"Math::denormalize(): denormalization must be done from floating-point to integral type");
return Integral::from(value*std::numeric_limits<typename Integral::Type>::max());
}
#endif #endif
/*@}*/ /*@}*/

10
src/Math/Test/FunctionsTest.cpp

@ -40,6 +40,8 @@ class FunctionsTest: public Corrade::TestSuite::Tester {
}; };
typedef Math::Vector3<float> Vector3; typedef Math::Vector3<float> Vector3;
typedef Math::Vector3<std::uint8_t> Vector3ub;
typedef Math::Vector3<std::int8_t> Vector3b;
typedef Math::Vector3<std::int32_t> Vector3i; typedef Math::Vector3<std::int32_t> Vector3i;
FunctionsTest::FunctionsTest() { FunctionsTest::FunctionsTest() {
@ -90,6 +92,8 @@ void FunctionsTest::normalizeUnsigned() {
CORRADE_COMPARE((Math::normalize<float, std::uint16_t>(8192)), 0.125002f); CORRADE_COMPARE((Math::normalize<float, std::uint16_t>(8192)), 0.125002f);
CORRADE_COMPARE((Math::normalize<float, std::uint16_t>(49152)), 0.750011f); CORRADE_COMPARE((Math::normalize<float, std::uint16_t>(49152)), 0.750011f);
CORRADE_COMPARE(Math::normalize<Vector3>(Vector3ub(0, 127, 255)), Vector3(0.0f, 0.498039f, 1.0f));
} }
void FunctionsTest::normalizeSigned() { void FunctionsTest::normalizeSigned() {
@ -111,6 +115,8 @@ void FunctionsTest::normalizeSigned() {
CORRADE_COMPARE((Math::normalize<float, std::int16_t>(16384)), 0.500015f); CORRADE_COMPARE((Math::normalize<float, std::int16_t>(16384)), 0.500015f);
CORRADE_COMPARE((Math::normalize<float, std::int16_t>(-16384)), -0.500015f); CORRADE_COMPARE((Math::normalize<float, std::int16_t>(-16384)), -0.500015f);
CORRADE_COMPARE(Math::normalize<Vector3>(Vector3b(0, -127, 64)), Vector3(0.0f, -1.0f, 0.503937f));
} }
void FunctionsTest::denormalizeUnsigned() { void FunctionsTest::denormalizeUnsigned() {
@ -128,6 +134,8 @@ void FunctionsTest::denormalizeUnsigned() {
CORRADE_COMPARE(Math::denormalize<std::uint16_t>(0.33f), 21626); CORRADE_COMPARE(Math::denormalize<std::uint16_t>(0.33f), 21626);
CORRADE_COMPARE(Math::denormalize<std::uint16_t>(0.66f), 43253); CORRADE_COMPARE(Math::denormalize<std::uint16_t>(0.66f), 43253);
CORRADE_COMPARE(Math::denormalize<Vector3ub>(Vector3(0.0f, 0.5f, 1.0f)), Vector3ub(0, 127, 255));
} }
void FunctionsTest::denormalizeSigned() { void FunctionsTest::denormalizeSigned() {
@ -149,6 +157,8 @@ void FunctionsTest::denormalizeSigned() {
CORRADE_COMPARE(Math::denormalize<std::int16_t>(-0.33f), -10813); CORRADE_COMPARE(Math::denormalize<std::int16_t>(-0.33f), -10813);
CORRADE_COMPARE(Math::denormalize<std::int16_t>(0.66f), 21626); CORRADE_COMPARE(Math::denormalize<std::int16_t>(0.66f), 21626);
CORRADE_COMPARE(Math::denormalize<Vector3b>(Vector3(0.0f, -1.0f, 0.5f)), Vector3b(0, -127, 63));
} }
void FunctionsTest::renormalizeUnsinged() { void FunctionsTest::renormalizeUnsinged() {

Loading…
Cancel
Save