From 62203ae8916d0498222e1f41346f20203b160755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 20 Oct 2015 21:05:51 +0200 Subject: [PATCH] Math: proper multiplication/division of Duals with different types. Now works both ways. The base class works with virtually any combination that is supported by the underlying types, so e.g. Dual> could be multiplied/divided with Vector3 (result is Vector3), with Matrix3 (result is Matrix3) or with T (result is Matrix3). The macros, on the other hand, because they are there only to help with implementation of *my* subclasses, restrict that to the two only cases I need (i.e. multiplication with Dual and Dual and nothing else). Could be extended in the future if it needs to be. --- src/Magnum/Math/Dual.h | 27 ++++++++++++++++++++++++--- src/Magnum/Math/DualComplex.h | 10 +++------- src/Magnum/Math/DualQuaternion.h | 4 +++- src/Magnum/Math/Test/DualTest.cpp | 16 +++++++++------- 4 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/Magnum/Math/Dual.h b/src/Magnum/Math/Dual.h index b39472901..adb43622a 100644 --- a/src/Magnum/Math/Dual.h +++ b/src/Magnum/Math/Dual.h @@ -153,7 +153,7 @@ template class Dual { * \hat a \hat b = a_0 b_0 + \epsilon (a_0 b_\epsilon + a_\epsilon b_0) * @f] */ - template Dual operator*(const Dual& other) const { + template auto operator*(const Dual& other) const -> Dual { return {_real*other._real, _real*other._dual + _dual*other._real}; } @@ -164,7 +164,7 @@ template class Dual { * \frac{\hat a}{\hat b} = \frac{a_0}{b_0} + \epsilon \frac{a_\epsilon b_0 - a_0 b_\epsilon}{b_0^2} * @f] */ - template Dual operator/(const Dual& other) const { + template auto operator/(const Dual& other) const -> Dual { return {_real/other._real, (_dual*other._real - _real*other._dual)/(other._real*other._real)}; } @@ -184,7 +184,7 @@ template class Dual { }; #ifndef DOXYGEN_GENERATING_OUTPUT -#define MAGNUM_DUAL_SUBCLASS_IMPLEMENTATION(Type, Underlying) \ +#define MAGNUM_DUAL_SUBCLASS_IMPLEMENTATION(Type, Underlying, Multiplicable) \ Type operator-() const { \ return Math::Dual>::operator-(); \ } \ @@ -201,7 +201,14 @@ template class Dual { } \ Type operator-(const Math::Dual>& other) const { \ return Math::Dual>::operator-(other); \ + } \ + Type operator*(const Math::Dual& other) const { \ + return Math::Dual>::operator*(other); \ + } \ + Type operator/(const Math::Dual& other) const { \ + return Math::Dual>::operator/(other); \ } + /* DualComplex needs its own special implementation of multiplication/division */ #define MAGNUM_DUAL_SUBCLASS_MULTIPLICATION_IMPLEMENTATION(Type, Underlying) \ template Type operator*(const Math::Dual& other) const { \ @@ -209,6 +216,20 @@ template class Dual { } \ template Type operator/(const Math::Dual& other) const { \ return Math::Dual>::operator/(other); \ + } \ + Type operator*(const Math::Dual>& other) const { \ + return Math::Dual>::operator*(other); \ + } \ + Type operator/(const Math::Dual>& other) const { \ + return Math::Dual>::operator/(other); \ + } + +#define MAGNUM_DUAL_OPERATOR_IMPLEMENTATION(Type, Underlying, Multiplicable) \ + template inline Type operator*(const Math::Dual& a, const Type& b) { \ + return a*static_cast>&>(b); \ + } \ + template inline Type operator/(const Math::Dual& a, const Type& b) { \ + return a/static_cast>&>(b); \ } #endif diff --git a/src/Magnum/Math/DualComplex.h b/src/Magnum/Math/DualComplex.h index f8927caac..ae2ef17b4 100644 --- a/src/Magnum/Math/DualComplex.h +++ b/src/Magnum/Math/DualComplex.h @@ -339,17 +339,13 @@ template class DualComplex: public Dual> { return Vector2(((*this)*DualComplex(vector)).dual()); } - MAGNUM_DUAL_SUBCLASS_IMPLEMENTATION(DualComplex, Vector2) + MAGNUM_DUAL_SUBCLASS_IMPLEMENTATION(DualComplex, Vector2, T) /* Not using MAGNUM_DUAL_SUBCLASS_MULTIPLICATION_IMPLEMENTATION(), as we have special multiplication/division implementation */ - - private: - /* Just to be sure nobody uses this, as it wouldn't probably work with - our operator*() */ - using Dual>::operator*; - using Dual>::operator/; }; +MAGNUM_DUAL_OPERATOR_IMPLEMENTATION(DualComplex, Vector2, T) + /** @debugoperator{Magnum::Math::DualQuaternion} */ template Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug& debug, const DualComplex& value) { return debug << "DualComplex({" << Corrade::Utility::Debug::nospace diff --git a/src/Magnum/Math/DualQuaternion.h b/src/Magnum/Math/DualQuaternion.h index 8d0c6d412..526f91598 100644 --- a/src/Magnum/Math/DualQuaternion.h +++ b/src/Magnum/Math/DualQuaternion.h @@ -354,10 +354,12 @@ template class DualQuaternion: public Dual> { return ((*this)*DualQuaternion(vector)*conjugated()).dual().vector(); } - MAGNUM_DUAL_SUBCLASS_IMPLEMENTATION(DualQuaternion, Quaternion) + MAGNUM_DUAL_SUBCLASS_IMPLEMENTATION(DualQuaternion, Quaternion, T) MAGNUM_DUAL_SUBCLASS_MULTIPLICATION_IMPLEMENTATION(DualQuaternion, Quaternion) }; +MAGNUM_DUAL_OPERATOR_IMPLEMENTATION(DualQuaternion, Quaternion, T) + /** @debugoperator{Magnum::Math::DualQuaternion} */ template Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug& debug, const DualQuaternion& value) { return debug << "DualQuaternion({{" << Corrade::Utility::Debug::nospace diff --git a/src/Magnum/Math/Test/DualTest.cpp b/src/Magnum/Math/Test/DualTest.cpp index 4ff641ad9..2880f6dc3 100644 --- a/src/Magnum/Math/Test/DualTest.cpp +++ b/src/Magnum/Math/Test/DualTest.cpp @@ -150,9 +150,9 @@ void DualTest::multiplyDivideDifferentType() { DualVector2 d{{-2.0f/1.5f, -1.0f}, {-7.25f/2.25f, 3.6f/4.0f}}; CORRADE_COMPARE(a*b, c); - //CORRADE_COMPARE(b*a, c); does not compile yet + CORRADE_COMPARE(b*a, c); CORRADE_COMPARE(c/b, a); - //CORRADE_COMPARE(b/a, d); does not compile yet + CORRADE_COMPARE(b/a, d); } void DualTest::conjugated() { @@ -170,10 +170,12 @@ template class BasicDualVec2: public Math::Dual> { /* MSVC 2015 can't handle {} here */ template constexpr BasicDualVec2(U&&... args): Math::Dual>(args...) {} - MAGNUM_DUAL_SUBCLASS_IMPLEMENTATION(BasicDualVec2, Math::Vector2) + MAGNUM_DUAL_SUBCLASS_IMPLEMENTATION(BasicDualVec2, Math::Vector2, T) MAGNUM_DUAL_SUBCLASS_MULTIPLICATION_IMPLEMENTATION(BasicDualVec2, Math::Vector2) }; +MAGNUM_DUAL_OPERATOR_IMPLEMENTATION(BasicDualVec2, Math::Vector2, T) + typedef BasicDualVec2 DualVec2; } @@ -192,9 +194,9 @@ void DualTest::subclassTypes() { const Dual c; CORRADE_VERIFY((std::is_same::value)); - //CORRADE_VERIFY((std::is_same::value)); does not compile yet + CORRADE_VERIFY((std::is_same::value)); CORRADE_VERIFY((std::is_same::value)); - //CORRADE_VERIFY((std::is_same::value)); does not compile yet + CORRADE_VERIFY((std::is_same::value)); } void DualTest::subclass() { @@ -216,9 +218,9 @@ void DualTest::subclass() { const DualVec2 f{Vector2{-3.0f, -4.0f}, Vector2{8.75f, -1.6f}}; const DualVec2 g{Vector2{-2.0f/1.5f, -1.0f}, Vector2{-7.25f/2.25f, 3.6f/4.0f}}; CORRADE_COMPARE(a*e, f); - //CORRADE_COMPARE(e*a, f); does not compile yet + CORRADE_COMPARE(e*a, f); CORRADE_COMPARE(f/e, a); - //CORRADE_COMPARE(e/a, g); does not compile yet + CORRADE_COMPARE(e/a, g); } void DualTest::debug() {