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);