/** * @file Quaternion.hpp * * A quaternion class. * * @author James Goppert */ #pragma once #include "math.hpp" #include "helper_functions.hpp" namespace matrix { template class Dcm; template class Euler; template class Quaternion : public Vector { public: virtual ~Quaternion() {}; typedef Matrix Matrix41; typedef Matrix Matrix31; Quaternion() : Vector() { Quaternion &q = *this; q(0) = 1; q(1) = 0; q(2) = 0; q(3) = 0; } Quaternion(const Matrix41 & other) : Vector(other) { } Quaternion(const Dcm & dcm) : Vector() { Quaternion &q = *this; q(0) = Type(0.5 * sqrt(1 + dcm(0, 0) + dcm(1, 1) + dcm(2, 2))); q(1) = Type((dcm(2, 1) - dcm(1, 2)) / (4 * q(0))); q(2) = Type((dcm(0, 2) - dcm(2, 0)) / (4 * q(0))); q(3) = Type((dcm(1, 0) - dcm(0, 1)) / (4 * q(0))); } Quaternion(const Euler & euler) : Vector() { Quaternion &q = *this; Type cosPhi_2 = Type(cos(euler.phi() / (Type)2.0)); Type cosTheta_2 = Type(cos(euler.theta() / (Type)2.0)); Type cosPsi_2 = Type(cos(euler.psi() / (Type)2.0)); Type sinPhi_2 = Type(sin(euler.phi() / (Type)2.0)); Type sinTheta_2 = Type(sin(euler.theta() / (Type)2.0)); Type sinPsi_2 = Type(sin(euler.psi() / (Type)2.0)); q(0) = cosPhi_2 * cosTheta_2 * cosPsi_2 + sinPhi_2 * sinTheta_2 * sinPsi_2; q(1) = sinPhi_2 * cosTheta_2 * cosPsi_2 - cosPhi_2 * sinTheta_2 * sinPsi_2; q(2) = cosPhi_2 * sinTheta_2 * cosPsi_2 + sinPhi_2 * cosTheta_2 * sinPsi_2; q(3) = cosPhi_2 * cosTheta_2 * sinPsi_2 - sinPhi_2 * sinTheta_2 * cosPsi_2; } Quaternion(Type a, Type b, Type c, Type d) : Vector() { Quaternion &q = *this; q(0) = a; q(1) = b; q(2) = c; q(3) = d; } Quaternion operator*(const Quaternion &q) const { const Quaternion &p = *this; Quaternion r; r(0) = p(0)*q(0) - p(1)*q(1) - p(2)*q(2) - p(3)*q(3); r(1) = p(0)*q(1) + p(1)*q(0) - p(2)*q(3) + p(3)*q(2); r(2) = p(0)*q(2) + p(1)*q(3) + p(2)*q(0) - p(3)*q(1); r(3) = p(0)*q(3) - p(1)*q(2) + p(2)*q(1) + p(3)*q(0); return r; } void operator*=(const Quaternion & other) { Quaternion &self = *this; self = self * other; } Quaternion operator*(Type scalar) const { const Quaternion &q = *this; return scalar * q; } void operator*=(Type scalar) { Quaternion &q = *this; q = q * scalar; } Matrix41 derivative(const Matrix31 & w) const { const Quaternion &q = *this; Type dataQ[] = { q(0), -q(1), -q(2), -q(3), q(1), q(0), -q(3), q(2), q(2), q(3), q(0), -q(1), q(3), -q(2), q(1), q(0) }; Matrix Q(dataQ); Vector v; v(0) = 0; v(1) = w(0,0); v(2) = w(1,0); v(3) = w(2,0); return Q * v * Type(0.5); } void invert() { Quaternion &q = *this; q(1) *= -1; q(2) *= -1; q(3) *= -1; } Quaternion inversed() { Quaternion &q = *this; Quaternion ret; ret(0) = q(0); ret(1) = -q(1); ret(2) = -q(2); ret(3) = -q(3); return ret; } void rotate(const Vector &vec) { Quaternion res; res.from_axis_angle(vec); (*this) = (*this) * res; } void from_axis_angle(Vector vec) { Quaternion &q = *this; Type theta = vec.norm(); if(theta < (Type)1e-10) { q(0) = (Type)1.0; q(1)=q(2)=q(3)=0; return; } vec /= theta; from_axis_angle(vec,theta); } void from_axis_angle(const Vector &axis, Type theta) { Quaternion &q = *this; if(theta < (Type)1e-10) { q(0) = (Type)1.0; q(1)=q(2)=q(3)=0; } Type magnitude = sinf(theta/2.0f); q(0) = cosf(theta/2.0f); q(1) = axis(0) * magnitude; q(2) = axis(1) * magnitude; q(3) = axis(2) * magnitude; } Vector to_axis_angle() { Quaternion &q = *this; Type axis_magnitude = Type(sqrt(q(1) * q(1) + q(2) * q(2) + q(3) * q(3))); Vector vec; vec(0) = q(1); vec(1) = q(2); vec(2) = q(3); if(axis_magnitude >= (Type)1e-10) { vec = vec / axis_magnitude; vec = vec * wrap_pi((Type)2.0 * atan2f(axis_magnitude,q(0))); } return vec; } }; typedef Quaternion Quatf; } // namespace matrix /* vim: set et fenc=utf-8 ff=unix sts=0 sw=4 ts=4 : */