Browse Source

Math: reworked DualComplex to actually work.

The tests now pass and it works similarly to transformation matrix
multiplication/inversion in 2D, but it hasn't any connection to dual
numbers anymore.
pull/278/head
Vladimír Vondruš 13 years ago
parent
commit
90f5a006c4
  1. 83
      src/Math/DualComplex.h
  2. 44
      src/Math/Test/DualComplexTest.cpp

83
src/Math/DualComplex.h

@ -30,6 +30,8 @@ namespace Magnum { namespace Math {
Represents 2D rotation and translation.
@see Dual, Complex, Matrix3
@todo Can this be done similarly as in dual quaternions? It sort of works, but
the math beneath is weird.
*/
template<class T> class DualComplex: public Dual<Complex<T>> {
public:
@ -107,7 +109,19 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @see translation(const Vector2&)
*/
inline Vector2<T> translation() const {
return Vector2<T>(this->dual()*this->real().conjugated());
return Vector2<T>(this->dual());
}
/**
* @brief Multipy with dual complex number
*
* @f[
* \hat a \hat b = a_0 b_0 + \epsilon (a_0 b_\epsilon + a_\epsilon)
* @f]
* @todo can this be done similarly to dual quaternions?
*/
inline DualComplex<T> operator*(const DualComplex<T>& other) const {
return {this->real()*other.real(), this->real()*other.dual() + this->dual()};
}
/**
@ -152,11 +166,12 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
*
* Should be used instead of length() for comparing complex number
* length with other values, because it doesn't compute the square root. @f[
* |\hat c|^2 = \sqrt{\hat c^* \hat c}^2 = c_0 \cdot c_0 + \epsilon 2 (c_0 \cdot c_\epsilon)
* |\hat c|^2 = c_0 \cdot c_0 = |c_0|^2
* @f]
* @todo Can this be done similarly to dual quaternins?
*/
inline Dual<T> lengthSquared() const {
return {this->real().dot(), T(2)*Complex<T>::dot(this->real(), this->dual())};
inline T lengthSquared() const {
return this->real().dot();
}
/**
@ -164,16 +179,24 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
*
* See lengthSquared() which is faster for comparing length with other
* values. @f[
* |\hat c| = \sqrt{\hat{c^*} \hat c} = |c_0| + \epsilon \frac{c_0 \cdot c_\epsilon}{|c_0|}
* |\hat c| = \sqrt{c_0 \cdot c_0} = |c_0|
* @f]
* @todo can this be done similarly to dual quaternions?
*/
inline Dual<T> length() const {
return Math::sqrt(lengthSquared());
inline T length() const {
return this->real().length();
}
/** @brief Normalized dual complex number (of unit length) */
/**
* @brief Normalized dual complex number (of unit length)
*
* @f[
* c' = \frac{c_0}{|c_0|}
* @f]
* @todo can this be done similarly to dual quaternions?
*/
inline DualComplex<T> normalized() const {
return (*this)/length();
return {this->real()/length(), this->dual()};
}
/**
@ -181,33 +204,57 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
*
* See invertedNormalized() which is faster for normalized dual complex
* numbers. @f[
* \hat c^{-1} = \frac{\hat c^*}{|\hat c|^2}
* \hat c^{-1} = c_0^{-1} - \epsilon c_\epsilon
* @f]
* @todo can this be done similarly to dual quaternions?
*/
inline DualComplex<T> inverted() const {
return complexConjugated()/lengthSquared();
return DualComplex<T>(this->real().inverted(), {{}, {}})*DualComplex<T>({}, -this->dual());
}
/**
* @brief Inverted normalized dual complex number
*
* Equivalent to complexConjugated(). Expects that the complex number
* is normalized. @f[
* \hat c^{-1} = \frac{\hat c^*}{|\hat c|^2} = \hat c^*
* Expects that the complex number is normalized. @f[
* \hat c^{-1} = c_0^{-1} - \epsilon c_\epsilon = c_0^* - \epsilon c_\epsilon
* @f]
* @see inverted()
* @todo can this be done similarly to dual quaternions?
*/
inline DualComplex<T> invertedNormalized() const {
CORRADE_ASSERT(lengthSquared() == Dual<T>(1),
"Math::DualComplex::invertedNormalized(): dual complex number must be normalized", {});
return complexConjugated();
return DualComplex<T>(this->real().invertedNormalized(), {{}, {}})*DualComplex<T>({}, -this->dual());
}
MAGNUM_DUAL_SUBCLASS_IMPLEMENTATION(DualComplex, Complex)
/* Verbatim copy of DUAL_SUBCLASS_IMPLEMENTATION(), as we need to hide
Dual's operator*() and operator/() */
#ifndef DOXYGEN_GENERATING_OUTPUT
inline DualComplex<T> operator-() const {
return Dual<Complex<T>>::operator-();
}
inline DualComplex<T>& operator+=(const Dual<Complex<T>>& other) {
Dual<Complex<T>>::operator+=(other);
return *this;
}
inline DualComplex<T> operator+(const Dual<Complex<T>>& other) const {
return Dual<Complex<T>>::operator+(other);
}
inline DualComplex<T>& operator-=(const Dual<Complex<T>>& other) {
Dual<Complex<T>>::operator-=(other);
return *this;
}
inline DualComplex<T> operator-(const Dual<Complex<T>>& other) const {
return Dual<Complex<T>>::operator-(other);
}
#endif
private:
/* Used by Dual operators and dualConjugated() */
inline constexpr DualComplex(const Dual<Complex<T>>& other): Dual<Complex<T>>(other) {}
/* Just to be sure nobody uses this, as it wouldn't probably work with
our operator*() */
using Dual<Complex<T>>::operator*;
using Dual<Complex<T>>::operator/;
};
/** @debugoperator{Magnum::Math::DualQuaternion} */

44
src/Math/Test/DualComplexTest.cpp

@ -17,6 +17,7 @@
#include <TestSuite/Tester.h>
#include "Math/DualComplex.h"
#include "Math/DualQuaternion.h"
namespace Magnum { namespace Math { namespace Test {
@ -29,6 +30,8 @@ class DualComplexTest: public Corrade::TestSuite::Tester {
void constExpressions();
void multiply();
void lengthSquared();
void length();
void normalized();
@ -59,6 +62,8 @@ DualComplexTest::DualComplexTest() {
&DualComplexTest::constExpressions,
&DualComplexTest::multiply,
&DualComplexTest::lengthSquared,
&DualComplexTest::length,
&DualComplexTest::normalized,
@ -101,19 +106,25 @@ void DualComplexTest::constExpressions() {
CORRADE_COMPARE(d, DualComplex({-1.0f, 2.5f}, {3.0f, -7.5f}));
}
void DualComplexTest::multiply() {
DualComplex a({-1.5f, 2.0f}, { 3.0f, -6.5f});
DualComplex b({ 2.0f, -7.5f}, {-0.5f, 1.0f});;
CORRADE_COMPARE(a*b, DualComplex({12.0f, 15.25f}, {1.75f, -9.0f}));
}
void DualComplexTest::lengthSquared() {
DualComplex a({-1.0f, 3.0f}, {0.5f, -2.0f});
CORRADE_COMPARE(a.lengthSquared(), Dual(10.0f, -13.0f));
CORRADE_COMPARE(a.lengthSquared(), 10.0f);
}
void DualComplexTest::length() {
DualComplex a({-1.0f, 3.0f}, {0.5f, -2.0f});
CORRADE_COMPARE(a.length(), Dual(3.162278f, -2.05548f));
CORRADE_COMPARE(a.length(), 3.162278f);
}
void DualComplexTest::normalized() {
DualComplex a({-1.0f, 3.0f}, {0.5f, -2.0f});
DualComplex b({-0.316228f, 0.948683f}, {-0.0474342f, -0.0158114f});
DualComplex b({-0.316228f, 0.948683f}, {0.5f, -2.0f});
CORRADE_COMPARE(a.normalized().length(), 1.0f);
CORRADE_COMPARE(a.normalized(), b);
}
@ -137,27 +148,26 @@ void DualComplexTest::conjugated() {
}
void DualComplexTest::inverted() {
DualComplex a({-1.0f, 2.5f}, { 3.0f, -7.5f});
DualComplex b({-1.0f, -2.5f}, { 3.0f, 7.5f});
DualComplex a({-1.0f, 1.5f}, {3.0f, -7.5f});
DualComplex b({-0.307692f, -0.461538f}, {4.384616f, -0.923077f});
CORRADE_COMPARE(a*a.inverted(), DualComplex());
CORRADE_COMPARE(a.inverted(), b/Dual(7.25f, -43.5f));
CORRADE_COMPARE(a.inverted(), b);
}
void DualComplexTest::invertedNormalized() {
DualComplex a({-1.0f, 2.5f}, { 3.0f, -7.5f});
DualComplex b({-1.0f, -2.5f}, { 3.0f, 7.5f});
DualComplex a({-0.316228f, 0.9486831f}, { 3.0f, -2.5f});
DualComplex b({-0.316228f, -0.9486831f}, {3.320391f, 2.05548f});
std::ostringstream o;
Error::setOutput(&o);
CORRADE_COMPARE(a.invertedNormalized(), DualComplex());
CORRADE_COMPARE(o.str(), "Math::DualComplex::invertedNormalized(): dual complex number must be normalized\n");
DualComplex normalized = a.normalized();
DualComplex inverted = normalized.invertedNormalized();
CORRADE_COMPARE(normalized*inverted, DualComplex());
CORRADE_COMPARE(inverted*normalized, DualComplex());
CORRADE_COMPARE(inverted, b/Math::sqrt(Dual(7.25f, -43.5f)));
DualComplex notInverted = DualComplex({-1.0f, -2.5f}, {}).invertedNormalized();
CORRADE_VERIFY(notInverted != notInverted);
CORRADE_COMPARE(o.str(), "Math::Complex::invertedNormalized(): complex number must be normalized\n");
DualComplex inverted = a.invertedNormalized();
CORRADE_COMPARE(a*inverted, DualComplex());
CORRADE_COMPARE(inverted*a, DualComplex());
CORRADE_COMPARE(inverted, b);
}
void DualComplexTest::rotation() {

Loading…
Cancel
Save