diff --git a/src/Magnum/Math/Functions.h b/src/Magnum/Math/Functions.h index 010bbb974..82e693b45 100644 --- a/src/Magnum/Math/Functions.h +++ b/src/Magnum/Math/Functions.h @@ -125,18 +125,19 @@ perform the operations component-wise. /** @brief Minimum +NaNs passed in @p value parameter are propagated. @see @ref max(), @ref minmax(), @ref clamp(), @ref Vector::min() */ #ifdef DOXYGEN_GENERATING_OUTPUT -template inline T min(T a, T b); +template inline T min(T value, T min); #else -template inline typename std::enable_if::value, T>::type min(T a, T b) { - return std::min(a, b); +template inline typename std::enable_if::value, T>::type min(T value, T min) { + return std::min(value, min); } -template inline Vector min(const Vector& a, const Vector& b) { +template inline Vector min(const Vector& value, const Vector& min) { Vector out; for(std::size_t i = 0; i != size; ++i) - out[i] = std::min(a[i], b[i]); + out[i] = std::min(value[i], min[i]); return out; } #endif @@ -152,18 +153,19 @@ template inline T min(std::initializer_list list) { /** @brief Maximum +NaNs passed in @p value parameter are propagated. @see @ref min(), @ref minmax(), @ref clamp(), @ref Vector::max() */ #ifdef DOXYGEN_GENERATING_OUTPUT -template inline T max(const T& a, const T& b); +template inline T max(T value, T max); #else -template inline typename std::enable_if::value, T>::type max(T a, T b) { - return std::max(a, b); +template inline typename std::enable_if::value, T>::type max(T value, T max) { + return std::max(value, max); } -template Vector max(const Vector& a, const Vector& b) { +template Vector max(const Vector& value, const Vector& max) { Vector out; for(std::size_t i = 0; i != size; ++i) - out[i] = std::max(a[i], b[i]); + out[i] = std::max(value[i], max[i]); return out; } #endif @@ -195,6 +197,31 @@ template std::pair, Vector> } #endif +/** +@brief Clamp value + +Values smaller than @p min are set to @p min, values larger than @p max are +set to @p max. Equivalent to: +@code +Math::min(Math::max(value, min), max) +@endcode +NaNs passed in @p value parameter are propagated. +@see @ref min(), @ref max() +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template inline T clamp(const T& value, U min, U max); +#else +template inline typename std::enable_if::value, T>::type clamp(T value, T min, T max) { + return std::min(std::max(value, min), max); +} +template Vector clamp(const Vector& value, T min, T max) { + Vector out; + for(std::size_t i = 0; i != size; ++i) + out[i] = clamp(value[i], min, max); + return out; +} +#endif + /** @brief Sign @@ -321,30 +348,6 @@ template Vector sqrtInverted(const Vector inline T clamp(const T& value, U min, U max); -#else -template inline typename std::enable_if::value, T>::type clamp(T value, T min, T max) { - return std::min(std::max(value, min), max); -} -template Vector clamp(const Vector& value, T min, T max) { - Vector out; - for(std::size_t i = 0; i != size; ++i) - out[i] = clamp(value[i], min, max); - return out; -} -#endif - /** @brief Linear interpolation of two values @param a First value diff --git a/src/Magnum/Math/Test/FunctionsTest.cpp b/src/Magnum/Math/Test/FunctionsTest.cpp index 385708a01..87211fd34 100644 --- a/src/Magnum/Math/Test/FunctionsTest.cpp +++ b/src/Magnum/Math/Test/FunctionsTest.cpp @@ -39,6 +39,9 @@ class FunctionsTest: public Corrade::TestSuite::Tester { void max(); void maxList(); void minmax(); + void clamp(); + void nanPropagation(); + void sign(); void abs(); @@ -48,7 +51,6 @@ class FunctionsTest: public Corrade::TestSuite::Tester { void sqrt(); void sqrtInverted(); - void clamp(); void lerp(); void lerpInverted(); void fma(); @@ -71,6 +73,7 @@ class FunctionsTest: public Corrade::TestSuite::Tester { typedef Math::Constants Constants; typedef Math::Deg Deg; typedef Math::Rad Rad; +typedef Math::Vector2 Vector2; typedef Math::Vector3 Vector3; typedef Math::Vector3 Vector3ub; typedef Math::Vector3 Vector3b; @@ -82,6 +85,9 @@ FunctionsTest::FunctionsTest() { &FunctionsTest::max, &FunctionsTest::maxList, &FunctionsTest::minmax, + &FunctionsTest::clamp, + &FunctionsTest::nanPropagation, + &FunctionsTest::sign, &FunctionsTest::abs, @@ -91,7 +97,6 @@ FunctionsTest::FunctionsTest() { &FunctionsTest::sqrt, &FunctionsTest::sqrtInverted, - &FunctionsTest::clamp, &FunctionsTest::lerp, &FunctionsTest::lerpInverted, &FunctionsTest::fma, @@ -147,6 +152,30 @@ void FunctionsTest::minmax() { CORRADE_COMPARE_AS(Math::minmax(b, a), expectedVector, std::pair); } +void FunctionsTest::clamp() { + CORRADE_COMPARE(Math::clamp(0.5f, -1.0f, 5.0f), 0.5f); + CORRADE_COMPARE(Math::clamp(-1.6f, -1.0f, 5.0f), -1.0f); + CORRADE_COMPARE(Math::clamp(9.5f, -1.0f, 5.0f), 5.0f); + + CORRADE_COMPARE(Math::clamp(Vector3(0.5f, -1.6f, 9.5f), -1.0f, 5.0f), Vector3(0.5f, -1.0f, 5.0f)); +} + +void FunctionsTest::nanPropagation() { + constexpr const Float NaN = std::numeric_limits::quiet_NaN(); + + CORRADE_COMPARE(Math::min(NaN, 5.0f), NaN); + CORRADE_COMPARE(Math::min(Vector2{NaN, 6.0f}, Vector2{5.0f})[0], NaN); + CORRADE_COMPARE(Math::min(Vector2{NaN, 6.0f}, Vector2{5.0f})[1], 5.0f); + + CORRADE_COMPARE(Math::max(NaN, 5.0f), NaN); + CORRADE_COMPARE(Math::max(Vector2{NaN, 4.0f}, Vector2{5.0f})[0], NaN); + CORRADE_COMPARE(Math::max(Vector2{NaN, 4.0f}, Vector2{5.0f})[1], 5.0f); + + CORRADE_COMPARE(Math::clamp(NaN, 2.0f, 6.0f), NaN); + CORRADE_COMPARE(Math::clamp(Vector2{NaN, 1.0f}, 2.0f, 6.0f)[0], NaN); + CORRADE_COMPARE(Math::clamp(Vector2{NaN, 1.0f}, 2.0f, 6.0f)[1], 2.0f); +} + void FunctionsTest::sign() { CORRADE_COMPARE(Math::sign(3516), 1); CORRADE_COMPARE(Math::sign(0.0f), 0.0f); @@ -194,14 +223,6 @@ void FunctionsTest::sqrtInverted() { CORRADE_COMPARE(Math::sqrtInverted(Vector3(1.0f, 4.0f, 16.0f)), Vector3(1.0f, 0.5f, 0.25f)); } -void FunctionsTest::clamp() { - CORRADE_COMPARE(Math::clamp(0.5f, -1.0f, 5.0f), 0.5f); - CORRADE_COMPARE(Math::clamp(-1.6f, -1.0f, 5.0f), -1.0f); - CORRADE_COMPARE(Math::clamp(9.5f, -1.0f, 5.0f), 5.0f); - - CORRADE_COMPARE(Math::clamp(Vector3(0.5f, -1.6f, 9.5f), -1.0f, 5.0f), Vector3(0.5f, -1.0f, 5.0f)); -} - void FunctionsTest::lerp() { /* Floating-point / integral scalar */ CORRADE_COMPARE(Math::lerp(2.0f, 5.0f, 0.5f), 3.5f);