// L============================================================================= // L This software is distributed under the MIT license. // L Copyright 2021 Péter Kardos // L============================================================================= #pragma once #include "QuaternionImpl.hpp" namespace mathter { namespace impl { template Quaternion Product(const Quaternion& lhs, const Quaternion& rhs) { if constexpr (IsBatched()) { using Vec4 = Vector; const auto lhsv = lhs.vec; const auto rhsv = rhs.vec; const Vec4 s1 = { -1, 1, -1, 1 }; const Vec4 s2 = { -1, 1, 1, -1 }; const Vec4 s3 = { -1, -1, 1, 1 }; // [ 3, 2, 1, 0 ] // [ 0, 3, 2, 1 ] const Vec4 t0 = lhsv.xxxx; const Vec4 t1 = rhsv.xyzw; const Vec4 t2 = lhsv.yyyy; const Vec4 t3 = rhsv.yxwz; const Vec4 t4 = lhsv.zzzz; const Vec4 t5 = rhsv.zwxy; const Vec4 t6 = lhsv.wwww; const Vec4 t7 = rhsv.wzyx; const auto m0 = t0 * t1; const auto m1 = s1 * t2 * t3; const auto m2 = s2 * t4 * t5; const auto m3 = s3 * t6 * t7; const auto s = m0 + m1 + m2 + m3; const auto w = lhs.s * rhs.s - lhs.x * rhs.x - lhs.y * rhs.y - lhs.z * rhs.z; const auto x = lhs.s * rhs.x + lhs.x * rhs.s + lhs.y * rhs.z - lhs.z * rhs.y; const auto y = lhs.s * rhs.y - lhs.x * rhs.z + lhs.y * rhs.s + lhs.z * rhs.x; const auto z = lhs.s * rhs.z + lhs.x * rhs.y - lhs.y * rhs.x + lhs.z * rhs.s; return Quaternion{ s }; } else { const auto w = lhs.s * rhs.s - lhs.x * rhs.x - lhs.y * rhs.y - lhs.z * rhs.z; const auto x = lhs.s * rhs.x + lhs.x * rhs.s + lhs.y * rhs.z - lhs.z * rhs.y; const auto y = lhs.s * rhs.y - lhs.x * rhs.z + lhs.y * rhs.s + lhs.z * rhs.x; const auto z = lhs.s * rhs.z + lhs.x * rhs.y - lhs.y * rhs.x + lhs.z * rhs.s; return { w, x, y, z }; } } } // namespace impl template Quaternion& operator+=(Quaternion& lhs, const Quaternion& rhs) { lhs.vec += rhs.vec; return lhs; } // Helpers to write quaternion in paper-style such as (1 + 2_i + 3_j + 4_k). Slow performance, be careful. template Quaternion& operator-=(Quaternion& lhs, const Quaternion& rhs) { lhs.vec -= rhs.vec; return lhs; } template Quaternion& operator*=(Quaternion& lhs, const Quaternion& rhs) { lhs = impl::Product(lhs, rhs); return lhs; } template Quaternion& operator*=(Quaternion& lhs, T s) { lhs.vec *= s; return lhs; } template Quaternion& operator/=(Quaternion& lhs, T s) { lhs *= T(1) / s; return lhs; } template Quaternion operator+(const Quaternion& lhs, const Quaternion& rhs) { Quaternion copy(lhs); copy += rhs; return copy; } template Quaternion operator-(const Quaternion& lhs, const Quaternion& rhs) { Quaternion copy(lhs); copy -= rhs; return copy; } template Quaternion operator*(const Quaternion& lhs, const Quaternion& rhs) { Quaternion copy(lhs); copy *= rhs; return copy; } template Quaternion operator*(const Quaternion& lhs, T s) { Quaternion copy(lhs); copy *= s; return copy; } template Quaternion operator/(const Quaternion& lhs, T s) { Quaternion copy(lhs); copy /= s; return copy; } template Quaternion operator+(const Quaternion& arg) { return arg; } template Quaternion operator-(const Quaternion& arg) { return Quaternion(-arg.vec); } /// Multiplies all coefficients of the quaternion by . template >::value>::type> Quaternion operator*(U s, const Quaternion& rhs) { return rhs * s; } /// Divides all coefficients of the quaternion by . template >::value>::type> Quaternion operator/(U s, const Quaternion& rhs) { return rhs / s; } /// Adds a real to the real part of the quaternion. template ::value>::type> Quaternion operator+(const U& lhs, const Quaternion& rhs) { return Quaternion(rhs.w + lhs, rhs.x, rhs.y, rhs.z); } } // namespace mathter