/*============================================================================= Copyright (c) 2011-2015 Bolero MURAKAMI https://github.com/bolero-MURAKAMI/Sprout Distributed under the sprout Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.sprout.org/LICENSE_1_0.txt) =============================================================================*/ #ifndef SPROUT_MATH_QUATERNION_HPP #define SPROUT_MATH_QUATERNION_HPP #include #include #include #include #include #include #include #include #include #include //#include //#include #include #include #include namespace sprout { namespace math { namespace detail { template class abs_less { public: SPROUT_CONSTEXPR T operator()(T const& lhs, T const& rhs) const { return sprout::math::abs(lhs) < sprout::math::abs(rhs); } }; template class abs_plus { public: SPROUT_CONSTEXPR T operator()(T const& lhs, T const& rhs) const { return sprout::math::abs(lhs) + sprout::math::abs(rhs); } }; template SPROUT_CONSTEXPR T abs_max(sprout::array const& c) { return sprout::math::abs(*sprout::range::max_element(c, sprout::math::detail::abs_less())); } template SPROUT_CONSTEXPR T sum(sprout::array const& c) { return sprout::range::accumulate(c, static_cast(0)); } template SPROUT_CONSTEXPR T abs_sum(sprout::array const& c) { return sprout::range::accumulate(c, static_cast(0), sprout::math::detail::abs_plus()); } template SPROUT_CONSTEXPR sprout::array mul(sprout::array const& l, T const& r) { return sprout::array{{ l[0] * r, l[1] * r, }}; } template SPROUT_CONSTEXPR sprout::array mul(sprout::array const& l, sprout::array const& r) { return sprout::array{{ l[0] * r[0], l[1] * r[1], }}; } template SPROUT_CONSTEXPR sprout::array mul(sprout::array const& l, T const& r) { return sprout::array{{ l[0] * r, l[1] * r, l[2] * r, l[3] * r }}; } template SPROUT_CONSTEXPR sprout::array mul(sprout::array const& l, sprout::array const& r) { return sprout::array{{ l[0] * r[0], l[1] * r[1], l[2] * r[2], l[3] * r[3] }}; } } // namespace detail #define SPROUT_QUATERNION_ACCESSOR_GENERATOR(type) \ SPROUT_CONSTEXPR type real() const { \ return (a); \ } \ SPROUT_CONSTEXPR quaternion unreal() const { \ return (quaternion(static_cast(0), b, c, d)); \ } \ SPROUT_CONSTEXPR type R_component_1() const { \ return (a); \ } \ SPROUT_CONSTEXPR type R_component_2() const { \ return (b); \ } \ SPROUT_CONSTEXPR type R_component_3() const { \ return (c); \ } \ SPROUT_CONSTEXPR type R_component_4() const { \ return (d); \ } \ SPROUT_CONSTEXPR sprout::complex C_component_1() const { \ return sprout::complex(a, b); \ } \ SPROUT_CONSTEXPR sprout::complex C_component_2() const { \ return sprout::complex(c, d); \ } #define SPROUT_QUATERNION_MEMBER_ASSIGNMENT_GENERATOR(type) \ template \ SPROUT_CXX14_CONSTEXPR quaternion& operator=(quaternion const& a_affecter) { \ a = static_cast(a_affecter.R_component_1()); \ b = static_cast(a_affecter.R_component_2()); \ c = static_cast(a_affecter.R_component_3()); \ d = static_cast(a_affecter.R_component_4()); \ return *this; \ } \ SPROUT_CXX14_CONSTEXPR quaternion& operator=(quaternion const& a_affecter) { \ a = a_affecter.a; \ b = a_affecter.b; \ c = a_affecter.c; \ d = a_affecter.d; \ return *this; \ } \ SPROUT_CXX14_CONSTEXPR quaternion& operator=(type const& a_affecter) { \ a = a_affecter; \ b = c = d = static_cast(0); \ return *this; \ } \ SPROUT_CXX14_CONSTEXPR quaternion& operator=(sprout::complex const& a_affecter) { \ a = a_affecter.real(); \ b = a_affecter.imag(); \ c = d = static_cast(0); \ return *this; \ } #define SPROUT_QUATERNION_MEMBER_DATA_GENERATOR(type) \ type a; \ type b; \ type c; \ type d; // // quaternion // template class quaternion { public: typedef T value_type; protected: SPROUT_QUATERNION_MEMBER_DATA_GENERATOR(T) public: explicit SPROUT_CONSTEXPR quaternion( T const& requested_a = T(), T const& requested_b = T(), T const& requested_c = T(), T const& requested_d = T() ) : a(requested_a) , b(requested_b) , c(requested_c) , d(requested_d) {} explicit SPROUT_CONSTEXPR quaternion( sprout::complex const& z0, sprout::complex const& z1 = sprout::complex() ) : a(z0.real()) , b(z0.imag()) , c(z1.real()) , d(z1.imag()) {} template explicit SPROUT_CONSTEXPR quaternion(quaternion const& a_recopier) : a(static_cast(a_recopier.R_component_1())) , b(static_cast(a_recopier.R_component_2())) , c(static_cast(a_recopier.R_component_3())) , d(static_cast(a_recopier.R_component_4())) {} SPROUT_QUATERNION_ACCESSOR_GENERATOR(T) SPROUT_QUATERNION_MEMBER_ASSIGNMENT_GENERATOR(T) SPROUT_CXX14_CONSTEXPR quaternion& operator+=(T const& rhs) { T at = a + rhs; a = at; return *this; } SPROUT_CXX14_CONSTEXPR quaternion& operator+=(sprout::complex const& rhs) { T at = a + rhs.real(); T bt = b + rhs.imag(); a = at; b = bt; return *this; } template SPROUT_CXX14_CONSTEXPR quaternion& operator+=(quaternion const& rhs) { T at = a + static_cast(rhs.R_component_1()); T bt = b + static_cast(rhs.R_component_2()); T ct = c + static_cast(rhs.R_component_3()); T dt = d + static_cast(rhs.R_component_4()); a = at; b = bt; c = ct; d = dt; return *this; } SPROUT_CXX14_CONSTEXPR quaternion& operator-=(T const& rhs) { T at = a - rhs; a = at; return *this; } SPROUT_CXX14_CONSTEXPR quaternion& operator-=(sprout::complex const& rhs) { T at = a - rhs.real(); T bt = b - rhs.imag(); a = at; b = bt; return *this; } template SPROUT_CXX14_CONSTEXPR quaternion& operator-=(quaternion const& rhs) { T at = a - static_cast(rhs.R_component_1()); T bt = b - static_cast(rhs.R_component_2()); T ct = c - static_cast(rhs.R_component_3()); T dt = d - static_cast(rhs.R_component_4()); a = at; b = bt; c = ct; d = dt; return *this; } SPROUT_CXX14_CONSTEXPR quaternion& operator*=(T const& rhs) { T at = a * rhs; T bt = b * rhs; T ct = c * rhs; T dt = d * rhs; a = at; b = bt; c = ct; d = dt; return *this; } SPROUT_CXX14_CONSTEXPR quaternion& operator*=(sprout::complex const& rhs) { T ar = rhs.real(); T br = rhs.imag(); T at = +a * ar - b * br; T bt = +a * br + b * ar; T ct = +c * ar + d * br; T dt = -c * br + d * ar; a = at; b = bt; c = ct; d = dt; return *this; } template SPROUT_CXX14_CONSTEXPR quaternion& operator*=(quaternion const& rhs) { T ar = static_cast(rhs.R_component_1()); T br = static_cast(rhs.R_component_2()); T cr = static_cast(rhs.R_component_3()); T dr = static_cast(rhs.R_component_4()); T at = +a * ar - b * br - c * cr - d * dr; T bt = +a * br + b * ar + c * dr - d * cr; T ct = +a * cr - b * dr + c * ar + d * br; T dt = +a * dr + b * cr - c * br + d * ar; a = at; b = bt; c = ct; d = dt; return *this; } SPROUT_CXX14_CONSTEXPR quaternion& operator/=(T const& rhs) { T at = a / rhs; T bt = b / rhs; T ct = c / rhs; T dt = d / rhs; a = at; b = bt; c = ct; d = dt; return *this; } SPROUT_CXX14_CONSTEXPR quaternion& operator/=(sprout::complex const& rhs) { T ar = rhs.real(); T br = rhs.imag(); T denominator = ar * ar + br * br; T at =(+a * ar + b * br) / denominator; T bt =(-a * br + b * ar) / denominator; T ct =(+c * ar - d * br) / denominator; T dt =(+c * br + d * ar) / denominator; a = at; b = bt; c = ct; d = dt; return *this; } template SPROUT_CXX14_CONSTEXPR quaternion& operator/=(quaternion const& rhs) { T ar = static_cast(rhs.R_component_1()); T br = static_cast(rhs.R_component_2()); T cr = static_cast(rhs.R_component_3()); T dr = static_cast(rhs.R_component_4()); T denominator = ar * ar + br * br + cr * cr + dr * dr; T at =(+a * ar + b * br + c * cr + d * dr) / denominator; T bt =(-a * br + b * ar - c * dr + d * cr) / denominator; T ct =(-a * cr + b * dr + c * ar - d * br) / denominator; T dt =(-a * dr - b * cr + c * br + d * ar) / denominator; a = at; b = bt; c = ct; d = dt; return *this; } }; template<> class quaternion; template<> class quaternion; template<> class quaternion; #define SPROUT_QUATERNION_CONSTRUCTOR_GENERATOR(type) \ explicit SPROUT_CONSTEXPR quaternion( \ type const& requested_a = static_cast(0), \ type const& requested_b = static_cast(0), \ type const& requested_c = static_cast(0), \ type const& requested_d = static_cast(0) \ ) \ : a(requested_a) \ , b(requested_b) \ , c(requested_c) \ , d(requested_d) \ {} \ explicit SPROUT_CONSTEXPR quaternion( \ sprout::complex const& z0, \ sprout::complex const& z1 = sprout::complex() \ ) \ : a(z0.real()) \ , b(z0.imag()) \ , c(z1.real()) \ , d(z1.imag()) \ {} #define SPROUT_QUATERNION_MEMBER_ADD_GENERATOR_1(type) \ SPROUT_CXX14_CONSTEXPR quaternion& operator+=(type const& rhs) { \ a += rhs; \ return *this; \ } #define SPROUT_QUATERNION_MEMBER_ADD_GENERATOR_2(type) \ SPROUT_CXX14_CONSTEXPR quaternion& operator+=(sprout::complex const& rhs) { \ a += rhs.real(); \ b += rhs.imag(); \ return *this; \ } #define SPROUT_QUATERNION_MEMBER_ADD_GENERATOR_3(type) \ template \ SPROUT_CXX14_CONSTEXPR quaternion& operator+=(quaternion const& rhs) { \ a += static_cast(rhs.R_component_1()); \ b += static_cast(rhs.R_component_2()); \ c += static_cast(rhs.R_component_3()); \ d += static_cast(rhs.R_component_4()); \ return *this; \ } #define SPROUT_QUATERNION_MEMBER_SUB_GENERATOR_1(type) \ SPROUT_CXX14_CONSTEXPR quaternion& operator-=(type const& rhs) { \ a -= rhs; \ return *this; \ } #define SPROUT_QUATERNION_MEMBER_SUB_GENERATOR_2(type) \ SPROUT_CXX14_CONSTEXPR quaternion& operator-=(sprout::complex const& rhs) { \ a -= rhs.real(); \ b -= rhs.imag(); \ return *this; \ } #define SPROUT_QUATERNION_MEMBER_SUB_GENERATOR_3(type) \ template \ SPROUT_CXX14_CONSTEXPR quaternion& operator-=(quaternion const& rhs) { \ a -= static_cast(rhs.R_component_1()); \ b -= static_cast(rhs.R_component_2()); \ c -= static_cast(rhs.R_component_3()); \ d -= static_cast(rhs.R_component_4()); \ return *this; \ } #define SPROUT_QUATERNION_MEMBER_MUL_GENERATOR_1(type) \ SPROUT_CXX14_CONSTEXPR quaternion& operator*=(type const& rhs) { \ a *= rhs; \ b *= rhs; \ c *= rhs; \ d *= rhs; \ return *this; \ } #define SPROUT_QUATERNION_MEMBER_MUL_GENERATOR_2(type) \ SPROUT_CXX14_CONSTEXPR quaternion& operator*=(sprout::complex const& rhs) { \ type ar = rhs.real(); \ type br = rhs.imag(); \ type at = +a * ar - b * br; \ type bt = +a * br + b * ar; \ type ct = +c * ar + d * br; \ type dt = -c * br + d * ar; \ a = at; \ b = bt; \ c = ct; \ d = dt; \ return *this; \ } #define SPROUT_QUATERNION_MEMBER_MUL_GENERATOR_3(type) \ template \ SPROUT_CXX14_CONSTEXPR quaternion& operator*=(quaternion const& rhs) { \ type ar = static_cast(rhs.R_component_1()); \ type br = static_cast(rhs.R_component_2()); \ type cr = static_cast(rhs.R_component_3()); \ type dr = static_cast(rhs.R_component_4()); \ type at = +a * ar - b * br - c * cr - d * dr; \ type bt = +a * br + b * ar + c * dr - d * cr; \ type ct = +a * cr - b * dr + c * ar + d * br; \ type dt = +a * dr + b * cr - c * br + d * ar; \ a = at; \ b = bt; \ c = ct; \ d = dt; \ return *this; \ } #define SPROUT_QUATERNION_MEMBER_DIV_GENERATOR_1(type) \ SPROUT_CXX14_CONSTEXPR quaternion& operator/=(type const& rhs) { \ a /= rhs; \ b /= rhs; \ c /= rhs; \ d /= rhs; \ return *this; \ } #define SPROUT_QUATERNION_MEMBER_DIV_GENERATOR_2(type) \ SPROUT_CXX14_CONSTEXPR quaternion& operator/=(sprout::complex const& rhs) { \ sprout::array tr{{ \ rhs.real(), \ rhs.imag() \ }}; \ type mixam = static_cast(1) / sprout::math::detail::abs_max(tr); \ tr = sprout::math::detail::mul(tr, mixam); \ sprout::array tt{{ \ +a * tr[0] + b * tr[1], \ -a * tr[1] + b * tr[0], \ +c * tr[0] - d * tr[1], \ +c * tr[1] + d * tr[0] \ }}; \ tr = sprout::math::detail::mul(tr, tr); \ tt = sprout::math::detail::mul(tt, mixam / sprout::math::detail::sum(tr)); \ a = tt[0]; \ b = tt[1]; \ c = tt[2]; \ d = tt[3]; \ return *this; \ } #define SPROUT_QUATERNION_MEMBER_DIV_GENERATOR_3(type) \ template \ SPROUT_CXX14_CONSTEXPR quaternion& operator/=(quaternion const& rhs) { \ sprout::array tr{{ \ static_cast(rhs.R_component_1()), \ static_cast(rhs.R_component_2()), \ static_cast(rhs.R_component_3()), \ static_cast(rhs.R_component_4()) \ }}; \ type mixam = static_cast(1) / sprout::math::detail::abs_max(tr); \ tr = sprout::math::detail::mul(tr, mixam); \ sprout::array tt{{ \ +a * tr[0] + b * tr[1] + c * tr[2] + d * tr[3], \ -a * tr[1] + b * tr[0] - c * tr[3] + d * tr[2], \ -a * tr[2] + b * tr[3] + c * tr[0] - d * tr[1], \ -a * tr[3] - b * tr[2] + c * tr[1] + d * tr[0] \ }}; \ tr = sprout::math::detail::mul(tr, tr); \ tt = sprout::math::detail::mul(tt, mixam / sprout::math::detail::sum(tr)); \ a = tt[0]; \ b = tt[1]; \ c = tt[2]; \ d = tt[3]; \ return *this; \ } #define SPROUT_QUATERNION_MEMBER_ADD_GENERATOR(type) \ SPROUT_QUATERNION_MEMBER_ADD_GENERATOR_1(type) \ SPROUT_QUATERNION_MEMBER_ADD_GENERATOR_2(type) \ SPROUT_QUATERNION_MEMBER_ADD_GENERATOR_3(type) #define SPROUT_QUATERNION_MEMBER_SUB_GENERATOR(type) \ SPROUT_QUATERNION_MEMBER_SUB_GENERATOR_1(type) \ SPROUT_QUATERNION_MEMBER_SUB_GENERATOR_2(type) \ SPROUT_QUATERNION_MEMBER_SUB_GENERATOR_3(type) #define SPROUT_QUATERNION_MEMBER_MUL_GENERATOR(type) \ SPROUT_QUATERNION_MEMBER_MUL_GENERATOR_1(type) \ SPROUT_QUATERNION_MEMBER_MUL_GENERATOR_2(type) \ SPROUT_QUATERNION_MEMBER_MUL_GENERATOR_3(type) #define SPROUT_QUATERNION_MEMBER_DIV_GENERATOR(type) \ SPROUT_QUATERNION_MEMBER_DIV_GENERATOR_1(type) \ SPROUT_QUATERNION_MEMBER_DIV_GENERATOR_2(type) \ SPROUT_QUATERNION_MEMBER_DIV_GENERATOR_3(type) #define SPROUT_QUATERNION_MEMBER_ALGEBRAIC_GENERATOR(type) \ SPROUT_QUATERNION_MEMBER_ADD_GENERATOR(type) \ SPROUT_QUATERNION_MEMBER_SUB_GENERATOR(type) \ SPROUT_QUATERNION_MEMBER_MUL_GENERATOR(type) \ SPROUT_QUATERNION_MEMBER_DIV_GENERATOR(type) template<> class quaternion { public: typedef float value_type; protected: SPROUT_QUATERNION_MEMBER_DATA_GENERATOR(float) public: SPROUT_QUATERNION_CONSTRUCTOR_GENERATOR(float) explicit SPROUT_CONSTEXPR quaternion(quaternion const& a_recopier); explicit SPROUT_CONSTEXPR quaternion(quaternion const& a_recopier); SPROUT_QUATERNION_ACCESSOR_GENERATOR(float) SPROUT_QUATERNION_MEMBER_ASSIGNMENT_GENERATOR(float) SPROUT_QUATERNION_MEMBER_ALGEBRAIC_GENERATOR(float) }; template<> class quaternion { public: typedef double value_type; protected: SPROUT_QUATERNION_MEMBER_DATA_GENERATOR(double) public: SPROUT_QUATERNION_CONSTRUCTOR_GENERATOR(double) explicit SPROUT_CONSTEXPR quaternion(quaternion const& a_recopier); explicit SPROUT_CONSTEXPR quaternion(quaternion const& a_recopier); SPROUT_QUATERNION_ACCESSOR_GENERATOR(double) SPROUT_QUATERNION_MEMBER_ASSIGNMENT_GENERATOR(double) SPROUT_QUATERNION_MEMBER_ALGEBRAIC_GENERATOR(double) }; template<> class quaternion { public: typedef double value_type; protected: SPROUT_QUATERNION_MEMBER_DATA_GENERATOR(long double) public: SPROUT_QUATERNION_CONSTRUCTOR_GENERATOR(long double) explicit SPROUT_CONSTEXPR quaternion(quaternion const& a_recopier); explicit SPROUT_CONSTEXPR quaternion(quaternion const& a_recopier); SPROUT_QUATERNION_ACCESSOR_GENERATOR(long double) SPROUT_QUATERNION_MEMBER_ASSIGNMENT_GENERATOR(long double) SPROUT_QUATERNION_MEMBER_ALGEBRAIC_GENERATOR(long double) }; SPROUT_CONSTEXPR sprout::math::quaternion::quaternion(sprout::math::quaternion const& a_recopier) : a(static_cast(a_recopier.R_component_1())) , b(static_cast(a_recopier.R_component_2())) , c(static_cast(a_recopier.R_component_3())) , d(static_cast(a_recopier.R_component_4())) {} SPROUT_CONSTEXPR sprout::math::quaternion::quaternion(sprout::math::quaternion const& a_recopier) : a(static_cast(a_recopier.R_component_1())) , b(static_cast(a_recopier.R_component_2())) , c(static_cast(a_recopier.R_component_3())) , d(static_cast(a_recopier.R_component_4())) {} SPROUT_CONSTEXPR sprout::math::quaternion::quaternion(sprout::math::quaternion const& a_recopier) : a(static_cast(a_recopier.R_component_1())) , b(static_cast(a_recopier.R_component_2())) , c(static_cast(a_recopier.R_component_3())) , d(static_cast(a_recopier.R_component_4())) {} SPROUT_CONSTEXPR sprout::math::quaternion::quaternion(sprout::math::quaternion const& a_recopier) : a(static_cast(a_recopier.R_component_1())) , b(static_cast(a_recopier.R_component_2())) , c(static_cast(a_recopier.R_component_3())) , d(static_cast(a_recopier.R_component_4())) {} SPROUT_CONSTEXPR sprout::math::quaternion::quaternion(sprout::math::quaternion const& a_recopier) : a(static_cast(a_recopier.R_component_1())) , b(static_cast(a_recopier.R_component_2())) , c(static_cast(a_recopier.R_component_3())) , d(static_cast(a_recopier.R_component_4())) {} SPROUT_CONSTEXPR sprout::math::quaternion::quaternion(sprout::math::quaternion const& a_recopier) : a(static_cast(a_recopier.R_component_1())) , b(static_cast(a_recopier.R_component_2())) , c(static_cast(a_recopier.R_component_3())) , d(static_cast(a_recopier.R_component_4())) {} #undef SPROUT_QUATERNION_MEMBER_ALGEBRAIC_GENERATOR #undef SPROUT_QUATERNION_MEMBER_ADD_GENERATOR #undef SPROUT_QUATERNION_MEMBER_SUB_GENERATOR #undef SPROUT_QUATERNION_MEMBER_MUL_GENERATOR #undef SPROUT_QUATERNION_MEMBER_DIV_GENERATOR #undef SPROUT_QUATERNION_MEMBER_ADD_GENERATOR_1 #undef SPROUT_QUATERNION_MEMBER_ADD_GENERATOR_2 #undef SPROUT_QUATERNION_MEMBER_ADD_GENERATOR_3 #undef SPROUT_QUATERNION_MEMBER_SUB_GENERATOR_1 #undef SPROUT_QUATERNION_MEMBER_SUB_GENERATOR_2 #undef SPROUT_QUATERNION_MEMBER_SUB_GENERATOR_3 #undef SPROUT_QUATERNION_MEMBER_MUL_GENERATOR_1 #undef SPROUT_QUATERNION_MEMBER_MUL_GENERATOR_2 #undef SPROUT_QUATERNION_MEMBER_MUL_GENERATOR_3 #undef SPROUT_QUATERNION_MEMBER_DIV_GENERATOR_1 #undef SPROUT_QUATERNION_MEMBER_DIV_GENERATOR_2 #undef SPROUT_QUATERNION_MEMBER_DIV_GENERATOR_3 #undef SPROUT_QUATERNION_CONSTRUCTOR_GENERATOR #undef SPROUT_QUATERNION_MEMBER_ASSIGNMENT_GENERATOR #undef SPROUT_QUATERNION_MEMBER_DATA_GENERATOR #undef SPROUT_QUATERNION_ACCESSOR_GENERATOR // // operator+ // template inline SPROUT_CONSTEXPR sprout::math::quaternion operator+(T const& lhs, sprout::math::quaternion const& rhs) { return sprout::math::quaternion( lhs + rhs.R_component_1(), rhs.R_component_2(), rhs.R_component_3(), rhs.R_component_4() ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion operator+(sprout::math::quaternion const& lhs, T const& rhs) { return sprout::math::quaternion( lhs.R_component_1() + rhs, lhs.R_component_2(), lhs.R_component_3(), lhs.R_component_4() ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion operator+(sprout::complex const& lhs, sprout::math::quaternion const& rhs) { return sprout::math::quaternion( lhs.real() + rhs.R_component_1(), lhs.imag() + rhs.R_component_2(), rhs.R_component_3(), rhs.R_component_4() ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion operator+(sprout::math::quaternion const& lhs, sprout::complex const& rhs) { return sprout::math::quaternion( lhs.R_component_1() + rhs.real(), lhs.R_component_2() + rhs.imag(), lhs.R_component_3(), lhs.R_component_4() ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion operator+(sprout::math::quaternion const& lhs, sprout::math::quaternion const& rhs) { return sprout::math::quaternion( lhs.R_component_1() + rhs.R_component_1(), lhs.R_component_2() + rhs.R_component_2(), lhs.R_component_3() + rhs.R_component_3(), lhs.R_component_4() + rhs.R_component_4() ); } // // operator- // template inline SPROUT_CONSTEXPR sprout::math::quaternion operator-(T const& lhs, sprout::math::quaternion const& rhs) { return sprout::math::quaternion( lhs - rhs.R_component_1(), rhs.R_component_2(), rhs.R_component_3(), rhs.R_component_4() ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion operator-(sprout::math::quaternion const& lhs, T const& rhs) { return sprout::math::quaternion( lhs.R_component_1() - rhs, lhs.R_component_2(), lhs.R_component_3(), lhs.R_component_4() ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion operator-(sprout::complex const& lhs, sprout::math::quaternion const& rhs) { return sprout::math::quaternion( lhs.real() - rhs.R_component_1(), lhs.imag() - rhs.R_component_2(), rhs.R_component_3(), rhs.R_component_4() ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion operator-(sprout::math::quaternion const& lhs, sprout::complex const& rhs) { return sprout::math::quaternion( lhs.R_component_1() - rhs.real(), lhs.R_component_2() - rhs.imag(), lhs.R_component_3(), lhs.R_component_4() ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion operator-(sprout::math::quaternion const& lhs, sprout::math::quaternion const& rhs) { return sprout::math::quaternion( lhs.R_component_1() - rhs.R_component_1(), lhs.R_component_2() - rhs.R_component_2(), lhs.R_component_3() - rhs.R_component_3(), lhs.R_component_4() - rhs.R_component_4() ); } // // operator* // template inline SPROUT_CONSTEXPR sprout::math::quaternion operator*(T const& lhs, sprout::math::quaternion const& rhs) { return sprout::math::quaternion( lhs * rhs.R_component_1(), lhs * rhs.R_component_2(), lhs * rhs.R_component_3(), lhs * rhs.R_component_4() ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion operator*(sprout::math::quaternion const& lhs, T const& rhs) { return sprout::math::quaternion( lhs.R_component_1() * rhs, lhs.R_component_2() * rhs, lhs.R_component_3() * rhs, lhs.R_component_4() * rhs ); } namespace detail { template inline SPROUT_CONSTEXPR sprout::math::quaternion mul_qc_impl(T const& a, T const& b, T const& c, T const& d, T const& ar, T const& br) { return sprout::math::quaternion( +a * ar - b * br, +a * br + b * ar, +c * ar + d * br, -c * br + d * ar ); } } // namespace detail template inline SPROUT_CONSTEXPR sprout::math::quaternion operator*(sprout::complex const& lhs, sprout::math::quaternion const& rhs) { return sprout::math::detail::mul_qc_impl( lhs.R_component_1(), lhs.R_component_2(), lhs.R_component_3(), lhs.R_component_4(), rhs.real(), rhs.imag() ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion operator*(sprout::math::quaternion const& lhs, sprout::complex const& rhs) { return sprout::math::detail::mul_qc_impl( rhs.R_component_1(), rhs.R_component_2(), rhs.R_component_3(), rhs.R_component_4(), lhs.real(), lhs.imag() ); } namespace detail { template inline SPROUT_CONSTEXPR sprout::math::quaternion mul_qq_impl(T const& a, T const& b, T const& c, T const& d, T const& ar, T const& br, T const& cr, T const& dr) { return sprout::math::quaternion( +a * ar - b * br - c * cr - d * dr, +a * br + b * ar + c * dr - d * cr, +a * cr - b * dr + c * ar + d * br, +a * dr + b * cr - c * br + d * ar ); } } // namespace detail template inline SPROUT_CONSTEXPR sprout::math::quaternion operator*(sprout::math::quaternion const& lhs, sprout::math::quaternion const& rhs) { return sprout::math::detail::mul_qq_impl( lhs.R_component_1(), lhs.R_component_2(), lhs.R_component_3(), lhs.R_component_4(), rhs.R_component_1(), rhs.R_component_2(), rhs.R_component_3(), rhs.R_component_4() ); } // // operator/ // template inline SPROUT_CONSTEXPR sprout::math::quaternion operator/(T const& lhs, sprout::math::quaternion const& rhs) { return sprout::math::quaternion( lhs / rhs.R_component_1(), lhs / rhs.R_component_2(), lhs / rhs.R_component_3(), lhs / rhs.R_component_4() ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion operator/(sprout::math::quaternion const& lhs, T const& rhs) { return sprout::math::quaternion( lhs.R_component_1() / rhs, lhs.R_component_2() / rhs, lhs.R_component_3() / rhs, lhs.R_component_4() / rhs ); } namespace detail { template inline SPROUT_CONSTEXPR sprout::math::quaternion div_qq_impl_4(sprout::array const& tt) { return sprout::math::quaternion( tt[0], tt[1], tt[2], tt[3] ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion div_qq_impl_3(sprout::array const& tr, T const& mixam, sprout::array const& tt) { return sprout::math::detail::div_qq_impl_3( sprout::math::detail::mul(tt, mixam / sprout::math::detail::sum(tr)) ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion div_qq_impl_2(T const& a, T const& b, T const& c, T const& d, sprout::array const& tr, T const& mixam) { return sprout::math::detail::div_qq_impl_3( sprout::math::detail::mul(tr, tr), mixam, sprout::array{{ +a * tr[0] + b * tr[1] + c * tr[2] + d * tr[3], -a * tr[1] + b * tr[0] - c * tr[3] + d * tr[2], -a * tr[2] + b * tr[3] + c * tr[0] - d * tr[1], -a * tr[3] - b * tr[2] + c * tr[1] + d * tr[0] }} ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion div_qq_impl_1(T const& a, T const& b, T const& c, T const& d, sprout::array const& tr, T const& mixam) { return sprout::math::detail::div_qq_impl_2( a, b, c, d, sprout::math::detail::mul(tr, mixam), mixam ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion div_qq_impl(T const& a, T const& b, T const& c, T const& d, sprout::array const& tr) { return sprout::math::detail::div_qq_impl_1( a, b, c, d, tr, static_cast(1) / sprout::math::detail::abs_max(tr) ); } } // namespace detail template inline SPROUT_CONSTEXPR sprout::math::quaternion operator/(sprout::complex const& lhs, sprout::math::quaternion const& rhs) { return sprout::math::detail::div_qq_impl( lhs.real(), lhs.imag(), static_cast(0), static_cast(0), sprout::array{{rhs.R_component_1(), rhs.R_component_2(), rhs.R_component_3(), rhs.R_component_4()}} ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion operator/(sprout::math::quaternion const& lhs, sprout::complex const& rhs) { return sprout::math::detail::div_qq_impl( lhs.R_component_1(), lhs.R_component_2(), lhs.R_component_3(), lhs.R_component_4(), sprout::array{{rhs.real(), rhs.imag(), static_cast(0), static_cast(0)}} ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion operator/(sprout::math::quaternion const& lhs, sprout::math::quaternion const& rhs) { return sprout::math::detail::div_qq_impl( lhs.R_component_1(), lhs.R_component_2(), lhs.R_component_3(), lhs.R_component_4(), sprout::array{{rhs.R_component_1(), rhs.R_component_2(), rhs.R_component_3(), rhs.R_component_4()}} ); } // // operator+ // operator- // template inline SPROUT_CONSTEXPR sprout::math::quaternion operator+(sprout::math::quaternion const& q) { return q; } template inline SPROUT_CONSTEXPR sprout::math::quaternion operator-(sprout::math::quaternion const& q) { return sprout::math::quaternion(-q.R_component_1(), -q.R_component_2(), -q.R_component_3(), -q.R_component_4()); } // // operator== // operator!= // template inline SPROUT_CONSTEXPR bool operator==(T const& lhs, sprout::math::quaternion const& rhs) { return rhs.R_component_1() == lhs && rhs.R_component_2() == static_cast(0) && rhs.R_component_3() == static_cast(0) && rhs.R_component_4() == static_cast(0) ; } template inline SPROUT_CONSTEXPR bool operator==(sprout::math::quaternion const& lhs, T const& rhs) { return lhs.R_component_1() == rhs && lhs.R_component_2() == static_cast(0) && lhs.R_component_3() == static_cast(0) && lhs.R_component_4() == static_cast(0) ; } template inline SPROUT_CONSTEXPR bool operator==(sprout::complex const& lhs, sprout::math::quaternion const& rhs) { return rhs.R_component_1() == lhs.real() && rhs.R_component_2() == lhs.imag() && rhs.R_component_3() == static_cast(0) && rhs.R_component_4() == static_cast(0) ; } template inline SPROUT_CONSTEXPR bool operator==(sprout::math::quaternion const& lhs, sprout::complex const& rhs) { return lhs.R_component_1() == rhs.real() && lhs.R_component_2() == rhs.imag() && lhs.R_component_3() == static_cast(0) && lhs.R_component_4() == static_cast(0) ; } template inline SPROUT_CONSTEXPR bool operator==(sprout::math::quaternion const& lhs, sprout::math::quaternion const& rhs) { return rhs.R_component_1() == lhs.R_component_1() && rhs.R_component_2() == lhs.R_component_2() && rhs.R_component_3() == lhs.R_component_3() && rhs.R_component_4() == lhs.R_component_4() ; } #define SPROUT_QUATERNION_NOT_EQUAL_GENERATOR \ { \ return !(lhs == rhs); \ } template inline SPROUT_CONSTEXPR bool operator!=(T const& lhs, sprout::math::quaternion const& rhs) SPROUT_QUATERNION_NOT_EQUAL_GENERATOR template inline SPROUT_CONSTEXPR bool operator!=(sprout::math::quaternion const& lhs, T const& rhs) SPROUT_QUATERNION_NOT_EQUAL_GENERATOR template inline SPROUT_CONSTEXPR bool operator!=(sprout::complex const& lhs, sprout::math::quaternion const& rhs) SPROUT_QUATERNION_NOT_EQUAL_GENERATOR template inline SPROUT_CONSTEXPR bool operator!=(sprout::math::quaternion const& lhs, sprout::complex const& rhs) SPROUT_QUATERNION_NOT_EQUAL_GENERATOR template inline SPROUT_CONSTEXPR bool operator!=(sprout::math::quaternion const& lhs, sprout::math::quaternion const& rhs) SPROUT_QUATERNION_NOT_EQUAL_GENERATOR #undef SPROUT_QUATERNION_NOT_EQUAL_GENERATOR // // operator<< // operator>> // template inline SPROUT_NON_CONSTEXPR std::basic_ostream& operator<<( std::basic_ostream& lhs, sprout::math::quaternion const& rhs) { std::basic_ostringstream s; s.flags(lhs.flags()); s.imbue(lhs.getloc()); s.precision(lhs.precision()); s << '(' << rhs.R_component_1() << ',' << rhs.R_component_2() << ',' << rhs.R_component_3() << ',' << rhs.R_component_4() << ')' ; return lhs << s.str(); } template inline SPROUT_NON_CONSTEXPR std::basic_istream& operator>>(std::basic_istream& lhs, sprout::math::quaternion& rhs) { std::ctype const& ct = std::use_facet >(lhs.getloc()); T a = T(); T b = T(); T c = T(); T d = T(); sprout::complex u = sprout::complex(); sprout::complex v = sprout::complex(); Elem ch = Elem(); char cc; lhs >> ch; if (!lhs.good()) { goto finish; } cc = ct.narrow(ch, char()); if (cc == '(') { lhs >> ch; if (!lhs.good()) { goto finish; } cc = ct.narrow(ch, char()); if (cc == '(') { lhs.putback(ch); lhs >> u; a = u.real(); b = u.imag(); if (!lhs.good()) { goto finish; } lhs >> ch; if (!lhs.good()) { goto finish; } cc = ct.narrow(ch, char()); if (cc == ')') { rhs = sprout::math::quaternion(a, b); } else if (cc == ',') { lhs >> v; c = v.real(); d = v.imag(); if (!lhs.good()) { goto finish; } lhs >> ch; if (!lhs.good()) { goto finish; } cc = ct.narrow(ch, char()); if (cc == ')') { rhs = sprout::math::quaternion(a, b, c, d); } else { lhs.setstate(std::ios_base::failbit); } } else { lhs.setstate(std::ios_base::failbit); } } else { lhs.putback(ch); lhs >> a; if (!lhs.good()) { goto finish; } lhs >> ch; if (!lhs.good()) { goto finish; } cc = ct.narrow(ch, char()); if (cc == ')') { rhs = sprout::math::quaternion(a); } else if (cc == ',') { lhs >> ch; if (!lhs.good()) { goto finish; } cc = ct.narrow(ch, char()); if (cc == '(') { lhs.putback(ch); lhs >> v; c = v.real(); d = v.imag(); if (!lhs.good()) { goto finish; } lhs >> ch; if (!lhs.good()) { goto finish; } cc = ct.narrow(ch, char()); if (cc == ')') { rhs = sprout::math::quaternion(a, b, c, d); } else { lhs.setstate(std::ios_base::failbit); } } else { lhs.putback(ch); lhs >> b; if (!lhs.good()) { goto finish; } lhs >> ch; if (!lhs.good()) { goto finish; } cc = ct.narrow(ch, char()); if (cc == ')') { rhs = sprout::math::quaternion(a, b); } else if (cc == ',') { lhs >> c; if (!lhs.good()) { goto finish; } lhs >> ch; if (!lhs.good()) { goto finish; } cc = ct.narrow(ch, char()); if (cc == ')') { rhs = sprout::math::quaternion(a, b, c); } else if (cc == ',') { lhs >> d; if (!lhs.good()) { goto finish; } lhs >> ch; if (!lhs.good()) { goto finish; } cc = ct.narrow(ch, char()); if (cc == ')') { rhs = sprout::math::quaternion(a, b, c, d); } else { lhs.setstate(std::ios_base::failbit); } } else { lhs.setstate(std::ios_base::failbit); } } else { lhs.setstate(std::ios_base::failbit); } } } else { lhs.setstate(std::ios_base::failbit); } } } else { lhs.putback(ch); lhs >> a; if (!lhs.good()) { goto finish; } rhs = sprout::math::quaternion(a); } finish: return lhs; } // // real // unreal // template inline SPROUT_CONSTEXPR T real(sprout::math::quaternion const& q) { return q.real(); } template inline SPROUT_CONSTEXPR sprout::math::quaternion unreal(sprout::math::quaternion const& q) { return q.unreal(); } // // sup // l1 // template inline SPROUT_CONSTEXPR T sup(sprout::math::quaternion const& q) { return sprout::math::detail::abs_max( sprout::array{{ q.R_component_1(), q.R_component_2(), q.R_component_3(), q.R_component_4() }} ); } template inline SPROUT_CONSTEXPR T l1(sprout::math::quaternion const& q) { return sprout::math::detail::abs_sum( sprout::array{{ q.R_component_1(), q.R_component_2(), q.R_component_3(), q.R_component_4() }} ); } // // abs // namespace detail { template inline SPROUT_CONSTEXPR T abs_q_impl_3(sprout::array const& temp, T const& maxim) { return maxim * sprout::math::sqrt(sprout::math::detail::sum(sprout::math::detail::mul(temp, temp))); } template inline SPROUT_CONSTEXPR T abs_q_impl_2(sprout::array const& temp, T const& maxim) { return sprout::math::detail::abs_q_impl_3( sprout::math::detail::mul(temp, maxim), maxim ); } template inline SPROUT_CONSTEXPR T abs_q_impl_1(sprout::array const& temp, T const& maxim) { return maxim == static_cast(0) ? sprout::math::quaternion(maxim) : sprout::math::detail::abs_q_impl_2( temp, static_cast(1) / maxim ) ; } template inline SPROUT_CONSTEXPR T abs_q_impl(sprout::array const& temp) { return sprout::math::detail::abs_q_impl_1( temp, sprout::math::detail::abs_max(temp) ); } } // namespace detail template inline SPROUT_CONSTEXPR T abs(sprout::math::quaternion const& q) { return sprout::math::detail::abs_q_impl( sprout::array{{ q.R_component_1(), q.R_component_2(), q.R_component_3(), q.R_component_4() }} ); } #undef SPROUT_QUATERNION_ARRAY_LOADER // // conj // norm // template inline SPROUT_CONSTEXPR sprout::math::quaternion conj(sprout::math::quaternion const& q) { return sprout::math::quaternion( +q.R_component_1(), -q.R_component_2(), -q.R_component_3(), -q.R_component_4() ); } template inline SPROUT_CONSTEXPR T norm(sprout::math::quaternion const& q) { return sprout::math::real(q * sprout::math::conj(q)); } // // spherical // semipolar // multipolar // cylindrospherical // cylindrical // namespace detail { template inline SPROUT_CONSTEXPR sprout::math::quaternion spherical_impl(T const& rho, T const& theta, T const& phi1, T const& phi2, T const& p1, T const& p2) { return rho * sprout::math::quaternion( sprout::math::cos(theta) * (p2 * p1), sprout::math::sin(theta) * (p2 * p1), sprout::math::sin(phi1) * p2, sprout::math::sin(phi2) ); } } // namespace detail template inline SPROUT_CONSTEXPR sprout::math::quaternion spherical(T const& rho, T const& theta, T const& phi1, T const& phi2) { return sprout::math::detail::spherical_impl( rho, theta, phi1, phi2, sprout::math::cos(phi1), sprout::math::cos(phi2) ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion semipolar(T const& rho, T const& alpha, T const& theta1, T const& theta2) { return rho * sprout::math::quaternion( sprout::math::cos(alpha) * sprout::math::cos(theta1), sprout::math::cos(alpha) * sprout::math::sin(theta1), sprout::math::sin(alpha) * sprout::math::cos(theta2), sprout::math::sin(alpha) * sprout::math::sin(theta2) ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion multipolar(T const& rho1, T const& theta1, T const& rho2, T const& theta2) { return sprout::math::quaternion( rho1 * sprout::math::cos(theta1), rho1 * sprout::math::sin(theta1), rho2 * sprout::math::cos(theta2), rho2 * sprout::math::sin(theta2) ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion cylindrospherical(T const& t, T const& radius, T const& longitude, T const& latitude) { return sprout::math::quaternion( t, radius * sprout::math::cos(longitude) * sprout::math::cos(latitude), radius * sprout::math::sin(longitude) * sprout::math::cos(latitude), radius * sprout::math::sin(latitude) ); } template inline SPROUT_CONSTEXPR sprout::math::quaternion cylindrical(T const& r, T const& angle, T const& h1, T const& h2) { return sprout::math::quaternion( r * sprout::math::cos(angle), r * sprout::math::sin(angle), h1, h2 ); } // // exp // // !!! // namespace detail { // template // inline SPROUT_CONSTEXPR sprout::math::quaternion // exp_impl_1(sprout::math::quaternion const& q, T const& z, T const& w) { // return sprout::math::exp(sprout::math::real(q)) * sprout::math::quaternion( // sprout::math::cos(z), // w * q.R_component_2(), // w * q.R_component_3(), // w * q.R_component_4() // ); // } // template // inline SPROUT_CONSTEXPR sprout::math::quaternion // exp_impl(sprout::math::quaternion const& q, T const& z) { // return sprout::math::detail::exp_impl_1( // q, z, // sprout::math::sinc_pi(z) // ); // } // } // namespace detail // inline SPROUT_CONSTEXPR sprout::math::quaternion // exp(sprout::math::quaternion const& q) { // return sprout::math::detail::exp_impl( // q, // sprout::math::abs(sprout::math::unreal(q)) // ); // } // // cos // sin // tan // // !!! // namespace detail { // template // inline SPROUT_CONSTEXPR sprout::math::quaternion // cos_impl_1(sprout::math::quaternion const& q, T const& z, T const& w) { // return sprout::math::quaternion( // sprout::math::cos(q.real()) * sprout::math::cosh(z), // w * q.R_component_2(), // w * q.R_component_3(), // w * q.R_component_4() // ); // } // template // inline SPROUT_CONSTEXPR sprout::math::quaternion // cos_impl(sprout::math::quaternion const& q, T const& z) { // return sprout::math::detail::cos_impl_1( // q, z, // -sprout::math::sin(q.real()) * sprout::math::sinhc_pi(z) // ); // } // } // namespace detail // template // inline SPROUT_CONSTEXPR sprout::math::quaternion // cos(sprout::math::quaternion const& q) { // return sprout::math::detail::cos_impl( // q, // sprout::math::abs(sprout::math::unreal(q)) // ); // } // namespace detail { // template // inline SPROUT_CONSTEXPR sprout::math::quaternion // sin_impl_1(sprout::math::quaternion const& q, T const& z, T const& w) { // return sprout::math::quaternion( // sprout::math::sin(q.real()) * sprout::math::cosh(z), // w * q.R_component_2(), // w * q.R_component_3(), // w * q.R_component_4() // ); // } // template // inline SPROUT_CONSTEXPR sprout::math::quaternion // sin_impl(sprout::math::quaternion const& q, T const& z) { // return sprout::math::detail::sin_impl_1( // q, z, // +sprout::math::cos(q.real()) * sprout::math::sinhc_pi(z) // ); // } // } // namespace detail // template // inline SPROUT_CONSTEXPR sprout::math::quaternion // sin(sprout::math::quaternion const& q) { // return sprout::math::detail::sin_impl( // q, // sprout::math::abs(sprout::math::unreal(q)) // ); // } // template // inline SPROUT_CONSTEXPR sprout::math::quaternion // tan(sprout::math::quaternion const& q) { // return sprout::math::sin(q) / sprout::math::cos(q); // } // // cosh // sinh // tanh // // !!! // template // inline SPROUT_CONSTEXPR sprout::math::quaternion // cosh(sprout::math::quaternion const& q) { // return (sprout::math::exp(+q) + sprout::math::exp(-q)) / static_cast(2); // } // template // inline SPROUT_CONSTEXPR sprout::math::quaternion // sinh(sprout::math::quaternion const& q) { // return (sprout::math::exp(+q) - sprout::math::exp(-q)) / static_cast(2); // } // template // inline SPROUT_CONSTEXPR sprout::math::quaternion // tanh(sprout::math::quaternion const& q) { // return sprout::math::sinh(q) / sprout::math::cosh(q); // } // // pow // namespace detail { template inline SPROUT_CONSTEXPR sprout::math::quaternion pow_q_impl(sprout::math::quaternion const& q, int n, int m, sprout::math::quaternion const& result) { return n != m << 1 ? result * result * q : result * result ; } } // namespace detail template inline SPROUT_CONSTEXPR sprout::math::quaternion pow(sprout::math::quaternion const& q, int n) { return n > 1 ? sprout::math::detail::pow_q_impl( q, n, n >> 1, sprout::math::pow(q, n >> 1) ) : n == 1 ? q : n == 0 ? sprout::math::quaternion(static_cast(1)) : sprout::math::pow(sprout::math::quaternion(static_cast(1)) / q, -n) ; } } // namespace math using sprout::math::quaternion; using sprout::math::real; using sprout::math::unreal; using sprout::math::sup; using sprout::math::l1; using sprout::math::abs; using sprout::math::conj; using sprout::math::norm; using sprout::math::spherical; using sprout::math::semipolar; using sprout::math::multipolar; using sprout::math::cylindrospherical; using sprout::math::cylindrical; // using sprout::math::exp; // using sprout::math::cos; // using sprout::math::sin; // using sprout::math::tan; // using sprout::math::cosh; // using sprout::math::sinh; // using sprout::math::tanh; using sprout::math::pow; } // namespace sprout #endif // #ifndef SPROUT_MATH_QUATERNION_HPP