/** \file G3D/Quat.h Quaternion \maintainer Morgan McGuire, http://graphics.cs.williams.edu \created 2002-01-23 \edited 2011-05-10 */ #ifndef G3D_Quat_h #define G3D_Quat_h #include "G3D/platform.h" #include "G3D/g3dmath.h" #include "G3D/Vector3.h" #include "G3D/Matrix3.h" #include namespace G3D { /** Arbitrary quaternion (not necessarily unit). Unit quaternions (aka versors) are used in computer graphics to represent rotation about an axis. Any 3x3 rotation matrix can be stored as a quaternion. A quaternion represents the sum of a real scalar and an imaginary vector: ix + jy + kz + w. A unit quaternion representing a rotation by A about axis v has the form [sin(A/2)*v, cos(A/2)]. For a unit quaternion, q.conj() == q.inverse() is a rotation by -A about v. -q is the same rotation as q (negate both the axis and angle). A non-unit quaterion q represents the same rotation as q.unitize() (Dam98 pg 28). Although quaternion-vector operations (eg. Quat + Vector3) are well defined, they are not supported by this class because they typically are bugs when they appear in code. Do not subclass. BETA API -- subject to change \cite Erik B. Dam, Martin Koch, Martin Lillholm, Quaternions, Interpolation and Animation. Technical Report DIKU-TR-98/5, Department of Computer Science, University of Copenhagen, Denmark. 1998. */ class Quat { private: // Hidden operators bool operator<(const Quat&) const; bool operator>(const Quat&) const; bool operator<=(const Quat&) const; bool operator>=(const Quat&) const; public: /** q = [sin(angle / 2) * axis, cos(angle / 2)] In Watt & Watt's notation, s = w, v = (x, y, z) In the Real-Time Rendering notation, u = (x, y, z), w = w */ float x, y, z, w; /** Initializes to a zero degree rotation, (0,0,0,1) */ Quat() : x(0), y(0), z(0), w(1) {} /** Expects "Quat(x,y,z,w)" or a Matrix3 constructor. */ Quat(const class Any& a); Any toAny() const; Quat(const Matrix3& rot); Quat(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) {} /** Defaults to a pure vector quaternion */ Quat(const Vector3& v, float _w = 0) : x(v.x), y(v.y), z(v.z), w(_w) { } /** True if the components are exactly equal. Note that two quaternations may be unequal but map to the same rotation. */ bool operator==(const Quat& q) const { return x == q.x && y == q.y && z == q.z && w == q.w; } /** The real part of the quaternion. */ const float& real() const { return w; } float& real() { return w; } Quat operator-() const { return Quat(-x, -y, -z, -w); } Quat operator-(const Quat& other) const { return Quat(x - other.x, y - other.y, z - other.z, w - other.w); } Quat& operator-=(const Quat& q) { x -= q.x; y -= q.y; z -= q.z; w -= q.w; return *this; } Quat operator+(const Quat& q) const { return Quat(x + q.x, y + q.y, z + q.z, w + q.w); } Quat& operator+=(const Quat& q) { x += q.x; y += q.y; z += q.z; w += q.w; return *this; } /** Negates the imaginary part. */ Quat conj() const { return Quat(-x, -y, -z, w); } float sum() const { return x + y + z + w; } float average() const { return sum() / 4.0f; } Quat operator*(float s) const { return Quat(x * s, y * s, z * s, w * s); } Quat& operator*=(float s) { x *= s; y *= s; z *= s; w *= s; return *this; } /** @cite Based on Watt & Watt, page 360 */ friend Quat operator* (float s, const Quat& q); inline Quat operator/(float s) const { return Quat(x / s, y / s, z / s, w / s); } float dot(const Quat& other) const { return (x * other.x) + (y * other.y) + (z * other.z) + (w * other.w); } /** Note: two quats can represent the Quat::sameRotation and not be equal. */ bool fuzzyEq(const Quat& q) { return G3D::fuzzyEq(x, q.x) && G3D::fuzzyEq(y, q.y) && G3D::fuzzyEq(z, q.z) && G3D::fuzzyEq(w, q.w); } /** True if these quaternions represent the same rotation (note that every rotation is represented by two values; q and -q). */ bool sameRotation(const Quat& q) { return fuzzyEq(q) || fuzzyEq(-q); } /** Returns the imaginary part (x, y, z) */ const Vector3& imag() const { return *(reinterpret_cast(this)); } Vector3& imag() { return *(reinterpret_cast(this)); } /** q = [sin(angle/2)*axis, cos(angle/2)] */ static Quat fromAxisAngleRotation( const Vector3& axis, float angle); /** Returns the axis and angle of rotation represented by this quaternion (i.e. q = [sin(angle/2)*axis, cos(angle/2)]) */ void toAxisAngleRotation( Vector3& axis, double& angle) const; void toAxisAngleRotation( Vector3& axis, float& angle) const { double d; toAxisAngleRotation(axis, d); angle = (float)d; } Matrix3 toRotationMatrix() const; void toRotationMatrix( Matrix3& rot) const; private: /** \param maxAngle Maximum angle of rotation allowed. If a larger rotation is required, the angle of rotation applied is clamped to maxAngle */ Quat slerp (const Quat& other, float alpha, float threshold, float maxAngle) const; public: /** Spherical linear interpolation: linear interpolation along the shortest (3D) great-circle route between two quaternions. Assumes that both arguments are unit quaternions. Note: Correct rotations are expected between 0 and PI in the right order. \cite Based on Game Physics -- David Eberly pg 538-540 \param threshold Critical angle between between rotations (in radians) at which the algorithm switches to normalized lerp, which is more numerically stable in those situations. 0.0 will always slerp. */ Quat slerp (const Quat& other, float alpha, float threshold = 0.05f) const { return slerp(other, alpha, threshold, finf()); } /** Rotates towards \a other by at most \a maxAngle. */ Quat movedTowards (const Quat& other, float maxAngle) const { return slerp(other, 1.0f, 0.05f, maxAngle); } /** Rotates towards \a other by at most \a maxAngle. */ void moveTowards (const Quat& other, float maxAngle) { *this = movedTowards(other, maxAngle); } /** Returns the angle in radians between this and other, assuming both are unit quaternions. \returns On the range [0, pif()]*/ float angleBetween(const Quat& other) const; /** Normalized linear interpolation of quaternion components. */ Quat nlerp(const Quat& other, float alpha) const; /** Note that q-1 = q.conj() for a unit quaternion. @cite Dam99 page 13 */ inline Quat inverse() const { return conj() / dot(*this); } /** Quaternion multiplication (composition of rotations). Note that this does not commute. */ Quat operator*(const Quat& other) const; /* (*this) * other.inverse() */ Quat operator/(const Quat& other) const { return (*this) * other.inverse(); } /** Is the magnitude nearly 1.0? */ bool isUnit(float tolerance = 1e-5) const { return abs(dot(*this) - 1.0f) < tolerance; } float magnitude() const { return sqrtf(dot(*this)); } Quat log() const { if ((x == 0) && (y == 0) && (z == 0)) { if (w > 0) { return Quat(0, 0, 0, ::logf(w)); } else if (w < 0) { // Log of a negative number. Multivalued, any number of the form // (PI * v, ln(-q.w)) return Quat((float)pi(), 0, 0, ::logf(-w)); } else { // log of zero! return Quat((float)nan(), (float)nan(), (float)nan(), (float)nan()); } } else { // Partly imaginary. float imagLen = sqrtf(x * x + y * y + z * z); float len = sqrtf(imagLen * imagLen + w * w); float theta = atan2f(imagLen, (float)w); float t = theta / imagLen; return Quat(t * x, t * y, t * z, ::logf(len)); } } /** exp q = [sin(A) * v, cos(A)] where q = [Av, 0]. Only defined for pure-vector quaternions */ inline Quat exp() const { debugAssertM(w == 0, "exp only defined for vector quaternions"); Vector3 u(x, y, z); float A = u.magnitude(); Vector3 v = u / A; return Quat(sinf(A) * v, cosf(A)); } /** Raise this quaternion to a power. For a rotation, this is the effect of rotating x times as much as the original quaterion. Note that q.pow(a).pow(b) == q.pow(a + b) @cite Dam98 pg 21 */ inline Quat pow(float x) const { return (log() * x).exp(); } /** Make unit length in place */ void unitize() { *this *= rsq(dot(*this)); } /** Returns a unit quaterion obtained by dividing through by the magnitude. */ Quat toUnit() const { Quat x = *this; x.unitize(); return x; } /** The linear algebra 2-norm, sqrt(q dot q). This matches the value used in Dam's 1998 tech report but differs from the n(q) value used in Eberly's 1999 paper, which is the square of the norm. */ float norm() const { return magnitude(); } // access quaternion as q[0] = q.x, q[1] = q.y, q[2] = q.z, q[3] = q.w // // WARNING. These member functions rely on // (1) Quat not having virtual functions // (2) the data packed in a 4*sizeof(float) memory block const float& operator[] (int i) const; float& operator[] (int i); /** Generate uniform random unit quaternion (i.e. random "direction") @cite From "Uniform Random Rotations", Ken Shoemake, Graphics Gems III. */ static Quat unitRandom(); void deserialize(class BinaryInput& b); void serialize(class BinaryOutput& b) const; // 2-char swizzles Vector2 xx() const; Vector2 yx() const; Vector2 zx() const; Vector2 wx() const; Vector2 xy() const; Vector2 yy() const; Vector2 zy() const; Vector2 wy() const; Vector2 xz() const; Vector2 yz() const; Vector2 zz() const; Vector2 wz() const; Vector2 xw() const; Vector2 yw() const; Vector2 zw() const; Vector2 ww() const; // 3-char swizzles Vector3 xxx() const; Vector3 yxx() const; Vector3 zxx() const; Vector3 wxx() const; Vector3 xyx() const; Vector3 yyx() const; Vector3 zyx() const; Vector3 wyx() const; Vector3 xzx() const; Vector3 yzx() const; Vector3 zzx() const; Vector3 wzx() const; Vector3 xwx() const; Vector3 ywx() const; Vector3 zwx() const; Vector3 wwx() const; Vector3 xxy() const; Vector3 yxy() const; Vector3 zxy() const; Vector3 wxy() const; Vector3 xyy() const; Vector3 yyy() const; Vector3 zyy() const; Vector3 wyy() const; Vector3 xzy() const; Vector3 yzy() const; Vector3 zzy() const; Vector3 wzy() const; Vector3 xwy() const; Vector3 ywy() const; Vector3 zwy() const; Vector3 wwy() const; Vector3 xxz() const; Vector3 yxz() const; Vector3 zxz() const; Vector3 wxz() const; Vector3 xyz() const; Vector3 yyz() const; Vector3 zyz() const; Vector3 wyz() const; Vector3 xzz() const; Vector3 yzz() const; Vector3 zzz() const; Vector3 wzz() const; Vector3 xwz() const; Vector3 ywz() const; Vector3 zwz() const; Vector3 wwz() const; Vector3 xxw() const; Vector3 yxw() const; Vector3 zxw() const; Vector3 wxw() const; Vector3 xyw() const; Vector3 yyw() const; Vector3 zyw() const; Vector3 wyw() const; Vector3 xzw() const; Vector3 yzw() const; Vector3 zzw() const; Vector3 wzw() const; Vector3 xww() const; Vector3 yww() const; Vector3 zww() const; Vector3 www() const; // 4-char swizzles Vector4 xxxx() const; Vector4 yxxx() const; Vector4 zxxx() const; Vector4 wxxx() const; Vector4 xyxx() const; Vector4 yyxx() const; Vector4 zyxx() const; Vector4 wyxx() const; Vector4 xzxx() const; Vector4 yzxx() const; Vector4 zzxx() const; Vector4 wzxx() const; Vector4 xwxx() const; Vector4 ywxx() const; Vector4 zwxx() const; Vector4 wwxx() const; Vector4 xxyx() const; Vector4 yxyx() const; Vector4 zxyx() const; Vector4 wxyx() const; Vector4 xyyx() const; Vector4 yyyx() const; Vector4 zyyx() const; Vector4 wyyx() const; Vector4 xzyx() const; Vector4 yzyx() const; Vector4 zzyx() const; Vector4 wzyx() const; Vector4 xwyx() const; Vector4 ywyx() const; Vector4 zwyx() const; Vector4 wwyx() const; Vector4 xxzx() const; Vector4 yxzx() const; Vector4 zxzx() const; Vector4 wxzx() const; Vector4 xyzx() const; Vector4 yyzx() const; Vector4 zyzx() const; Vector4 wyzx() const; Vector4 xzzx() const; Vector4 yzzx() const; Vector4 zzzx() const; Vector4 wzzx() const; Vector4 xwzx() const; Vector4 ywzx() const; Vector4 zwzx() const; Vector4 wwzx() const; Vector4 xxwx() const; Vector4 yxwx() const; Vector4 zxwx() const; Vector4 wxwx() const; Vector4 xywx() const; Vector4 yywx() const; Vector4 zywx() const; Vector4 wywx() const; Vector4 xzwx() const; Vector4 yzwx() const; Vector4 zzwx() const; Vector4 wzwx() const; Vector4 xwwx() const; Vector4 ywwx() const; Vector4 zwwx() const; Vector4 wwwx() const; Vector4 xxxy() const; Vector4 yxxy() const; Vector4 zxxy() const; Vector4 wxxy() const; Vector4 xyxy() const; Vector4 yyxy() const; Vector4 zyxy() const; Vector4 wyxy() const; Vector4 xzxy() const; Vector4 yzxy() const; Vector4 zzxy() const; Vector4 wzxy() const; Vector4 xwxy() const; Vector4 ywxy() const; Vector4 zwxy() const; Vector4 wwxy() const; Vector4 xxyy() const; Vector4 yxyy() const; Vector4 zxyy() const; Vector4 wxyy() const; Vector4 xyyy() const; Vector4 yyyy() const; Vector4 zyyy() const; Vector4 wyyy() const; Vector4 xzyy() const; Vector4 yzyy() const; Vector4 zzyy() const; Vector4 wzyy() const; Vector4 xwyy() const; Vector4 ywyy() const; Vector4 zwyy() const; Vector4 wwyy() const; Vector4 xxzy() const; Vector4 yxzy() const; Vector4 zxzy() const; Vector4 wxzy() const; Vector4 xyzy() const; Vector4 yyzy() const; Vector4 zyzy() const; Vector4 wyzy() const; Vector4 xzzy() const; Vector4 yzzy() const; Vector4 zzzy() const; Vector4 wzzy() const; Vector4 xwzy() const; Vector4 ywzy() const; Vector4 zwzy() const; Vector4 wwzy() const; Vector4 xxwy() const; Vector4 yxwy() const; Vector4 zxwy() const; Vector4 wxwy() const; Vector4 xywy() const; Vector4 yywy() const; Vector4 zywy() const; Vector4 wywy() const; Vector4 xzwy() const; Vector4 yzwy() const; Vector4 zzwy() const; Vector4 wzwy() const; Vector4 xwwy() const; Vector4 ywwy() const; Vector4 zwwy() const; Vector4 wwwy() const; Vector4 xxxz() const; Vector4 yxxz() const; Vector4 zxxz() const; Vector4 wxxz() const; Vector4 xyxz() const; Vector4 yyxz() const; Vector4 zyxz() const; Vector4 wyxz() const; Vector4 xzxz() const; Vector4 yzxz() const; Vector4 zzxz() const; Vector4 wzxz() const; Vector4 xwxz() const; Vector4 ywxz() const; Vector4 zwxz() const; Vector4 wwxz() const; Vector4 xxyz() const; Vector4 yxyz() const; Vector4 zxyz() const; Vector4 wxyz() const; Vector4 xyyz() const; Vector4 yyyz() const; Vector4 zyyz() const; Vector4 wyyz() const; Vector4 xzyz() const; Vector4 yzyz() const; Vector4 zzyz() const; Vector4 wzyz() const; Vector4 xwyz() const; Vector4 ywyz() const; Vector4 zwyz() const; Vector4 wwyz() const; Vector4 xxzz() const; Vector4 yxzz() const; Vector4 zxzz() const; Vector4 wxzz() const; Vector4 xyzz() const; Vector4 yyzz() const; Vector4 zyzz() const; Vector4 wyzz() const; Vector4 xzzz() const; Vector4 yzzz() const; Vector4 zzzz() const; Vector4 wzzz() const; Vector4 xwzz() const; Vector4 ywzz() const; Vector4 zwzz() const; Vector4 wwzz() const; Vector4 xxwz() const; Vector4 yxwz() const; Vector4 zxwz() const; Vector4 wxwz() const; Vector4 xywz() const; Vector4 yywz() const; Vector4 zywz() const; Vector4 wywz() const; Vector4 xzwz() const; Vector4 yzwz() const; Vector4 zzwz() const; Vector4 wzwz() const; Vector4 xwwz() const; Vector4 ywwz() const; Vector4 zwwz() const; Vector4 wwwz() const; Vector4 xxxw() const; Vector4 yxxw() const; Vector4 zxxw() const; Vector4 wxxw() const; Vector4 xyxw() const; Vector4 yyxw() const; Vector4 zyxw() const; Vector4 wyxw() const; Vector4 xzxw() const; Vector4 yzxw() const; Vector4 zzxw() const; Vector4 wzxw() const; Vector4 xwxw() const; Vector4 ywxw() const; Vector4 zwxw() const; Vector4 wwxw() const; Vector4 xxyw() const; Vector4 yxyw() const; Vector4 zxyw() const; Vector4 wxyw() const; Vector4 xyyw() const; Vector4 yyyw() const; Vector4 zyyw() const; Vector4 wyyw() const; Vector4 xzyw() const; Vector4 yzyw() const; Vector4 zzyw() const; Vector4 wzyw() const; Vector4 xwyw() const; Vector4 ywyw() const; Vector4 zwyw() const; Vector4 wwyw() const; Vector4 xxzw() const; Vector4 yxzw() const; Vector4 zxzw() const; Vector4 wxzw() const; Vector4 xyzw() const; Vector4 yyzw() const; Vector4 zyzw() const; Vector4 wyzw() const; Vector4 xzzw() const; Vector4 yzzw() const; Vector4 zzzw() const; Vector4 wzzw() const; Vector4 xwzw() const; Vector4 ywzw() const; Vector4 zwzw() const; Vector4 wwzw() const; Vector4 xxww() const; Vector4 yxww() const; Vector4 zxww() const; Vector4 wxww() const; Vector4 xyww() const; Vector4 yyww() const; Vector4 zyww() const; Vector4 wyww() const; Vector4 xzww() const; Vector4 yzww() const; Vector4 zzww() const; Vector4 wzww() const; Vector4 xwww() const; Vector4 ywww() const; Vector4 zwww() const; Vector4 wwww() const; }; inline Quat exp(const Quat& q) { return q.exp(); } inline Quat log(const Quat& q) { return q.log(); } inline G3D::Quat operator*(double s, const G3D::Quat& q) { return q * (float)s; } inline G3D::Quat operator*(float s, const G3D::Quat& q) { return q * s; } inline float& Quat::operator[] (int i) { debugAssert(i >= 0); debugAssert(i < 4); return ((float*)this)[i]; } inline const float& Quat::operator[] (int i) const { debugAssert(i >= 0); debugAssert(i < 4); return ((float*)this)[i]; } } // Namespace G3D // Outside the namespace to avoid overloading confusion for C++ inline G3D::Quat pow(const G3D::Quat& q, double x) { return q.pow((float)x); } #endif