⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 quaternion.h

📁 一个纹理地形渲染器
💻 H
字号:
// Quaternion class

#pragma once

#include "Float.h"
#include "Vector.h"
#include "Matrix.h"


namespace Mathematics
{
    /// A quaternion.
    /// This quaternion class is generic and may be non-unit, however most 
    /// anticipated uses of quaternions are typically unit cases representing
    /// a rotation 2*acos(w) about the unit length axis (x,y,z).

    class Quaternion
    {
    public:

        /// default constructor.
        /// does nothing for speed.

        Quaternion() {}

        /// construct quaternion from real component w and imaginary x,y,z.

	    Quaternion(float w, float x, float y, float z)
	    {
		    this->w = w;
		    this->x = x;
		    this->y = y;
		    this->z = z;
	    }

        /// construct quaternion from angle-axis
        /// todo: consider changing parameter order to axis-angle ?

	    Quaternion(float angle, const Vector &axis)
	    {
		    assert(axis.normalized());

		    const float a = angle * 0.5f;
		    const float s = (float) sin(a);
		    const float c = (float) cos(a);
		    w = c;
		    x = axis.x * s;
		    y = axis.y * s;
		    z = axis.z * s;
	    }

        /// construct quaternion from rotation matrix.

	    Quaternion(const Matrix &matrix)
	    {
		    // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
		    // article "Quaternion Calculus and Fast Animation".

		    const float trace = matrix.m11 + matrix.m22 + matrix.m33;

		    if (trace>0)
		    {
			    // |w| > 1/2, may as well choose w > 1/2

			    float root = Float::sqrt(trace + 1.0f);  // 2w
			    w = 0.5f * root;
			    root = 0.5f / root;  // 1/(4w)
			    x = (matrix.m32-matrix.m23) * root;
			    y = (matrix.m13-matrix.m31) * root;
			    z = (matrix.m21-matrix.m12) * root;
		    }
		    else
		    {
			    // |w| <= 1/2

			    static int next[3] = { 2, 3, 1 };
    			
			    int i = 1;
			    if (matrix.m22>matrix.m11)  i = 2;
			    if (matrix.m33>matrix(i,i)) i = 3;
			    int j = next[i];
			    int k = next[j];
    			
			    float root = Float::sqrt(matrix(i,i)-matrix(j,j)-matrix(k,k) + 1.0f);
			    float *quaternion[3] = { &x, &y, &z };
			    *quaternion[i] = 0.5f * root;
			    root = 0.5f / root;
			    w = (matrix(k,j)-matrix(j,k))*root;
			    *quaternion[j] = (matrix(j,i)+matrix(i,j))*root;
			    *quaternion[k] = (matrix(k,i)+matrix(i,k))*root;
		    }
	    }

        /// convert quaternion to matrix.

	    Matrix matrix() const
	    {
		    float fTx  = 2.0f*x;
		    float fTy  = 2.0f*y;
		    float fTz  = 2.0f*z;
		    float fTwx = fTx*w;
		    float fTwy = fTy*w;
		    float fTwz = fTz*w;
		    float fTxx = fTx*x;
		    float fTxy = fTy*x;
		    float fTxz = fTz*x;
		    float fTyy = fTy*y;
		    float fTyz = fTz*y;
		    float fTzz = fTz*z;

		    return Matrix(1.0f-(fTyy+fTzz), fTxy-fTwz, fTxz+fTwy,
					    fTxy+fTwz, 1.0f-(fTxx+fTzz), fTyz-fTwx,
					    fTxz-fTwy, fTyz+fTwx, 1.0f-(fTxx+fTyy));
	    }

        /// convert quaternion to angle-axis.

	    void angle_axis(float &angle, Vector &axis)
	    {
		    assert(normalized());

		    const float square_length = x*x + y*y + z*z;
		    if (square_length > 0.0f )
		    {
			    angle = 2.0f * (float) acos(w);
			    const float inverse_length = 1.0f / Float::sqrt(square_length);
			    axis.x = x * inverse_length;
			    axis.y = y * inverse_length;
			    axis.z = z * inverse_length;
		    }
		    else
		    {
			    angle = 0.0f;
			    axis.x = 1.0f;
			    axis.y = 0.0f;
			    axis.z = 0.0f;
		    }
	    }

        /// set quaternion to zero.

	    void zero()
	    {
		    w = 0;
		    x = 0;
		    y = 0;
		    z = 0;
	    }

        /// set quaternion to identity.

	    void identity()
	    {
		    w = 1;
		    x = 0;
		    y = 0;
		    z = 0;
	    }
    	
        /// add another quaternion to this quaternion.

	    void add(const Quaternion &q)
	    {
		    w += q.w;
		    x += q.x;
		    y += q.y;
		    z += q.z;
	    }

        /// subtract another quaternion from this quaternion.

	    void subtract(const Quaternion &q)
	    {
		    w -= q.w;
		    x -= q.x;
		    y -= q.y;
		    z -= q.z;
	    }

        /// multiply this quaternion by a scalar.

	    void multiply(float s)
	    {
		    w *= s;
		    x *= s;
		    y *= s;
		    z *= s;
	    }

        /// divide this quaternion by a scalar.

	    void divide(float s)
	    {
		    assert(s!=0);
		    const float inv = 1.0f / s;
		    w *= inv;
		    x *= inv;
		    y *= inv;
		    z *= inv;
	    }

        /// multiply this quaternion with another quaternion.

	    void multiply(const Quaternion &q)
	    {
		    const float rw = w*q.w - x*q.x - y*q.y - z*q.z;
		    const float rx = w*q.x + x*q.w + y*q.z - z*q.y;
		    const float ry = w*q.y - x*q.z + y*q.w + z*q.x;
		    const float rz = w*q.z + x*q.y - y*q.x + z*q.w;
		    w = rw;
		    x = rx;
		    y = ry;
		    z = rz;
	    }

        /// multiply this quaternion with another quaternion and store result in parameter.

	    void multiply(const Quaternion &q, Quaternion &result) const
	    {
		    result.w = w*q.w - x*q.x - y*q.y - z*q.z;
		    result.x = w*q.x + x*q.w + y*q.z - z*q.y;
		    result.y = w*q.y - x*q.z + y*q.w + z*q.x;
		    result.z = w*q.z + x*q.y - y*q.x + z*q.w;
	    }

        /// dot product of two quaternions.

	    Quaternion dot(const Quaternion &q)
	    {
		    return Quaternion(w*q.w + x*q.x + y*q.y + z*q.z, 0, 0, 0);
	    }

        /// dot product of two quaternions writing result to parameter.

	    void dot(const Quaternion &q, Quaternion &result)
	    {
		    result = Quaternion(w*q.w + x*q.x + y*q.y + z*q.z, 0, 0, 0);
	    }

        /// calculate conjugate of quaternion.

	    Quaternion conjugate()
	    {
		    return Quaternion(w, -x, -y, -z);
	    }

        /// calculate conjugate of quaternion and store result in parameter.

	    void conjugate(Quaternion &result) const
	    {
		    result = Quaternion(w, -x, -y, -z);
	    }

        /// calculate length of quaternion

	    float length() const
	    {
		    return Float::sqrt(w*w + x*x + y*y + z*z);
	    }

        /// calculate norm of quaternion.
        /// note: norm is length squared.

	    float norm() const
	    {
		    return w*w + x*x + y*y + z*z;
	    }

        /// normalize quaternion.
        /// note: normalization occurs in place!

	    void normalize()
	    {
		    const float length = this->length();

		    if (length == 0)
		    {
			    w = 1;
			    x = 0;
			    y = 0;
			    z = 0;
		    }
		    else
		    {
			    float inv = 1.0f / length;
			    x = x * inv;
			    y = y * inv;
			    z = z * inv;
			    w = w * inv;
		    }
	    }

        /// check if quaternion is normalized

	    bool normalized() const
	    {
		    return Float::equal(norm(),1);
	    }

        /// calculate inverse of quaternion

	    Quaternion inverse() const
	    {
		    const float n = norm();
		    assert(n!=0);
		    return Quaternion(w/n, -x/n, -y/n, -z/n); 
	    }

        /// calculate inverse of quaternion and store result in parameter.

	    void inverse(Quaternion &result) const
	    {
		    const float n = norm();
		    result = Quaternion(w/n, -x/n, -y/n, -z/n);
	    }

        /// equals operator

	    bool operator ==(const Quaternion &other) const
	    {
		    if ( Float::equal(w,other.w) && Float::equal(x,other.x) && Float::equal(y,other.y) && Float::equal(z,other.z)) return true;
		    else return false;
	    }

        /// not equals operator

	    bool operator !=(const Quaternion &other) const
	    {
		    return !(*this==other);
	    }

        /// print a basic representation of quaternion to stdout

	    void print() const
	    {
		    printf("Quaternion[%f, %f, %f, %f]\n", w, x, y, z);
	    }
    	
	    friend inline Quaternion operator-(const Quaternion &a);
	    friend inline Quaternion operator+(const Quaternion &a, const Quaternion &b);
	    friend inline Quaternion operator-(const Quaternion &a, const Quaternion &b);
	    friend inline Quaternion operator*(const Quaternion &a, const Quaternion &b);
	    friend inline Quaternion& operator+=(Quaternion &a, const Quaternion &b);
	    friend inline Quaternion& operator-=(Quaternion &a, const Quaternion &b);
	    friend inline Quaternion& operator*=(Quaternion &a, const Quaternion &b);

	    friend inline bool operator ==(const Quaternion &q, float scalar);
	    friend inline bool operator !=(const Quaternion &q, float scalar);
	    friend inline bool operator ==(float scalar, const Quaternion &q);
	    friend inline bool operator !=(float scalar, const Quaternion &q);

	    friend inline Quaternion operator*(const Quaternion &a, float s);
	    friend inline Quaternion operator/(const Quaternion &a, float s);
	    friend inline Quaternion& operator*=(Quaternion &a, float s);
	    friend inline Quaternion& operator/=(Quaternion &a, float s);
	    friend inline Quaternion operator*(float s, const Quaternion &a);
	    friend inline Quaternion& operator*=(float s, Quaternion &a);

	    float w;        ///< w component of quaternion
        float x;        ///< x component of quaternion
        float y;        ///< y component of quaternion
        float z;        ///< z component of quaternion
    };


    inline Quaternion operator-(const Quaternion &a)
    {
	    return Quaternion(-a.w, -a.x, -a.y, -a.z);
    }

    inline Quaternion operator+(const Quaternion &a, const Quaternion &b)
    {
	    return Quaternion(a.w+b.w, a.x+b.x, a.y+b.y, a.z+b.z);
    }

    inline Quaternion operator-(const Quaternion &a, const Quaternion &b)
    {
	    return Quaternion(a.w-b.w, a.x-b.x, a.y-b.y, a.z-b.z);
    }

    inline Quaternion operator*(const Quaternion &a, const Quaternion &b)
    {
	    return Quaternion( a.w*b.w - a.x*b.x - a.y*b.y - a.z*b.z, 
					    a.w*b.x + a.x*b.w + a.y*b.z - a.z*b.y,
					    a.w*b.y - a.x*b.z + a.y*b.w + a.z*b.x,
					    a.w*b.z + a.x*b.y - a.y*b.x + a.z*b.w );
    }

    inline Quaternion& operator+=(Quaternion &a, const Quaternion &b)
    {
	    a.w += b.w;
	    a.x += b.x;
	    a.y += b.y;
	    a.z += b.z;
	    return a;
    }

    inline Quaternion& operator-=(Quaternion &a, const Quaternion &b)
    {
	    a.w -= b.w;
	    a.x -= b.x;
	    a.y -= b.y;
	    a.z -= b.z;
	    return a;
    }

    inline Quaternion& operator*=(Quaternion &a, const Quaternion &b)
    {
	    a.multiply(b);
	    return a;
    }


    inline bool operator ==(const Quaternion &q, float scalar)
    {
	    if ( Float::equal(q.w,scalar) && Float::equal(q.x,0) && Float::equal(q.y,0) && Float::equal(q.z,0)) return true;
	    else return false;
    }

    inline bool operator !=(const Quaternion &q, float scalar)
    {
	    return !(q==scalar);
    }

    inline bool operator ==(float scalar, const Quaternion &q)
    {
	    if ( Float::equal(q.w,scalar) && Float::equal(q.x,0) && Float::equal(q.y,0) && Float::equal(q.z,0)) return true;
	    else return false;
    }

    inline bool operator !=(float scalar, const Quaternion &q)
    {
	    return !(q==scalar);
    }

    inline Quaternion operator*(const Quaternion &a, float s)
    {
	    return Quaternion(a.w*s, a.x*s, a.y*s, a.z*s);
    }

    inline Quaternion operator/(const Quaternion &a, float s)
    {
	    return Quaternion(a.w/s, a.x/s, a.y/s, a.z/s);
    }

    inline Quaternion& operator*=(Quaternion &a, float s)
    {
	    a.multiply(s);
	    return a;
    }

    inline Quaternion& operator/=(Quaternion &a, float s)
    {
	    a.divide(s);
	    return a;
    }

    inline Quaternion operator*(float s, const Quaternion &a)
    {
	    return Quaternion(a.w*s, a.x*s, a.y*s, a.z*s);
    }

    inline Quaternion& operator*=(float s, Quaternion &a)
    {
	    a.multiply(s);
	    return a;
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -