From 687bd37b8165ba34317521e60101662eacb4d164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 19 Feb 2013 21:19:07 +0100 Subject: [PATCH] Math: initial complex number implementation. --- src/CMakeLists.txt | 1 + src/Math/CMakeLists.txt | 1 + src/Math/Complex.cpp | 27 +++++ src/Math/Complex.h | 218 ++++++++++++++++++++++++++++++++++ src/Math/Test/CMakeLists.txt | 1 + src/Math/Test/ComplexTest.cpp | 129 ++++++++++++++++++++ 6 files changed, 377 insertions(+) create mode 100644 src/Math/Complex.cpp create mode 100644 src/Math/Complex.h create mode 100644 src/Math/Test/ComplexTest.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5fb41fd06..1fa36c4e0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -98,6 +98,7 @@ add_library(MagnumObjects OBJECT ${Magnum_SRCS}) # Files shared between main library and math unit test library set(MagnumMath_SRCS + Math/Complex.cpp Math/DualQuaternion.cpp Math/Functions.cpp Math/Quaternion.cpp diff --git a/src/Math/CMakeLists.txt b/src/Math/CMakeLists.txt index 4bcbf5743..1b7647b1c 100644 --- a/src/Math/CMakeLists.txt +++ b/src/Math/CMakeLists.txt @@ -1,5 +1,6 @@ set(MagnumMath_HEADERS BoolVector.h + Complex.h Constants.h Dual.h DualQuaternion.h diff --git a/src/Math/Complex.cpp b/src/Math/Complex.cpp new file mode 100644 index 000000000..0a6c5bd39 --- /dev/null +++ b/src/Math/Complex.cpp @@ -0,0 +1,27 @@ +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "Complex.h" + +namespace Magnum { namespace Math { + +#ifndef DOXYGEN_GENERATING_OUTPUT +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Complex&); +#ifndef MAGNUM_TARGET_GLES +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Complex&); +#endif +#endif + +}} diff --git a/src/Math/Complex.h b/src/Math/Complex.h new file mode 100644 index 000000000..91630a9fd --- /dev/null +++ b/src/Math/Complex.h @@ -0,0 +1,218 @@ +#ifndef Magnum_Math_Complex_h +#define Magnum_Math_Complex_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Class Magnum::Math::Complex + */ + +#include + +#include "Math/MathTypeTraits.h" + +#include "magnumVisibility.h" + +namespace Magnum { namespace Math { + +/** +@brief %Complex number +@tparam T Data type + +Represents 2D rotation. +*/ +template class Complex { + public: + typedef T Type; /**< @brief Underlying data type */ + + /** + * @brief Default constructor + * + * @f[ + * c = 0 + i0 + * @f] + */ + inline constexpr /*implicit*/ Complex(): _real(T(0)), _imaginary(T(0)) {} + + /** + * @brief Construct complex from real and imaginary part + * + * @f[ + * c = a + ib + * @f] + */ + inline constexpr /*implicit*/ Complex(T real, T imaginary = T(0)): _real(real), _imaginary(imaginary) {} + + /** @brief Equality comparison */ + inline bool operator==(const Complex& other) const { + return MathTypeTraits::equals(_real, other._real) && + MathTypeTraits::equals(_imaginary, other._imaginary); + } + + /** @brief Non-equality comparison */ + inline bool operator!=(const Complex& other) const { + return !operator==(other); + } + + /** @brief Real part */ + inline constexpr T real() const { return _real; } + + /** @brief Imaginary part */ + inline constexpr T imaginary() const { return _imaginary; } + + /** + * @brief Add and assign complex + * + * The computation is done in-place. @f[ + * c_0 + c_1 = a_0 + a_1 + i(b_0 + b_1) + * @f] + */ + inline Complex& operator+=(const Complex& other) { + _real += other._real; + _imaginary += other._imaginary; + return *this; + } + + /** + * @brief Add complex + * + * @see operator+=() + */ + inline Complex operator+(const Complex& other) const { + return Complex(*this) += other; + } + + /** + * @brief Negated complex + * + * @f[ + * -c = -a -ib + * @f] + */ + inline Complex operator-() const { + return {-_real, -_imaginary}; + } + + /** + * @brief Subtract and assign complex + * + * The computation is done in-place. @f[ + * c_0 - c_1 = a_0 - a_1 + i(b_0 - b_1) + * @f] + */ + inline Complex& operator-=(const Complex& other) { + _real -= other._real; + _imaginary -= other._imaginary; + return *this; + } + + /** + * @brief Subtract complex + * + * @see operator-=() + */ + inline Complex operator-(const Complex& other) const { + return Complex(*this) -= other; + } + + /** + * @brief Multiply with scalar and assign + * + * The computation is done in-place. @f[ + * c \cdot t = ta + itb + * @f] + */ + inline Complex& operator*=(T scalar) { + _real *= scalar; + _imaginary *= scalar; + return *this; + } + + /** + * @brief Multiply with scalar + * + * @see operator*=(T) + */ + inline Complex operator*(T scalar) const { + return Complex(*this) *= scalar; + } + + /** + * @brief Divide with scalar and assign + * + * The computation is done in-place. @f[ + * \frac c t = \frac a t + i \frac b t + * @f] + */ + inline Complex& operator/=(T scalar) { + _real /= scalar; + _imaginary /= scalar; + return *this; + } + + /** + * @brief Divide with scalar + * + * @see operator/=(T) + */ + inline Complex operator/(T scalar) const { + return Complex(*this) /= scalar; + } + + private: + T _real, _imaginary; +}; + +/** @relates Complex +@brief Multiply scalar with complex + +Same as Complex::operator*(T) const. +*/ +template inline Complex operator*(T scalar, const Complex& complex) { + return complex*scalar; +} + +/** @relates Complex +@brief Divide complex with number and invert + +@f[ + \frac t c = \frac t a + i \frac t b +@f] +@see Complex::operator/() +*/ +template inline Complex operator/(T scalar, const Complex& complex) { + return {scalar/complex.real(), scalar/complex.imaginary()}; +} + +/** @debugoperator{Magnum::Math::Complex} */ +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Complex& value) { + debug << "Complex("; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); + debug << value.real() << ", " << value.imaginary() << ")"; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); + return debug; +} + +/* Explicit instantiation for commonly used types */ +#ifndef DOXYGEN_GENERATING_OUTPUT +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Complex&); +#ifndef MAGNUM_TARGET_GLES +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Complex&); +#endif +#endif + +}} + +#endif diff --git a/src/Math/Test/CMakeLists.txt b/src/Math/Test/CMakeLists.txt index 1f70c8dcb..22b5ff493 100644 --- a/src/Math/Test/CMakeLists.txt +++ b/src/Math/Test/CMakeLists.txt @@ -17,6 +17,7 @@ corrade_add_test(MathMatrix4Test Matrix4Test.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(MathSwizzleTest SwizzleTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathComplexTest ComplexTest.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(MathDualTest DualTest.cpp) corrade_add_test(MathQuaternionTest QuaternionTest.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(MathDualQuaternionTest DualQuaternionTest.cpp LIBRARIES MagnumMathTestLib) diff --git a/src/Math/Test/ComplexTest.cpp b/src/Math/Test/ComplexTest.cpp new file mode 100644 index 000000000..f4c352252 --- /dev/null +++ b/src/Math/Test/ComplexTest.cpp @@ -0,0 +1,129 @@ +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include +#include + +#include "Math/Complex.h" + +namespace Magnum { namespace Math { namespace Test { + +class ComplexTest: public Corrade::TestSuite::Tester { + public: + explicit ComplexTest(); + + void construct(); + void constructDefault(); + void compare(); + + void constExpressions(); + + void addSubtract(); + void negated(); + void multiplyDivideScalar(); + + void debug(); +}; + +ComplexTest::ComplexTest() { + addTests(&ComplexTest::construct, + &ComplexTest::constructDefault, + &ComplexTest::compare, + + &ComplexTest::constExpressions, + + &ComplexTest::addSubtract, + &ComplexTest::negated, + &ComplexTest::multiplyDivideScalar, + + &ComplexTest::debug); +} + +typedef Math::Complex Complex; + +void ComplexTest::construct() { + Complex c(0.5f, -3.7f); + CORRADE_COMPARE(c.real(), 0.5f); + CORRADE_COMPARE(c.imaginary(), -3.7f); + + CORRADE_COMPARE(Complex(2.0f), Complex(2.0f, 0.0f)); +} + +void ComplexTest::constructDefault() { + CORRADE_COMPARE(Complex(), Complex(0.0f, 0.0f)); +} + +void ComplexTest::compare() { + CORRADE_VERIFY(Complex(3.7f, -1.0f+MathTypeTraits::epsilon()/2) == Complex(3.7f, -1.0f)); + CORRADE_VERIFY(Complex(3.7f, -1.0f+MathTypeTraits::epsilon()*2) != Complex(3.7f, -1.0f)); + CORRADE_VERIFY(Complex(1.0f+MathTypeTraits::epsilon()/2, 3.7f) == Complex(1.0f, 3.7f)); + CORRADE_VERIFY(Complex(1.0f+MathTypeTraits::epsilon()*2, 3.7f) != Complex(1.0f, 3.7f)); +} + +void ComplexTest::constExpressions() { + /* Default constructor */ + constexpr Complex a; + CORRADE_COMPARE(a, Complex(0.0f, 0.0f)); + + /* Value constructor */ + constexpr Complex b(2.5f, -5.0f); + CORRADE_COMPARE(b, Complex(2.5f, -5.0f)); + + /* Copy constructor */ + constexpr Complex c(b); + CORRADE_COMPARE(c, Complex(2.5f, -5.0f)); + + /* Data access */ + constexpr float d = b.real(); + constexpr float e = c.imaginary(); + CORRADE_COMPARE(d, 2.5f); + CORRADE_COMPARE(e, -5.0f); +} + +void ComplexTest::addSubtract() { + Complex a( 1.7f, -3.7f); + Complex b(-3.6f, 0.2f); + Complex c(-1.9f, -3.5f); + + CORRADE_COMPARE(a + b, c); + CORRADE_COMPARE(c - b, a); +} + +void ComplexTest::negated() { + CORRADE_COMPARE(-Complex(2.5f, -7.4f), Complex(-2.5f, 7.4f)); +} + +void ComplexTest::multiplyDivideScalar() { + Complex a( 2.5f, -0.5f); + Complex b(-7.5f, 1.5f); + + CORRADE_COMPARE(a*-3.0f, b); + CORRADE_COMPARE(-3.0f*a, b); + CORRADE_COMPARE(b/-3.0f, a); + + Complex c(-0.8f, 4.0f); + CORRADE_COMPARE(-2.0f/a, c); +} + +void ComplexTest::debug() { + std::ostringstream o; + + Debug(&o) << Complex(2.5f, -7.5f); + CORRADE_COMPARE(o.str(), "Complex(2.5, -7.5)\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::ComplexTest)