diff --git a/doc/changelog.dox b/doc/changelog.dox index d9e261570..55b1922d7 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -160,6 +160,9 @@ See also: @ref Math::IsFloatingPoint and @ref Math::IsUnitless type traits and a @ref Math::UnderlyingTypeOf utility - Added batch versions of @ref Math::isInf() and @ref Math::isNan() +- @ref Math::equal() and @ref Math::notEqual() for component-wise comparison + of @ref Math::Vector, as the equality/non-equality operators return a + single @cpp bool @ce @subsubsection changelog-latest-new-meshtools MeshTools library diff --git a/src/Magnum/Math/Test/VectorTest.cpp b/src/Magnum/Math/Test/VectorTest.cpp index 23798b812..61bbc38bc 100644 --- a/src/Magnum/Math/Test/VectorTest.cpp +++ b/src/Magnum/Math/Test/VectorTest.cpp @@ -343,6 +343,16 @@ void VectorTest::compare() { void VectorTest::compareComponentWise() { typedef BoolVector<3> BoolVector3; + typedef BoolVector<4> BoolVector4; + + Vector4 a{1.0f, -3.5f, 5.0f, -10.0f}; + Vector4 b{1.0f + TypeTraits::epsilon()/2, -3.5f, 5.0f - TypeTraits::epsilon()*2, -10.0f}; + Vector4 c{1.0f + TypeTraits::epsilon()*2, -3.5f, 5.0f - TypeTraits::epsilon()*10, -10.0f}; + CORRADE_COMPARE(equal(a, b), BoolVector4{0xf}); + CORRADE_COMPARE(equal(a, c), BoolVector4{0xa}); + CORRADE_COMPARE(notEqual(a, b), BoolVector4{0x0}); + CORRADE_COMPARE(notEqual(a, c), BoolVector4{0x5}); + CORRADE_COMPARE(Vector3(1.0f, -1.0f, 5.0f) < Vector3(1.1f, -1.0f, 3.0f), BoolVector3(0x1)); CORRADE_COMPARE(Vector3(1.0f, -1.0f, 5.0f) <= Vector3(1.1f, -1.0f, 3.0f), BoolVector3(0x3)); CORRADE_COMPARE(Vector3(1.0f, -1.0f, 5.0f) >= Vector3(1.1f, -1.0f, 3.0f), BoolVector3(0x6)); diff --git a/src/Magnum/Math/Vector.h b/src/Magnum/Math/Vector.h index 1b303ddd8..5ba85f280 100644 --- a/src/Magnum/Math/Vector.h +++ b/src/Magnum/Math/Vector.h @@ -48,13 +48,13 @@ namespace Magnum { namespace Math { template inline typename std::enable_if::value, bool>::type isNan(T value) { return std::isnan(UnderlyingTypeOf(value)); } - -template constexpr typename std::enable_if::value, T>::type min(T a, T b) { - return b < a ? b : a; +/* Keeping the same parameter names as in Functions.h so the note about + NaN propagation works here too */ +template constexpr typename std::enable_if::value, T>::type min(T value, T min) { + return min < value ? min : value; } - -template constexpr typename std::enable_if::value, T>::type max(T a, T b) { - return a < b ? b : a; +template constexpr typename std::enable_if::value, T>::type max(T value, T max) { + return value < max ? max : value; } #endif @@ -237,7 +237,11 @@ template class Vector { T& operator[](std::size_t pos) { return _data[pos]; } constexpr T operator[](std::size_t pos) const { return _data[pos]; } /**< @overload */ - /** @brief Equality comparison */ + /** + * @brief Equality comparison + * + * @see @ref Math::equal() + */ bool operator==(const Vector& other) const { for(std::size_t i = 0; i != size; ++i) if(!TypeTraits::equals(_data[i], other._data[i])) return false; @@ -245,7 +249,11 @@ template class Vector { return true; } - /** @brief Non-equality comparison */ + /** + * @brief Non-equality comparison + * + * @see @ref Math::notEqual() + */ bool operator!=(const Vector& other) const { return !operator==(other); } @@ -640,6 +648,11 @@ template class Vector { template friend class Matrix; template friend struct Implementation::MatrixDeterminant; + /* So the out-of-class comparators can access data directly to avoid + function call overhead */ + template friend BoolVector equal(const Vector&, const Vector&); + template friend BoolVector notEqual(const Vector&, const Vector&); + /* Implementation for Vector::Vector(const Vector&) */ template constexpr explicit Vector(Implementation::Sequence, const Vector& vector) noexcept: _data{T(vector._data[sequence])...} {} @@ -655,6 +668,36 @@ template class Vector { } }; +/** @relatesalso Vector +@brief Component-wise equality comparison + +Unlike @ref Vector::operator==() returns a @ref BoolVector instead of a single +value. +*/ +template inline BoolVector equal(const Vector& a, const Vector& b) { + BoolVector out; + + for(std::size_t i = 0; i != size; ++i) + out.set(i, TypeTraits::equals(a._data[i], b._data[i])); + + return out; +} + +/** @relatesalso Vector +@brief Component-wise non-equality comparison + +Unlike @ref Vector::operator!=() returns a @ref BoolVector instead of a single +value. +*/ +template inline BoolVector notEqual(const Vector& a, const Vector& b) { + BoolVector out; + + for(std::size_t i = 0; i != size; ++i) + out.set(i, !TypeTraits::equals(a._data[i], b._data[i])); + + return out; +} + /** @relates Vector @brief Multiply a scalar with a vector