/* * SOLID - Software Library for Interference Detection * * Copyright (C) 2001-2003 Dtecta. All rights reserved. * * This library may be distributed under the terms of the Q Public License * (QPL) as defined by Trolltech AS of Norway and appearing in the file * LICENSE.QPL included in the packaging of this file. * * This library may be distributed and/or modified under the terms of the * GNU General Public License (GPL) version 2 as published by the Free Software * Foundation and appearing in the file LICENSE.GPL included in the * packaging of this file. * * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Commercial use or any other use of this library not covered by either * the QPL or the GPL requires an additional license from Dtecta. * Please contact info@dtecta.com for enquiries about the terms of commercial * use of this library. */ #ifndef QUATERNION_H #define QUATERNION_H #if defined (__sgi) #include #else #include #endif #include "Tuple4.h" #include "Vector3.h" namespace MT { template class Quaternion : public Tuple4 { public: Quaternion() {} template explicit Quaternion(const Scalar2 *v) : Tuple4(v) {} template Quaternion(const Scalar2& x, const Scalar2& y, const Scalar2& z, const Scalar2& w) : Tuple4(x, y, z, w) {} Quaternion(const Vector3& axis, const Scalar& angle) { setRotation(axis, angle); } template Quaternion(const Scalar2& yaw, const Scalar2& pitch, const Scalar2& roll) { setEuler(yaw, pitch, roll); } void setRotation(const Vector3& axis, const Scalar& angle) { Scalar d = axis.length(); assert(d != Scalar(0.0)); Scalar s = Scalar_traits::sin(angle * Scalar(0.5)) / d; setValue(axis[0] * s, axis[1] * s, axis[2] * s, Scalar_traits::cos(angle * Scalar(0.5))); } template void setEuler(const Scalar2& yaw, const Scalar2& pitch, const Scalar2& roll) { Scalar halfYaw = Scalar(yaw) * Scalar(0.5); Scalar halfPitch = Scalar(pitch) * Scalar(0.5); Scalar halfRoll = Scalar(roll) * Scalar(0.5); Scalar cosYaw = Scalar_traits::cos(halfYaw); Scalar sinYaw = Scalar_traits::sin(halfYaw); Scalar cosPitch = Scalar_traits::cos(halfPitch); Scalar sinPitch = Scalar_traits::sin(halfPitch); Scalar cosRoll = Scalar_traits::cos(halfRoll); Scalar sinRoll = Scalar_traits::sin(halfRoll); setValue(cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw, cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw, sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw, cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw); } Quaternion& operator+=(const Quaternion& q) { this->m_co[0] += q[0]; this->m_co[1] += q[1]; this->m_co[2] += q[2]; this->m_co[3] += q[3]; return *this; } Quaternion& operator-=(const Quaternion& q) { this->m_co[0] -= q[0]; this->m_co[1] -= q[1]; this->m_co[2] -= q[2]; this->m_co[3] -= q[3]; return *this; } Quaternion& operator*=(const Scalar& s) { this->m_co[0] *= s; this->m_co[1] *= s; this->m_co[2] *= s; this->m_co[3] *= s; return *this; } Quaternion& operator/=(const Scalar& s) { assert(s != Scalar(0.0)); return *this *= Scalar(1.0) / s; } Quaternion& operator*=(const Quaternion& q) { setValue(this->m_co[3] * q[0] + this->m_co[0] * q[3] + this->m_co[1] * q[2] - this->m_co[2] * q[1], this->m_co[3] * q[1] + this->m_co[1] * q[3] + this->m_co[2] * q[0] - this->m_co[0] * q[2], this->m_co[3] * q[2] + this->m_co[2] * q[3] + this->m_co[0] * q[1] - this->m_co[1] * q[0], this->m_co[3] * q[3] - this->m_co[0] * q[0] - this->m_co[1] * q[1] - this->m_co[2] * q[2]); return *this; } Scalar dot(const Quaternion& q) const { return this->m_co[0] * q[0] + this->m_co[1] * q[1] + this->m_co[2] * q[2] + this->m_co[3] * q[3]; } Scalar length2() const { return dot(*this); } Scalar length() const { return Scalar_traits::sqrt(length2()); } Quaternion& normalize() { return *this /= length(); } Quaternion normalized() const { return *this / length(); } Scalar angle(const Quaternion& q) const { Scalar s = Scalar_traits::sqrt(length2() * q.length2()); assert(s != Scalar(0.0)); return Scalar_traits::acos(dot(q) / s); } Quaternion conjugate() const { return Quaternion(-this->m_co[0], -this->m_co[1], -this->m_co[2], this->m_co[3]); } Quaternion inverse() const { return conjugate / length2(); } Quaternion slerp(const Quaternion& q, const Scalar& t) const { Scalar theta = angle(q); if (theta != Scalar(0.0)) { Scalar d = Scalar(1.0) / Scalar_traits::sin(theta); Scalar s0 = Scalar_traits::sin((Scalar(1.0) - t) * theta); Scalar s1 = Scalar_traits::sin(t * theta); return Quaternion((this->m_co[0] * s0 + q[0] * s1) * d, (this->m_co[1] * s0 + q[1] * s1) * d, (this->m_co[2] * s0 + q[2] * s1) * d, (this->m_co[3] * s0 + q[3] * s1) * d); } else { return *this; } } static Quaternion random() { // From: "Uniform Random Rotations", Ken Shoemake, Graphics Gems III, // pg. 124-132 Scalar x0 = Scalar_traits::random(); Scalar r1 = Scalar_traits::sqrt(Scalar(1.0) - x0); Scalar r2 = Scalar_traits::sqrt(x0); Scalar t1 = Scalar_traits::TwoTimesPi() * Scalar_traits::random(); Scalar t2 = Scalar_traits::TwoTimesPi() * Scalar_traits::random(); Scalar c1 = Scalar_traits::cos(t1); Scalar s1 = Scalar_traits::sin(t1); Scalar c2 = Scalar_traits::cos(t2); Scalar s2 = Scalar_traits::sin(t2); return Quaternion(s1 * r1, c1 * r1, s2 * r2, c2 * r2); } }; template inline Quaternion operator+(const Quaternion& q1, const Quaternion& q2) { return Quaternion(q1[0] + q2[0], q1[1] + q2[1], q1[2] + q2[2], q1[3] + q2[3]); } template inline Quaternion operator-(const Quaternion& q1, const Quaternion& q2) { return Quaternion(q1[0] - q2[0], q1[1] - q2[1], q1[2] - q2[2], q1[3] - q2[3]); } template inline Quaternion operator-(const Quaternion& q) { return Quaternion(-q[0], -q[1], -q[2], -q[3]); } template inline Quaternion operator*(const Quaternion& q, const Scalar& s) { return Quaternion(q[0] * s, q[1] * s, q[2] * s, q[3] * s); } template inline Quaternion operator*(const Scalar& s, const Quaternion& q) { return q * s; } template inline Quaternion operator*(const Quaternion& q1, const Quaternion& q2) { return Quaternion(q1[3] * q2[0] + q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1], q1[3] * q2[1] + q1[1] * q2[3] + q1[2] * q2[0] - q1[0] * q2[2], q1[3] * q2[2] + q1[2] * q2[3] + q1[0] * q2[1] - q1[1] * q2[0], q1[3] * q2[3] - q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2]); } template inline Quaternion operator*(const Quaternion& q, const Vector3& w) { return Quaternion( q[3] * w[0] + q[1] * w[2] - q[2] * w[1], q[3] * w[1] + q[2] * w[0] - q[0] * w[2], q[3] * w[2] + q[0] * w[1] - q[1] * w[0], -q[0] * w[0] - q[1] * w[1] - q[2] * w[2]); } template inline Quaternion operator*(const Vector3& w, const Quaternion& q) { return Quaternion( w[0] * q[3] + w[1] * q[2] - w[2] * q[1], w[1] * q[3] + w[2] * q[0] - w[0] * q[2], w[2] * q[3] + w[0] * q[1] - w[1] * q[0], -w[0] * q[0] - w[1] * q[1] - w[2] * q[2]); } template inline Scalar dot(const Quaternion& q1, const Quaternion& q2) { return q1.dot(q2); } template inline Scalar length2(const Quaternion& q) { return q.length2(); } template inline Scalar length(const Quaternion& q) { return q.length(); } template inline Scalar angle(const Quaternion& q1, const Quaternion& q2) { return q1.angle(q2); } template inline Quaternion conjugate(const Quaternion& q) { return q.conjugate(); } template inline Quaternion inverse(const Quaternion& q) { return q.inverse(); } template inline Quaternion slerp(const Quaternion& q1, const Quaternion& q2, const Scalar& t) { return q1.slerp(q2, t); } } #endif