From 609df779f5f65c98696616d5068988893d130447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 24 Oct 2015 23:55:38 +0200 Subject: [PATCH] Math: added sincos() for Dual numbers. Calculating sin of Dual number involves also calculating the cos value, thus a helper function is in order. --- src/Magnum/Math/Dual.h | 27 +++++++++++++++++++++++++++ src/Magnum/Math/Functions.h | 2 +- src/Magnum/Math/Test/DualTest.cpp | 29 +++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/Magnum/Math/Dual.h b/src/Magnum/Math/Dual.h index feb48b08d..5000d2fa6 100644 --- a/src/Magnum/Math/Dual.h +++ b/src/Magnum/Math/Dual.h @@ -32,6 +32,7 @@ #include #include +#include "Magnum/Math/Angle.h" #include "Magnum/Math/Tags.h" #include "Magnum/Math/TypeTraits.h" @@ -322,6 +323,32 @@ template Dual sqrt(const Dual& dual) { return {sqrt0, dual.dual()/(2*sqrt0)}; } +/** @relatesalso Dual +@brief Sine and cosine of dual angle + +@f[ +\begin{array}{rcl} + sin(\hat a) & = & sin(a_0) + \epsilon a_\epsilon cos(a_0) \\ + cos(\hat a) & = & cos(a_0) - \epsilon a_\epsilon sin(a_0) +\end{array} +@f] +@see @ref sincos(Rad) +*/ +/* The function accepts Unit instead of Rad to make it working with operator + products (e.g. 2*35.0_degf, which is of type Unit) */ +template std::pair, Dual> sincos(const Dual>& angle) +{ + /* Not using Math::sincos(), because I don't want to include Functions.h */ + const T sin = std::sin(T(angle.real())); + const T cos = std::cos(T(angle.real())); + return {{sin, T(angle.dual())*cos}, {cos, -T(angle.dual())*sin}}; +} +#ifndef DOXYGEN_GENERATING_OUTPUT +template std::pair, Dual> sincos(const Dual>& angle) { return sincos(Dual>(angle)); } +template std::pair, Dual> sincos(const Dual>& angle) { return sincos(Dual>(angle)); } +template std::pair, Dual> sincos(const Dual>& angle) { return sincos(Dual>(angle)); } +#endif + }} #endif diff --git a/src/Magnum/Math/Functions.h b/src/Magnum/Math/Functions.h index e570f3bfa..3c70d30f7 100644 --- a/src/Magnum/Math/Functions.h +++ b/src/Magnum/Math/Functions.h @@ -132,7 +132,7 @@ template inline T cos(Unit angle) { return cos(Rad(angle)); @brief Sine and cosine On some architectures might be faster than doing both computations separately. -@see @ref sin(), @ref cos() +@see @ref sin(), @ref cos(), @ref sincos(const Dual>&) */ #ifdef DOXYGEN_GENERATING_OUTPUT template inline std::pair sincos(Rad angle); diff --git a/src/Magnum/Math/Test/DualTest.cpp b/src/Magnum/Math/Test/DualTest.cpp index cff84eca2..a2bb6ca76 100644 --- a/src/Magnum/Math/Test/DualTest.cpp +++ b/src/Magnum/Math/Test/DualTest.cpp @@ -51,6 +51,9 @@ struct DualTest: Corrade::TestSuite::Tester { void conjugated(); void sqrt(); + void sincos(); + void sincosWithBase(); + void subclassTypes(); void subclass(); @@ -60,6 +63,9 @@ struct DualTest: Corrade::TestSuite::Tester { typedef Math::Dual Dual; typedef Math::Vector2 Vector2; typedef Math::Dual DualVector2; +typedef Math::Deg Deg; +typedef Math::Rad Rad; +typedef Math::Constants Constants; DualTest::DualTest() { addTests({&DualTest::construct, @@ -79,6 +85,9 @@ DualTest::DualTest() { &DualTest::conjugated, &DualTest::sqrt, + &DualTest::sincos, + &DualTest::sincosWithBase, + &DualTest::subclassTypes, &DualTest::subclass, @@ -188,6 +197,26 @@ void DualTest::sqrt() { CORRADE_COMPARE(Math::sqrt(Dual(16.0f, 2.0f)), Dual(4.0f, 0.25f)); } +void DualTest::sincos() { + const auto result = std::make_pair( + Dual(0.5f, 0.8660254037844386f*Constants::pi()/2), + Dual(0.8660254037844386f, -0.5f*Constants::pi()/2)); + CORRADE_COMPARE(Math::sincos(Math::Dual(30.0_degf, 90.0_degf)), result); + CORRADE_COMPARE(Math::sincos(Math::Dual(Rad(Constants::pi()/6), Rad(Constants::pi()/2))), result); +} + +void DualTest::sincosWithBase() { + /* Verify that the functions can be called with Dual> and Dual> */ + CORRADE_VERIFY((std::is_same{15.0_degf}), Math::Dual>>::value)); + CORRADE_VERIFY((std::is_same{Rad{Constants::pi()/12}}), Math::Dual>>::value)); + + const auto result = std::make_pair( + Dual(0.5f, 0.8660254037844386f*Constants::pi()/2), + Dual(0.8660254037844386f, -0.5f*Constants::pi()/2)); + CORRADE_COMPARE(Math::sincos(2*Math::Dual(15.0_degf, 45.0_degf)), result); + CORRADE_COMPARE(Math::sincos(2*Math::Dual(Rad(Constants::pi()/12), Rad(Constants::pi()/4))), result); +} + namespace { template class BasicDualVec2: public Math::Dual> {