diff --git a/src/Magnum/DebugTools/Implementation/CapsuleRendererTransformation.h b/src/Magnum/DebugTools/Implementation/CapsuleRendererTransformation.h index 09230632c..7064c4069 100644 --- a/src/Magnum/DebugTools/Implementation/CapsuleRendererTransformation.h +++ b/src/Magnum/DebugTools/Implementation/CapsuleRendererTransformation.h @@ -74,7 +74,7 @@ template<> std::array capsuleRendererTransformation<3>(const Vector3 Vector3 capDistance; if(length >= Math::TypeTraits::epsilon()) { const Vector3 directionNormalized = direction/length; - const Float dot = Vector3::dot(directionNormalized, Vector3::zAxis()); + const Float dot = Math::dot(directionNormalized, Vector3::zAxis()); /* Direction is parallel to Z axis, special rotation case */ if(Math::abs(dot) > 1.0f - Math::TypeTraits::epsilon()) { @@ -85,8 +85,8 @@ template<> std::array capsuleRendererTransformation<3>(const Vector3 /* Common case */ } else { rotation.up() = directionNormalized; - rotation.right() = Vector3::cross(rotation.up(), Vector3::zAxis()).normalized(); - rotation.backward() = Vector3::cross(rotation.right(), rotation.up()); + rotation.right() = Math::cross(rotation.up(), Vector3::zAxis()).normalized(); + rotation.backward() = Math::cross(rotation.right(), rotation.up()); CORRADE_INTERNAL_ASSERT(rotation.up().isNormalized() && rotation.backward().isNormalized()); } diff --git a/src/Magnum/DebugTools/Implementation/CylinderRendererTransformation.h b/src/Magnum/DebugTools/Implementation/CylinderRendererTransformation.h index 479cba460..aec563175 100644 --- a/src/Magnum/DebugTools/Implementation/CylinderRendererTransformation.h +++ b/src/Magnum/DebugTools/Implementation/CylinderRendererTransformation.h @@ -63,7 +63,7 @@ template<> Matrix4 cylinderRendererTransformation<3>(const Vector3& a, const Vec Matrix4 rotation; if(length >= Math::TypeTraits::epsilon()) { const Vector3 directionNormalized = direction/length; - const Float dot = Vector3::dot(directionNormalized, Vector3::zAxis()); + const Float dot = Math::dot(directionNormalized, Vector3::zAxis()); /* Direction is parallel to Z axis, special rotation case */ if(Math::abs(dot) > 1.0f - Math::TypeTraits::epsilon()) { @@ -74,8 +74,8 @@ template<> Matrix4 cylinderRendererTransformation<3>(const Vector3& a, const Vec /* Common case */ } else { rotation.up() = directionNormalized; - rotation.right() = Vector3::cross(rotation.up(), Vector3::zAxis()).normalized(); - rotation.backward() = Vector3::cross(rotation.right(), rotation.up()); + rotation.right() = Math::cross(rotation.up(), Vector3::zAxis()).normalized(); + rotation.backward() = Math::cross(rotation.right(), rotation.up()); CORRADE_INTERNAL_ASSERT(rotation.up().isNormalized() && rotation.backward().isNormalized()); } } diff --git a/src/Magnum/DebugTools/Implementation/ForceRendererTransformation.h b/src/Magnum/DebugTools/Implementation/ForceRendererTransformation.h index a8d0070da..a446e7f76 100644 --- a/src/Magnum/DebugTools/Implementation/ForceRendererTransformation.h +++ b/src/Magnum/DebugTools/Implementation/ForceRendererTransformation.h @@ -47,17 +47,17 @@ template<> Matrix4 forceRendererTransformation<3>(const Vector3& forcePosition, if(forceLength < Math::TypeTraits::epsilon()) return translation*Matrix4::scaling(Vector3(0.0f)); - const Float dot = Vector3::dot(force/forceLength, Vector3::xAxis()); + const Float dot = Math::dot(force/forceLength, Vector3::xAxis()); /* Force is parallel to X axis, just scaling */ if(Math::abs(dot) > 1.0f - Math::TypeTraits::epsilon()) return translation*Matrix4::scaling({Math::sign(dot)*forceLength, forceLength, forceLength}); /* Normal of plane going through force vector and X axis vector */ - const Vector3 normal = Vector3::cross(Vector3::xAxis(), force).normalized(); + const Vector3 normal = Math::cross(Vector3::xAxis(), force).normalized(); /* Third base vector, orthogonal to force and normal */ - const Vector3 binormal = Vector3::cross(normal, force/forceLength); + const Vector3 binormal = Math::cross(normal, force/forceLength); CORRADE_INTERNAL_ASSERT(binormal.isNormalized()); /* Transformation matrix from scaled base vectors and translation vector */ diff --git a/src/Magnum/DebugTools/Test/CapsuleRendererTest.cpp b/src/Magnum/DebugTools/Test/CapsuleRendererTest.cpp index 23bd3a001..94c4537fe 100644 --- a/src/Magnum/DebugTools/Test/CapsuleRendererTest.cpp +++ b/src/Magnum/DebugTools/Test/CapsuleRendererTest.cpp @@ -82,7 +82,7 @@ void CapsuleRendererTest::common2D() { CORRADE_COMPARE(transformation[2].right(), right); /* Orthogonality */ - CORRADE_COMPARE(Vector2::dot(transformation[0].up(), transformation[0].right()), 0.0f); + CORRADE_COMPARE(Math::dot(transformation[0].up(), transformation[0].right()), 0.0f); const Vector2 capDistance = up.resized(3.5f); CORRADE_COMPARE(transformation[0].translation(), a+capDistance); @@ -162,9 +162,9 @@ void CapsuleRendererTest::common3D() { CORRADE_COMPARE(transformation[2].backward(), backward); /* Orthogonality */ - CORRADE_COMPARE(Vector3::dot(transformation[0].up(), transformation[0].right()), 0.0f); - CORRADE_COMPARE(Vector3::dot(transformation[0].up(), transformation[0].backward()), 0.0f); - CORRADE_COMPARE(Vector3::dot(transformation[0].right(), transformation[0].backward()), 0.0f); + CORRADE_COMPARE(Math::dot(transformation[0].up(), transformation[0].right()), 0.0f); + CORRADE_COMPARE(Math::dot(transformation[0].up(), transformation[0].backward()), 0.0f); + CORRADE_COMPARE(Math::dot(transformation[0].right(), transformation[0].backward()), 0.0f); const Vector3 capDistance = up.resized(3.5f); CORRADE_COMPARE(transformation[0].translation(), a+capDistance); diff --git a/src/Magnum/DebugTools/Test/CylinderRendererTest.cpp b/src/Magnum/DebugTools/Test/CylinderRendererTest.cpp index 807329bf5..eebf18980 100644 --- a/src/Magnum/DebugTools/Test/CylinderRendererTest.cpp +++ b/src/Magnum/DebugTools/Test/CylinderRendererTest.cpp @@ -67,7 +67,7 @@ void CylinderRendererTest::common2D() { /* Rotation + scaling, test orthogonality */ CORRADE_COMPARE(transformation.up(), Vector2(3.5f, -2.0f)); CORRADE_COMPARE(transformation.right(), Vector2(4.0f, 7.0f).resized(3.5f)); - CORRADE_COMPARE(Vector2::dot(transformation.up(), transformation.right()), 0.0f); + CORRADE_COMPARE(Math::dot(transformation.up(), transformation.right()), 0.0f); CORRADE_COMPARE(transformation.translation(), 0.5f*(a + b)); } @@ -113,9 +113,9 @@ void CylinderRendererTest::common3D() { CORRADE_COMPARE(transformation.backward(), Vector3(9.625f, -5.5f, 16.25f).resized(3.5f)); /* Orthogonality */ - CORRADE_COMPARE(Vector3::dot(transformation.up(), transformation.right()), 0.0f); - CORRADE_COMPARE(Vector3::dot(transformation.up(), transformation.backward()), 0.0f); - CORRADE_COMPARE(Vector3::dot(transformation.right(), transformation.backward()), 0.0f); + CORRADE_COMPARE(Math::dot(transformation.up(), transformation.right()), 0.0f); + CORRADE_COMPARE(Math::dot(transformation.up(), transformation.backward()), 0.0f); + CORRADE_COMPARE(Math::dot(transformation.right(), transformation.backward()), 0.0f); CORRADE_COMPARE(transformation.translation(), 0.5f*(a + b)); } diff --git a/src/Magnum/DebugTools/Test/ForceRendererTest.cpp b/src/Magnum/DebugTools/Test/ForceRendererTest.cpp index ef3f50c6f..c07c3a7df 100644 --- a/src/Magnum/DebugTools/Test/ForceRendererTest.cpp +++ b/src/Magnum/DebugTools/Test/ForceRendererTest.cpp @@ -68,7 +68,7 @@ void ForceRendererTest::common2D() { CORRADE_COMPARE(m.up().length(), force.length()); /* All vectors are orthogonal */ - CORRADE_COMPARE(Vector2::dot(m.right(), m.up()), 0.0f); + CORRADE_COMPARE(Math::dot(m.right(), m.up()), 0.0f); } void ForceRendererTest::zero3D() { @@ -99,10 +99,10 @@ void ForceRendererTest::arbitrary3D() { CORRADE_COMPARE(m.backward().length(), force.length()); /* All vectors are orthogonal */ - CORRADE_COMPARE(Vector3::dot(m.right(), m.up()), 0.0f); - CORRADE_COMPARE(Vector3::dot(m.right(), m.backward()), 0.0f); + CORRADE_COMPARE(Math::dot(m.right(), m.up()), 0.0f); + CORRADE_COMPARE(Math::dot(m.right(), m.backward()), 0.0f); /** @todo This shouldn't be too different */ - CORRADE_VERIFY(Math::abs(Vector3::dot(m.up(), m.backward())) < Math::TypeTraits::epsilon()); + CORRADE_VERIFY(Math::abs(Math::dot(m.up(), m.backward())) < Math::TypeTraits::epsilon()); } }}}} diff --git a/src/Magnum/Math/Algorithms/Test/GramSchmidtTest.cpp b/src/Magnum/Math/Algorithms/Test/GramSchmidtTest.cpp index 386cddc6f..92c35a476 100644 --- a/src/Magnum/Math/Algorithms/Test/GramSchmidtTest.cpp +++ b/src/Magnum/Math/Algorithms/Test/GramSchmidtTest.cpp @@ -57,9 +57,9 @@ void GramSchmidtTest::orthogonalize() { /* (The vectors don't need to unit length) */ /* Verify the vectors are orthogonal */ - CORRADE_COMPARE(Vector3::dot(orthogonalized[0], orthogonalized[1]), 0.0f); - CORRADE_COMPARE(Vector3::dot(orthogonalized[0], orthogonalized[2]), 0.0f); - CORRADE_COMPARE(Vector3::dot(orthogonalized[1], orthogonalized[2]), 0.0f); + CORRADE_COMPARE(dot(orthogonalized[0], orthogonalized[1]), 0.0f); + CORRADE_COMPARE(dot(orthogonalized[0], orthogonalized[2]), 0.0f); + CORRADE_COMPARE(dot(orthogonalized[1], orthogonalized[2]), 0.0f); /* Just to be sure */ Matrix3x3 expected(Vector3( 3.0f, 5.0f, 1.0f), @@ -84,9 +84,9 @@ void GramSchmidtTest::orthonormalize() { CORRADE_COMPARE(orthonormalized[2].length(), 1.0f); /* Verify the vectors are orthogonal */ - CORRADE_COMPARE(Vector3::dot(orthonormalized[0], orthonormalized[1]), 0.0f); - CORRADE_COMPARE(Vector3::dot(orthonormalized[0], orthonormalized[2]), 0.0f); - CORRADE_COMPARE(Vector3::dot(orthonormalized[1], orthonormalized[2]), 0.0f); + CORRADE_COMPARE(dot(orthonormalized[0], orthonormalized[1]), 0.0f); + CORRADE_COMPARE(dot(orthonormalized[0], orthonormalized[2]), 0.0f); + CORRADE_COMPARE(dot(orthonormalized[1], orthonormalized[2]), 0.0f); /* Just to be sure */ Matrix3x3 expected(Vector3( 0.3030458f, 0.5050763f, 0.8081220f), diff --git a/src/Magnum/Math/Complex.h b/src/Magnum/Math/Complex.h index efd8a8c43..5372469f0 100644 --- a/src/Magnum/Math/Complex.h +++ b/src/Magnum/Math/Complex.h @@ -45,6 +45,34 @@ namespace Implementation { } } +/** @relatesalso Complex +@brief Dot product of two complex numbers + +@f[ + c_0 \cdot c_1 = a_0 a_1 + b_0 b_1 +@f] +@see @ref Complex::dot() const +*/ +template inline T dot(const Complex& a, const Complex& b) { + return a.real()*b.real() + a.imaginary()*b.imaginary(); +} + +/** @relatesalso Complex +@brief Angle between normalized complex numbers + +Expects that both complex numbers are normalized. @f[ + \theta = acos \left( \frac{Re(c_0 \cdot c_1))}{|c_0| |c_1|} \right) = acos (a_0 a_1 + b_0 b_1) +@f] +@see @ref Complex::isNormalized(), + @ref angle(const Quaternion&, const Quaternion&), + @ref angle(const Vector&, const Vector&) +*/ +template inline Rad angle(const Complex& normalizedA, const Complex& normalizedB) { + CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), + "Math::angle(): complex numbers must be normalized", {}); + return Rad(std::acos(normalizedA.real()*normalizedB.real() + normalizedA.imaginary()*normalizedB.imaginary())); +} + /** @brief Complex number @tparam T Data type @@ -56,32 +84,25 @@ template class Complex { public: typedef T Type; /**< @brief Underlying data type */ + #ifdef MAGNUM_BUILD_DEPRECATED /** - * @brief Dot product - * - * @f[ - * c_0 \cdot c_1 = a_0 a_1 + b_0 b_1 - * @f] - * @see @ref Complex::dot() const + * @copybrief Math::dot(const Complex&, const Complex&) + * @deprecated Use @ref Math::dot(const Complex&, const Complex&) + * instead. */ - static T dot(const Complex& a, const Complex& b) { - return a._real*b._real + a._imaginary*b._imaginary; + CORRADE_DEPRECATED("use Math::dot() instead") static T dot(const Complex& a, const Complex& b) { + return Math::dot(a, b); } /** - * @brief Angle between normalized complex numbers - * - * Expects that both complex numbers are normalized. @f[ - * \theta = acos \left( \frac{Re(c_0 \cdot c_1))}{|c_0| |c_1|} \right) = acos (a_0 a_1 + b_0 b_1) - * @f] - * @see @ref isNormalized(), @ref Quaternion::angle(), - * @ref Vector::angle() + * @copybrief Math::angle(const Complex&, const Complex&) + * @deprecated Use @ref Math::angle(const Complex&, const Complex&) + * instead. */ - static Rad angle(const Complex& normalizedA, const Complex& normalizedB) { - CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), - "Math::Complex::angle(): complex numbers must be normalized", {}); - return Rad(std::acos(normalizedA._real*normalizedB._real + normalizedA._imaginary*normalizedB._imaginary)); + CORRADE_DEPRECATED("use Math::angle() instead") static Rad angle(const Complex& normalizedA, const Complex& normalizedB) { + return Math::angle(normalizedA, normalizedB); } + #endif /** * @brief Rotation complex number @@ -328,9 +349,7 @@ template class Complex { * @f] * @see @ref dot(const Complex&, const Complex&), @ref isNormalized() */ - T dot() const { - return dot(*this, *this); - } + T dot() const { return Math::dot(*this, *this); } /** * @brief Complex number length diff --git a/src/Magnum/Math/DualQuaternion.h b/src/Magnum/Math/DualQuaternion.h index 3f2b34a28..694e080e1 100644 --- a/src/Magnum/Math/DualQuaternion.h +++ b/src/Magnum/Math/DualQuaternion.h @@ -233,7 +233,7 @@ template class DualQuaternion: public Dual> { * @f] */ Dual lengthSquared() const { - return {Dual>::real().dot(), T(2)*Quaternion::dot(Dual>::real(), Dual>::dual())}; + return {Dual>::real().dot(), T(2)*dot(Dual>::real(), Dual>::dual())}; } /** diff --git a/src/Magnum/Math/Functions.h b/src/Magnum/Math/Functions.h index 73054d02d..c6e7ae14e 100644 --- a/src/Magnum/Math/Functions.h +++ b/src/Magnum/Math/Functions.h @@ -358,9 +358,7 @@ template Vector sqrtInverted(const Vector&, const Quaternion&, T) */ #ifdef DOXYGEN_GENERATING_OUTPUT template inline T lerp(const T& a, const T& b, U t); diff --git a/src/Magnum/Math/Geometry/Distance.h b/src/Magnum/Math/Geometry/Distance.h index 5d3c31a05..7c514990b 100644 --- a/src/Magnum/Math/Geometry/Distance.h +++ b/src/Magnum/Math/Geometry/Distance.h @@ -46,7 +46,7 @@ class Distance { * @param point Point * * The distance *d* is computed from point **p** and line defined by **a** - * and **b** using @ref Vector2::cross() "perp-dot product": @f[ + * and **b** using @ref cross(const Vector2&, const Vector2&) "perp-dot product": @f[ * d = \frac{|(\boldsymbol b - \boldsymbol a)_\bot \cdot (\boldsymbol a - \boldsymbol p)|} {|\boldsymbol b - \boldsymbol a|} * @f] * Source: http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html @@ -54,7 +54,7 @@ class Distance { */ template static T linePoint(const Vector2& a, const Vector2& b, const Vector2& point) { const Vector2 bMinusA = b - a; - return std::abs(Vector2::cross(bMinusA, a - point))/bMinusA.length(); + return std::abs(cross(bMinusA, a - point))/bMinusA.length(); } /** @@ -70,7 +70,7 @@ class Distance { */ template static T linePointSquared(const Vector2& a, const Vector2& b, const Vector2& point) { const Vector2 bMinusA = b - a; - return Math::pow<2>(Vector2::cross(bMinusA, a - point))/bMinusA.dot(); + return Math::pow<2>(cross(bMinusA, a - point))/bMinusA.dot(); } /** @@ -80,7 +80,7 @@ class Distance { * @param point Point * * The distance *d* is computed from point **p** and line defined by **a** - * and **b** using @ref Vector3::cross() "cross product": @f[ + * and **b** using @ref cross(const Vector3&, const Vector3&) "cross product": @f[ * d = \frac{|(\boldsymbol p - \boldsymbol a) \times (\boldsymbol p - \boldsymbol b)|} * {|\boldsymbol b - \boldsymbol a|} * @f] @@ -99,7 +99,7 @@ class Distance { * compute the square root. */ template static T linePointSquared(const Vector3& a, const Vector3& b, const Vector3& point) { - return Vector3::cross(point - a, point - b).dot()/(b - a).dot(); + return cross(point - a, point - b).dot()/(b - a).dot(); } /** @@ -181,7 +181,7 @@ template T Distance::lineSegmentPoint(const Vector2& a, const Vector return std::sqrt(pointDistanceB); /* Between A and B */ - return std::abs(Vector2::cross(bMinusA, -pointMinusA))/std::sqrt(bDistanceA); + return std::abs(cross(bMinusA, -pointMinusA))/std::sqrt(bDistanceA); } template T Distance::lineSegmentPointSquared(const Vector2& a, const Vector2& b, const Vector2& point) { @@ -201,7 +201,7 @@ template T Distance::lineSegmentPointSquared(const Vector2& a, const return pointDistanceB; /* Between A and B */ - return Math::pow<2>(Vector2::cross(bMinusA, -pointMinusA))/bDistanceA; + return Math::pow<2>(cross(bMinusA, -pointMinusA))/bDistanceA; } template T Distance::lineSegmentPointSquared(const Vector3& a, const Vector3& b, const Vector3& point) { @@ -220,7 +220,7 @@ template T Distance::lineSegmentPointSquared(const Vector3& a, const return pointDistanceB; /* Between A and B */ - return Vector3::cross(pointMinusA, pointMinusB).dot()/bDistanceA; + return cross(pointMinusA, pointMinusB).dot()/bDistanceA; } }}} diff --git a/src/Magnum/Math/Geometry/Intersection.h b/src/Magnum/Math/Geometry/Intersection.h index 87a188321..78ba97b9c 100644 --- a/src/Magnum/Math/Geometry/Intersection.h +++ b/src/Magnum/Math/Geometry/Intersection.h @@ -72,9 +72,8 @@ class Intersection { */ template static std::pair lineSegmentLineSegment(const Vector2& p, const Vector2& r, const Vector2& q, const Vector2& s) { const Vector2 qp = q - p; - const T rs = Vector2::cross(r, s); - return {Vector2::cross(qp, s)/rs, - Vector2::cross(qp, r)/rs}; + const T rs = cross(r, s); + return {cross(qp, s)/rs, cross(qp, r)/rs}; } /** @@ -92,7 +91,7 @@ class Intersection { * Unlike @ref lineSegmentLineSegment() computes only **t**. */ template static T lineSegmentLine(const Vector2& p, const Vector2& r, const Vector2& q, const Vector2& s) { - return Vector2::cross(q - p, s)/Vector2::cross(r, s); + return cross(q - p, s)/cross(r, s); } /** @@ -121,8 +120,8 @@ class Intersection { * @f] */ template static T planeLine(const Vector3& planePosition, const Vector3& planeNormal, const Vector3& p, const Vector3& r) { - const T f = Vector3::dot(planePosition, planeNormal); - return (f-Vector3::dot(planeNormal, p))/Vector3::dot(planeNormal, r); + const T f = dot(planePosition, planeNormal); + return (f-dot(planeNormal, p))/dot(planeNormal, r); } }; diff --git a/src/Magnum/Math/Matrix.h b/src/Magnum/Math/Matrix.h index a124925c2..380df95e4 100644 --- a/src/Magnum/Math/Matrix.h +++ b/src/Magnum/Math/Matrix.h @@ -284,7 +284,7 @@ template bool Matrix::isOrthogonal() const { /* Orthogonality */ for(std::size_t i = 0; i != size-1; ++i) for(std::size_t j = i+1; j != size; ++j) - if(Vector::dot((*this)[i], (*this)[j]) > TypeTraits::epsilon()) + if(dot((*this)[i], (*this)[j]) > TypeTraits::epsilon()) return false; return true; diff --git a/src/Magnum/Math/Matrix4.h b/src/Magnum/Math/Matrix4.h index 2b2395af4..d38d34eea 100644 --- a/src/Magnum/Math/Matrix4.h +++ b/src/Magnum/Math/Matrix4.h @@ -539,8 +539,8 @@ template Matrix4 Matrix4::perspectiveProjection(const Vector2& template Matrix4 Matrix4::lookAt(const Vector3& eye, const Vector3& target, const Vector3& up) { const Vector3 backward = (eye - target).normalized(); - const Vector3 right = Vector3::cross(up, backward).normalized(); - const Vector3 realUp = Vector3::cross(backward, right); + const Vector3 right = cross(up, backward).normalized(); + const Vector3 realUp = cross(backward, right); return {{ right, T(0)}, { realUp, T(0)}, diff --git a/src/Magnum/Math/Quaternion.h b/src/Magnum/Math/Quaternion.h index 0c309400f..d13e15c44 100644 --- a/src/Magnum/Math/Quaternion.h +++ b/src/Magnum/Math/Quaternion.h @@ -39,6 +39,79 @@ namespace Magnum { namespace Math { +/** @relatesalso Quaternion +@brief Dot product between two quaternions + +@f[ + p \cdot q = \boldsymbol p_V \cdot \boldsymbol q_V + p_S q_S +@f] +@see @ref Quaternion::dot() const +*/ +template inline T dot(const Quaternion& a, const Quaternion& b) { + return dot(a.vector(), b.vector()) + a.scalar()*b.scalar(); +} + +namespace Implementation { + /* Used in angle() and slerp() (no assertions) */ + template inline Rad angle(const Quaternion& normalizedA, const Quaternion& normalizedB) { + return Rad{std::acos(dot(normalizedA, normalizedB))}; + } +} + +/** @relatesalso Quaternion +@brief Angle between normalized quaternions + +Expects that both quaternions are normalized. @f[ + \theta = acos \left( \frac{p \cdot q}{|p| |q|} \right) = acos(p \cdot q) +@f] +@see @ref Quaternion::isNormalized(), + @ref angle(const Complex&, const Complex&), + @ref angle(const Vector&, const Vector&) + */ +template inline Rad angle(const Quaternion& normalizedA, const Quaternion& normalizedB) { + CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), + "Math::angle(): quaternions must be normalized", {}); + return Implementation::angle(normalizedA, normalizedB); +} + +/** @relatesalso Quaternion +@brief Linear interpolation of two quaternions +@param normalizedA First quaternion +@param normalizedB Second quaternion +@param t Interpolation phase (from range @f$ [0; 1] @f$) + +Expects that both quaternions are normalized. @f[ + q_{LERP} = \frac{(1 - t) q_A + t q_B}{|(1 - t) q_A + t q_B|} +@f] +@see @ref Quaternion::isNormalized(), @ref slerp(const Quaternion&, const Quaternion&, T), + @ref lerp(const T&, const T&, U) + */ +template inline Quaternion lerp(const Quaternion& normalizedA, const Quaternion& normalizedB, T t) { + CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), + "Math::lerp(): quaternions must be normalized", {}); + return ((T(1) - t)*normalizedA + t*normalizedB).normalized(); +} + +/** @relatesalso Quaternion +@brief Spherical linear interpolation of two quaternions +@param normalizedA First quaternion +@param normalizedB Second quaternion +@param t Interpolation phase (from range @f$ [0; 1] @f$) + +Expects that both quaternions are normalized. @f[ + q_{SLERP} = \frac{sin((1 - t) \theta) q_A + sin(t \theta) q_B}{sin \theta} + ~ ~ ~ ~ ~ ~ ~ + \theta = acos \left( \frac{q_A \cdot q_B}{|q_A| \cdot |q_B|} \right) = acos(q_A \cdot q_B) +@f] +@see @ref Quaternion::isNormalized(), @ref lerp(const Quaternion&, const Quaternion&, T) + */ +template inline Quaternion slerp(const Quaternion& normalizedA, const Quaternion& normalizedB, T t) { + CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), + "Math::slerp(): quaternions must be normalized", {}); + const T a = Implementation::angle(normalizedA, normalizedB); + return (std::sin((T(1) - t)*a)*normalizedA + std::sin(t*a)*normalizedB)/std::sin(a); +} + /** @brief Quaternion @tparam T Underlying data type @@ -51,57 +124,43 @@ template class Quaternion { public: typedef T Type; /**< @brief Underlying data type */ + #ifdef MAGNUM_BUILD_DEPRECATED /** - * @brief Dot product - * - * @f[ - * p \cdot q = \boldsymbol p_V \cdot \boldsymbol q_V + p_S q_S - * @f] - * @see @ref dot() const + * @copybrief Math::dot(const Quaternion&, const Quaternion&) + * @deprecated Use @ref Math::dot(const Quaternion&, const Quaternion&) + * instead. */ - static T dot(const Quaternion& a, const Quaternion& b) { - /** @todo Use four-component SIMD implementation when available */ - return Vector3::dot(a.vector(), b.vector()) + a.scalar()*b.scalar(); + CORRADE_DEPRECATED("use Math::dot() instead") static T dot(const Quaternion& a, const Quaternion& b) { + return Math::dot(a, b); } /** - * @brief Angle between normalized quaternions - * - * Expects that both quaternions are normalized. @f[ - * \theta = acos \left( \frac{p \cdot q}{|p| |q|} \right) = acos(p \cdot q) - * @f] - * @see @ref isNormalized(), @ref Complex::angle(), - * @ref Vector::angle() + * @copybrief Math::angle(const Quaternion&, const Quaternion&) + * @deprecated Use @ref Math::angle(const Quaternion&, const Quaternion&) + * instead. */ - static Rad angle(const Quaternion& normalizedA, const Quaternion& normalizedB); + CORRADE_DEPRECATED("use Math::angle() instead") static Rad angle(const Quaternion& normalizedA, const Quaternion& normalizedB) { + return Math::angle(normalizedA, normalizedB); + } /** - * @brief Linear interpolation of two quaternions - * @param normalizedA First quaternion - * @param normalizedB Second quaternion - * @param t Interpolation phase (from range @f$ [0; 1] @f$) - * - * Expects that both quaternions are normalized. @f[ - * q_{LERP} = \frac{(1 - t) q_A + t q_B}{|(1 - t) q_A + t q_B|} - * @f] - * @see @ref isNormalized(), @ref slerp(), @ref Math::lerp() + * @copybrief Math::lerp(const Quaternion&, const Quaternion&, T) + * @deprecated Use @ref Math::lerp(const Quaternion&, const Quaternion&, T) + * instead. */ - static Quaternion lerp(const Quaternion& normalizedA, const Quaternion& normalizedB, T t); + CORRADE_DEPRECATED("use Math::lerp() instead") static Quaternion lerp(const Quaternion& normalizedA, const Quaternion& normalizedB, T t) { + return Math::lerp(normalizedA, normalizedB, t); + } /** - * @brief Spherical linear interpolation of two quaternions - * @param normalizedA First quaternion - * @param normalizedB Second quaternion - * @param t Interpolation phase (from range @f$ [0; 1] @f$) - * - * Expects that both quaternions are normalized. @f[ - * q_{SLERP} = \frac{sin((1 - t) \theta) q_A + sin(t \theta) q_B}{sin \theta} - * ~~~~~~~~~~ - * \theta = acos \left( \frac{q_A \cdot q_B}{|q_A| \cdot |q_B|} \right) = acos(q_A \cdot q_B) - * @f] - * @see @ref isNormalized(), @ref lerp() + * @copybrief Math::slerp(const Quaternion&, const Quaternion&, T) + * @deprecated Use @ref Math::slerp(const Quaternion&, const Quaternion&, T) + * instead. */ - static Quaternion slerp(const Quaternion& normalizedA, const Quaternion& normalizedB, T t); + CORRADE_DEPRECATED("use Math::slerp() instead") static Quaternion slerp(const Quaternion& normalizedA, const Quaternion& normalizedB, T t) { + return Math::slerp(normalizedA, normalizedB, t); + } + #endif /** * @brief Rotation quaternion @@ -331,7 +390,7 @@ template class Quaternion { * @see @ref isNormalized(), * @ref dot(const Quaternion&, const Quaternion&) */ - T dot() const { return dot(*this, *this); } + T dot() const { return Math::dot(*this, *this); } /** * @brief Quaternion length @@ -424,11 +483,6 @@ template class Quaternion { return value*value; } - /* Used in angle() and slerp() (no assertions) */ - static T angleInternal(const Quaternion& normalizedA, const Quaternion& normalizedB) { - return std::acos(dot(normalizedA, normalizedB)); - } - Vector3 _vector; T _scalar; }; @@ -463,16 +517,12 @@ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug deb return debug; } -/** @todoc Remove the workaround when Doxygen is really able to preprocessor */ - /* Explicit instantiation for commonly used types */ #ifndef DOXYGEN_GENERATING_OUTPUT -/** @privatesection */ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Quaternion&); #ifndef MAGNUM_TARGET_GLES extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Quaternion&); #endif -/** @endprivatesection */ #endif namespace Implementation { @@ -510,25 +560,6 @@ template Quaternion quaternionFromMatrix(const Matrix3x3& m) { } -template inline Rad Quaternion::angle(const Quaternion& normalizedA, const Quaternion& normalizedB) { - CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), - "Math::Quaternion::angle(): quaternions must be normalized", {}); - return Rad(angleInternal(normalizedA, normalizedB)); -} - -template inline Quaternion Quaternion::lerp(const Quaternion& normalizedA, const Quaternion& normalizedB, const T t) { - CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), - "Math::Quaternion::lerp(): quaternions must be normalized", {}); - return ((T(1) - t)*normalizedA + t*normalizedB).normalized(); -} - -template inline Quaternion Quaternion::slerp(const Quaternion& normalizedA, const Quaternion& normalizedB, const T t) { - CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), - "Math::Quaternion::slerp(): quaternions must be normalized", {}); - const T a = angleInternal(normalizedA, normalizedB); - return (std::sin((T(1) - t)*a)*normalizedA + std::sin(t*a)*normalizedB)/std::sin(a); -} - template inline Quaternion Quaternion::rotation(const Rad angle, const Vector3& normalizedAxis) { CORRADE_ASSERT(normalizedAxis.isNormalized(), "Math::Quaternion::rotation(): axis must be normalized", {}); @@ -565,8 +596,8 @@ template Matrix3x3 Quaternion::toMatrix() const { } template inline Quaternion Quaternion::operator*(const Quaternion& other) const { - return {_scalar*other._vector + other._scalar*_vector + Vector3::cross(_vector, other._vector), - _scalar*other._scalar - Vector3::dot(_vector, other._vector)}; + return {_scalar*other._vector + other._scalar*_vector + Math::cross(_vector, other._vector), + _scalar*other._scalar - Math::dot(_vector, other._vector)}; } template inline Quaternion Quaternion::invertedNormalized() const { @@ -576,8 +607,8 @@ template inline Quaternion Quaternion::invertedNormalized() const template inline Vector3 Quaternion::transformVectorNormalized(const Vector3& vector) const { CORRADE_ASSERT(isNormalized(), "Math::Quaternion::transformVectorNormalized(): quaternion must be normalized", {}); - const Vector3 t = T(2)*Vector3::cross(_vector, vector); - return vector + _scalar*t + Vector3::cross(_vector, t); + const Vector3 t = T(2)*Math::cross(_vector, vector); + return vector + _scalar*t + Math::cross(_vector, t); } }} diff --git a/src/Magnum/Math/Test/ComplexTest.cpp b/src/Magnum/Math/Test/ComplexTest.cpp index cd654a1cb..43ba7ce18 100644 --- a/src/Magnum/Math/Test/ComplexTest.cpp +++ b/src/Magnum/Math/Test/ComplexTest.cpp @@ -188,7 +188,7 @@ void ComplexTest::dot() { Complex a(5.0f, 3.0f); Complex b(6.0f, -7.0f); - CORRADE_COMPARE(Complex::dot(a, b), 9.0f); + CORRADE_COMPARE(Math::dot(a, b), 9.0f); } void ComplexTest::dotSelf() { @@ -240,18 +240,18 @@ void ComplexTest::invertedNormalized() { void ComplexTest::angle() { std::ostringstream o; Error::setOutput(&o); - Complex::angle(Complex(1.5f, -2.0f).normalized(), {-4.0f, 3.5f}); - CORRADE_COMPARE(o.str(), "Math::Complex::angle(): complex numbers must be normalized\n"); + Math::angle(Complex(1.5f, -2.0f).normalized(), {-4.0f, 3.5f}); + CORRADE_COMPARE(o.str(), "Math::angle(): complex numbers must be normalized\n"); o.str({}); - Complex::angle({1.5f, -2.0f}, Complex(-4.0f, 3.5f).normalized()); - CORRADE_COMPARE(o.str(), "Math::Complex::angle(): complex numbers must be normalized\n"); + Math::angle({1.5f, -2.0f}, Complex(-4.0f, 3.5f).normalized()); + CORRADE_COMPARE(o.str(), "Math::angle(): complex numbers must be normalized\n"); /* Verify also that the angle is the same as angle between 2D vectors */ - Rad angle = Complex::angle(Complex( 1.5f, -2.0f).normalized(), - Complex(-4.0f, 3.5f).normalized()); - CORRADE_COMPARE(angle, Vector2::angle(Vector2( 1.5f, -2.0f).normalized(), - Vector2(-4.0f, 3.5f).normalized())); + Rad angle = Math::angle(Complex( 1.5f, -2.0f).normalized(), + Complex(-4.0f, 3.5f).normalized()); + CORRADE_COMPARE(angle, Math::angle(Vector2( 1.5f, -2.0f).normalized(), + Vector2(-4.0f, 3.5f).normalized())); CORRADE_COMPARE(angle, Rad(2.933128f)); } diff --git a/src/Magnum/Math/Test/QuaternionTest.cpp b/src/Magnum/Math/Test/QuaternionTest.cpp index 479bb8342..3da43b1c7 100644 --- a/src/Magnum/Math/Test/QuaternionTest.cpp +++ b/src/Magnum/Math/Test/QuaternionTest.cpp @@ -184,7 +184,7 @@ void QuaternionTest::dot() { Quaternion a({ 1.0f, 3.0f, -2.0f}, -4.0f); Quaternion b({-0.5f, 1.5f, 3.0f}, 12.0f); - CORRADE_COMPARE(Quaternion::dot(a, b), -50.0f); + CORRADE_COMPARE(Math::dot(a, b), -50.0f); } void QuaternionTest::dotSelf() { @@ -260,18 +260,18 @@ void QuaternionTest::rotation() { void QuaternionTest::angle() { std::ostringstream o; Error::setOutput(&o); - Quaternion::angle(Quaternion({1.0f, 2.0f, -3.0f}, -4.0f).normalized(), {{4.0f, -3.0f, 2.0f}, -1.0f}); - CORRADE_COMPARE(o.str(), "Math::Quaternion::angle(): quaternions must be normalized\n"); + Math::angle(Quaternion({1.0f, 2.0f, -3.0f}, -4.0f).normalized(), {{4.0f, -3.0f, 2.0f}, -1.0f}); + CORRADE_COMPARE(o.str(), "Math::angle(): quaternions must be normalized\n"); o.str({}); - Quaternion::angle({{1.0f, 2.0f, -3.0f}, -4.0f}, Quaternion({4.0f, -3.0f, 2.0f}, -1.0f).normalized()); - CORRADE_COMPARE(o.str(), "Math::Quaternion::angle(): quaternions must be normalized\n"); + Math::angle({{1.0f, 2.0f, -3.0f}, -4.0f}, Quaternion({4.0f, -3.0f, 2.0f}, -1.0f).normalized()); + CORRADE_COMPARE(o.str(), "Math::angle(): quaternions must be normalized\n"); /* Verify also that the angle is the same as angle between 4D vectors */ - Rad angle = Quaternion::angle(Quaternion({1.0f, 2.0f, -3.0f}, -4.0f).normalized(), - Quaternion({4.0f, -3.0f, 2.0f}, -1.0f).normalized()); - CORRADE_COMPARE(angle, Vector4::angle(Vector4(1.0f, 2.0f, -3.0f, -4.0f).normalized(), - Vector4(4.0f, -3.0f, 2.0f, -1.0f).normalized())); + Rad angle = Math::angle(Quaternion({1.0f, 2.0f, -3.0f}, -4.0f).normalized(), + Quaternion({4.0f, -3.0f, 2.0f}, -1.0f).normalized()); + CORRADE_COMPARE(angle, Math::angle(Vector4(1.0f, 2.0f, -3.0f, -4.0f).normalized(), + Vector4(4.0f, -3.0f, 2.0f, -1.0f).normalized())); CORRADE_COMPARE(angle, Rad(1.704528f)); } @@ -308,14 +308,14 @@ void QuaternionTest::lerp() { std::ostringstream o; Corrade::Utility::Error::setOutput(&o); - Quaternion::lerp(a*3.0f, b, 0.35f); - CORRADE_COMPARE(o.str(), "Math::Quaternion::lerp(): quaternions must be normalized\n"); + Math::lerp(a*3.0f, b, 0.35f); + CORRADE_COMPARE(o.str(), "Math::lerp(): quaternions must be normalized\n"); o.str({}); - Quaternion::lerp(a, b*-3.0f, 0.35f); - CORRADE_COMPARE(o.str(), "Math::Quaternion::lerp(): quaternions must be normalized\n"); + Math::lerp(a, b*-3.0f, 0.35f); + CORRADE_COMPARE(o.str(), "Math::lerp(): quaternions must be normalized\n"); - Quaternion lerp = Quaternion::lerp(a, b, 0.35f); + Quaternion lerp = Math::lerp(a, b, 0.35f); CORRADE_COMPARE(lerp, Quaternion({0.119127f, 0.049134f, 0.049134f}, 0.990445f)); } @@ -326,14 +326,14 @@ void QuaternionTest::slerp() { std::ostringstream o; Corrade::Utility::Error::setOutput(&o); - Quaternion::slerp(a*3.0f, b, 0.35f); - CORRADE_COMPARE(o.str(), "Math::Quaternion::slerp(): quaternions must be normalized\n"); + Math::slerp(a*3.0f, b, 0.35f); + CORRADE_COMPARE(o.str(), "Math::slerp(): quaternions must be normalized\n"); o.str({}); - Quaternion::slerp(a, b*-3.0f, 0.35f); - CORRADE_COMPARE(o.str(), "Math::Quaternion::slerp(): quaternions must be normalized\n"); + Math::slerp(a, b*-3.0f, 0.35f); + CORRADE_COMPARE(o.str(), "Math::slerp(): quaternions must be normalized\n"); - Quaternion slerp = Quaternion::slerp(a, b, 0.35f); + Quaternion slerp = Math::slerp(a, b, 0.35f); CORRADE_COMPARE(slerp, Quaternion({0.1191653f, 0.0491109f, 0.0491109f}, 0.9904423f)); } diff --git a/src/Magnum/Math/Test/Vector2Test.cpp b/src/Magnum/Math/Test/Vector2Test.cpp index 61664c404..a2d62a9ed 100644 --- a/src/Magnum/Math/Test/Vector2Test.cpp +++ b/src/Magnum/Math/Test/Vector2Test.cpp @@ -27,7 +27,7 @@ #include #include -#include "Magnum/Math/Vector3.h" /* Vector3 used in Vector2::cross() */ +#include "Magnum/Math/Vector3.h" /* Vector3 used in Vector2Test::cross() */ struct Vec2 { float x, y; @@ -166,8 +166,8 @@ void Vector2Test::cross() { Vector2i a(1, -1); Vector2i b(4, 3); - CORRADE_COMPARE(Vector2i::cross(a, b), 7); - CORRADE_COMPARE(Vector3i::cross({a, 0}, {b, 0}), Vector3i(0, 0, Vector2i::cross(a, b))); + CORRADE_COMPARE(Math::cross(a, b), 7); + CORRADE_COMPARE(Math::cross({a, 0}, {b, 0}), Vector3i(0, 0, Math::cross(a, b))); } void Vector2Test::axes() { @@ -187,7 +187,7 @@ void Vector2Test::scales() { void Vector2Test::perpendicular() { const Vector2 a(0.5f, -15.0f); CORRADE_COMPARE(a.perpendicular(), Vector2(15.0f, 0.5f)); - CORRADE_COMPARE(Vector2::dot(a.perpendicular(), a), 0.0f); + CORRADE_COMPARE(dot(a.perpendicular(), a), 0.0f); CORRADE_COMPARE(Vector2::xAxis().perpendicular(), Vector2::yAxis()); } diff --git a/src/Magnum/Math/Test/Vector3Test.cpp b/src/Magnum/Math/Test/Vector3Test.cpp index 9c32093d3..b7859cf00 100644 --- a/src/Magnum/Math/Test/Vector3Test.cpp +++ b/src/Magnum/Math/Test/Vector3Test.cpp @@ -183,7 +183,7 @@ void Vector3Test::cross() { Vector3i a(1, -1, 1); Vector3i b(4, 3, 7); - CORRADE_COMPARE(Vector3i::cross(a, b), Vector3i(-10, -3, 7)); + CORRADE_COMPARE(Math::cross(a, b), Vector3i(-10, -3, 7)); } void Vector3Test::axes() { diff --git a/src/Magnum/Math/Test/VectorTest.cpp b/src/Magnum/Math/Test/VectorTest.cpp index 5980b2c44..7d8f90206 100644 --- a/src/Magnum/Math/Test/VectorTest.cpp +++ b/src/Magnum/Math/Test/VectorTest.cpp @@ -364,7 +364,7 @@ void VectorTest::bitwise() { } void VectorTest::dot() { - CORRADE_COMPARE(Vector4::dot({1.0f, 0.5f, 0.75f, 1.5f}, {2.0f, 4.0f, 1.0f, 7.0f}), 15.25f); + CORRADE_COMPARE(Math::dot(Vector4{1.0f, 0.5f, 0.75f, 1.5f}, {2.0f, 4.0f, 1.0f, 7.0f}), 15.25f); } void VectorTest::dotSelf() { @@ -435,15 +435,15 @@ void VectorTest::projectedOntoNormalized() { void VectorTest::angle() { std::ostringstream o; Error::setOutput(&o); - Vector3::angle(Vector3(2.0f, 3.0f, 4.0f).normalized(), {1.0f, -2.0f, 3.0f}); - CORRADE_COMPARE(o.str(), "Math::Vector::angle(): vectors must be normalized\n"); + Math::angle(Vector3(2.0f, 3.0f, 4.0f).normalized(), {1.0f, -2.0f, 3.0f}); + CORRADE_COMPARE(o.str(), "Math::angle(): vectors must be normalized\n"); o.str({}); - Vector3::angle({2.0f, 3.0f, 4.0f}, Vector3(1.0f, -2.0f, 3.0f).normalized()); - CORRADE_COMPARE(o.str(), "Math::Vector::angle(): vectors must be normalized\n"); + Math::angle({2.0f, 3.0f, 4.0f}, Vector3(1.0f, -2.0f, 3.0f).normalized()); + CORRADE_COMPARE(o.str(), "Math::angle(): vectors must be normalized\n"); - CORRADE_COMPARE(Vector3::angle(Vector3(2.0f, 3.0f, 4.0f).normalized(), - Vector3(1.0f, -2.0f, 3.0f).normalized()), + CORRADE_COMPARE(Math::angle(Vector3(2.0f, 3.0f, 4.0f).normalized(), + Vector3(1.0f, -2.0f, 3.0f).normalized()), Rad(1.162514f)); } diff --git a/src/Magnum/Math/Vector.h b/src/Magnum/Math/Vector.h index cf5a5f59d..2a4c9f695 100644 --- a/src/Magnum/Math/Vector.h +++ b/src/Magnum/Math/Vector.h @@ -31,8 +31,9 @@ #include #include -#include #include +#include +#include #include "Magnum/visibility.h" #include "Magnum/Math/Angle.h" @@ -45,6 +46,35 @@ namespace Implementation { template struct VectorConverter; } +/** @relatesalso Vector +@brief Dot product of two vectors + +Returns `0` when two vectors are perpendicular, `1` when two *normalized* +vectors are parallel and `-1` when two *normalized* vectors are antiparallel. @f[ + \boldsymbol a \cdot \boldsymbol b = \sum_{i=0}^{n-1} \boldsymbol a_i \boldsymbol b_i +@f] +@see @ref Vector::dot() const, @ref Vector::operator-(), @ref Vector2::perpendicular() +*/ +template inline T dot(const Vector& a, const Vector& b) { + return (a*b).sum(); +} + +/** @relatesalso Vector +@brief Angle between normalized vectors + +Expects that both vectors are normalized. @f[ + \theta = acos \left( \frac{\boldsymbol a \cdot \boldsymbol b}{|\boldsymbol a| |\boldsymbol b|} \right) = acos (\boldsymbol a \cdot \boldsymbol b) +@f] +@see @ref Vector::isNormalized(), + @ref angle(const Complex&, const Complex&), + @ref angle(const Quaternion&, const Quaternion&) +*/ +template inline Rad angle(const Vector& normalizedA, const Vector& normalizedB) { + CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), + "Math::angle(): vectors must be normalized", {}); + return Rad(std::acos(dot(normalizedA, normalizedB))); +} + /** @brief Vector @tparam size Vector size @@ -89,30 +119,25 @@ template class Vector { return padInternal(typename Implementation::GenerateSequence::Type(), a, value); } + #ifdef MAGNUM_BUILD_DEPRECATED /** - * @brief Dot product - * - * Returns `0` when two vectors are perpendicular, `1` when two - * *normalized* vectors are parallel and `-1` when two *normalized* - * vectors are antiparallel. @f[ - * \boldsymbol a \cdot \boldsymbol b = \sum_{i=0}^{n-1} \boldsymbol a_i \boldsymbol b_i - * @f] - * @see @ref dot() const, @ref operator-(), @ref Vector2::perpendicular() + * @copybrief Math::dot(const Vector&, const Vector&) + * @deprecated Use @ref Math::dot(const Vector&, const Vector&) + * instead. */ - static T dot(const Vector& a, const Vector& b) { - return (a*b).sum(); + CORRADE_DEPRECATED("use Math::dot() instead") static T dot(const Vector& a, const Vector& b) { + return Math::dot(a, b); } /** - * @brief Angle between normalized vectors - * - * Expects that both vectors are normalized. @f[ - * \theta = acos \left( \frac{\boldsymbol a \cdot \boldsymbol b}{|\boldsymbol a| |\boldsymbol b|} \right) = acos (\boldsymbol a \cdot \boldsymbol b) - * @f] - * @see @ref isNormalized(), @ref Quaternion::angle(), - * @ref Complex::angle() + * @copybrief Math::angle(const Vector&, const Vector&) + * @deprecated Use @ref Math::angle(const Vector&, const Vector&) + * instead. */ - static Rad angle(const Vector& normalizedA, const Vector& normalizedB); + CORRADE_DEPRECATED("use Math::angle() instead") static Rad angle(const Vector& normalizedA, const Vector& normalizedB) { + return Math::angle(normalizedA, normalizedB); + } + #endif /** * @brief Default constructor @@ -409,7 +434,7 @@ template class Vector { * @see @ref dot(const Vector&, const Vector&), * @ref isNormalized() */ - T dot() const { return dot(*this, *this); } + T dot() const { return Math::dot(*this, *this); } /** * @brief Vector length @@ -466,7 +491,7 @@ template class Vector { * @see @ref dot(), @ref projectedOntoNormalized() */ Vector projected(const Vector& line) const { - return line*dot(*this, line)/line.dot(); + return line*Math::dot(*this, line)/line.dot(); } /** @@ -1214,12 +1239,6 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit } #endif -template inline Rad Vector::angle(const Vector& normalizedA, const Vector& normalizedB) { - CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), - "Math::Vector::angle(): vectors must be normalized", {}); - return Rad(std::acos(dot(normalizedA, normalizedB))); -} - template inline BoolVector Vector::operator<(const Vector& other) const { BoolVector out; @@ -1267,7 +1286,7 @@ template inline Vector Vector::oper template inline Vector Vector::projectedOntoNormalized(const Vector& line) const { CORRADE_ASSERT(line.isNormalized(), "Math::Vector::projectedOntoNormalized(): line must be normalized", {}); - return line*dot(*this, line); + return line*Math::dot(*this, line); } template inline T Vector::sum() const { diff --git a/src/Magnum/Math/Vector2.h b/src/Magnum/Math/Vector2.h index 2885966eb..d73ccf29e 100644 --- a/src/Magnum/Math/Vector2.h +++ b/src/Magnum/Math/Vector2.h @@ -33,6 +33,24 @@ namespace Magnum { namespace Math { +/** +@brief 2D cross product + +2D version of cross product, also called perp-dot product, equivalent to +calling @ref cross(const Vector3&, const Vector3&) with Z coordinate set +to `0` and extracting only Z coordinate from the result (X and Y coordinates +are always zero). Returns `0` either when one of the vectors is zero or they +are parallel or antiparallel and `1` when two *normalized* vectors are +perpendicular. @f[ + \boldsymbol a \times \boldsymbol b = \boldsymbol a_\bot \cdot \boldsymbol b = a_xb_y - a_yb_x +@f] +@see @ref Vector2::perpendicular(), + @ref dot(const Vector&, const Vector&) + */ +template inline T cross(const Vector2& a, const Vector2& b) { + return dot(a.perpendicular(), b); +} + /** @brief Two-component vector @tparam T Data type @@ -82,23 +100,16 @@ template class Vector2: public Vector<2, T> { */ constexpr static Vector2 yScale(T scale) { return {T(1), scale}; } + #ifdef MAGNUM_BUILD_DEPRECATED /** - * @brief 2D cross product - * - * 2D version of cross product, also called perp-dot product, - * equivalent to calling @ref Vector3::cross() with Z coordinate set to - * `0` and extracting only Z coordinate from the result (X and Y - * coordinates are always zero). Returns `0` either when one of the - * vectors is zero or they are parallel or antiparallel and `1` when - * two *normalized* vectors are perpendicular, @f[ - * \boldsymbol a \times \boldsymbol b = \boldsymbol a_\bot \cdot \boldsymbol b = a_xb_y - a_yb_x - * @f] - * @see @ref perpendicular(), - * @ref dot(const Vector&, const Vector&) + * @copybrief Math::cross(const Vector2&, const Vector2&) + * @deprecated Use @ref Math::cross(const Vector2&, const Vector2&) + * instead. */ - static T cross(const Vector2& a, const Vector2& b) { - return Vector<2, T>::dot(a.perpendicular(), b); + CORRADE_DEPRECATED("use Math::cross() instead") static T cross(const Vector2& a, const Vector2& b) { + return Math::cross(a, b); } + #endif /** @copydoc Vector::Vector() */ constexpr /*implicit*/ Vector2() {} diff --git a/src/Magnum/Math/Vector3.h b/src/Magnum/Math/Vector3.h index 8273c3c36..93277ac0d 100644 --- a/src/Magnum/Math/Vector3.h +++ b/src/Magnum/Math/Vector3.h @@ -34,6 +34,27 @@ namespace Magnum { namespace Math { +/** +@brief Cross product + +Result has length of `0` either when one of them is zero or they are parallel +or antiparallel and length of `1` when two *normalized* vectors are +perpendicular. Done using the following equation: @f[ + \boldsymbol a \times \boldsymbol b = \begin{pmatrix} c_y \\ c_z \\ c_x \end{pmatrix} ~~~~~ + \boldsymbol c = \boldsymbol a \begin{pmatrix} b_y \\ b_z \\ b_x \end{pmatrix} - + \boldsymbol b \begin{pmatrix} a_y \\ a_z \\ a_x \end{pmatrix} +@f] +Which is equivalent to the common one (source: +https://twitter.com/sjb3d/status/563640846671953920): @f[ + \boldsymbol a \times \boldsymbol b = \begin{pmatrix}a_yb_z - a_zb_y \\ a_zb_x - a_xb_z \\ a_xb_y - a_yb_x \end{pmatrix} +@f] +@see @ref cross(const Vector2&, const Vector2&) +*/ +template inline Vector3 cross(const Vector3& a, const Vector3& b) { + return swizzle<'y', 'z', 'x'>(a*swizzle<'y', 'z', 'x'>(b) - + b*swizzle<'y', 'z', 'x'>(a)); +} + /** @brief Three-component vector @tparam T Data type @@ -101,26 +122,16 @@ template class Vector3: public Vector<3, T> { */ constexpr static Vector3 zScale(T scale) { return {T(1), T(1), scale}; } + #ifdef MAGNUM_BUILD_DEPRECATED /** - * @brief Cross product - * - * Result has length of `0` either when one of them is zero or they are - * parallel or antiparallel and length of `1` when two *normalized* - * vectors are perpendicular. Done using the following equation: @f[ - * \boldsymbol a \times \boldsymbol b = \begin{pmatrix} c_y \\ c_z \\ c_x \end{pmatrix} ~~~~~ - * \boldsymbol c = \boldsymbol a \begin{pmatrix} b_y \\ b_z \\ b_x \end{pmatrix} - - * \boldsymbol b \begin{pmatrix} a_y \\ a_z \\ a_x \end{pmatrix} - * @f] - * Which is equivalent to the common one (source: - * https://twitter.com/sjb3d/status/563640846671953920): @f[ - * \boldsymbol a \times \boldsymbol b = \begin{pmatrix}a_yb_z - a_zb_y \\ a_zb_x - a_xb_z \\ a_xb_y - a_yb_x \end{pmatrix} - * @f] - * @see @ref Vector2::cross() + * @copybrief Math::cross(const Vector3&, const Vector3&) + * @deprecated Use @ref Math::cross(const Vector3&, const Vector3&) + * instead. */ - static Vector3 cross(const Vector3& a, const Vector3& b) { - return swizzle<'y', 'z', 'x'>(a*swizzle<'y', 'z', 'x'>(b) - - b*swizzle<'y', 'z', 'x'>(a)); + CORRADE_DEPRECATED("use Math::cross() instead") static Vector3 cross(const Vector3& a, const Vector3& b) { + return Math::cross(a, b); } + #endif /** @copydoc Vector::Vector() */ constexpr /*implicit*/ Vector3() {} diff --git a/src/Magnum/MeshTools/GenerateFlatNormals.cpp b/src/Magnum/MeshTools/GenerateFlatNormals.cpp index 2e7ab6ac7..242ff0c1c 100644 --- a/src/Magnum/MeshTools/GenerateFlatNormals.cpp +++ b/src/Magnum/MeshTools/GenerateFlatNormals.cpp @@ -40,8 +40,8 @@ std::tuple, std::vector> generateFlatNormals(c std::vector normals; normals.reserve(indices.size()/3); for(std::size_t i = 0; i != indices.size(); i += 3) { - Vector3 normal = Vector3::cross(positions[indices[i+2]]-positions[indices[i+1]], - positions[indices[i]]-positions[indices[i+1]]).normalized(); + const Vector3 normal = Math::cross(positions[indices[i+2]]-positions[indices[i+1]], + positions[indices[i]]-positions[indices[i+1]]).normalized(); /* Use the same normal for all three vertices of the face */ normalIndices.push_back(normals.size());