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

📄 quat.h

📁 WOW 服务模拟端 支持2.4.3版本 来自开源的ASCENT 自己REPACK
💻 H
📖 第 1 页 / 共 2 页
字号:
/**
  @file Quat.h
 
  Quaternion
  
  @maintainer Morgan McGuire, matrix@graphics3d.com
  
  @created 2002-01-23
  @edited  2006-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 <string>

namespace G3D {

/**
  Unit quaternions 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.

  <B>BETA API -- subject to change</B>
  @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.
     */
    inline Quat() : x(0), y(0), z(0), w(1) {}

    Quat(
        const Matrix3& rot);

    inline Quat(float _x, float _y, float _z, float _w) :
        x(_x), y(_y), z(_z), w(_w) {}

    /** Defaults to a pure vector quaternion */
    inline Quat(const Vector3& v, float _w = 0) : x(v.x), y(v.y), z(v.z), w(_w) {
    }

    /**
     The real part of the quaternion.
     */
    inline const float& real() const {
        return w;
    }

    inline float& real() {
        return 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);
    }

	inline Quat operator-() const {
		return Quat(-x, -y, -z, -w);
	}

    /**
     Returns the imaginary part (x, y, z)
     */
    inline const Vector3& imag() const {
        return *(reinterpret_cast<const Vector3*>(this));
    }

    inline Vector3& imag() {
        return *(reinterpret_cast<Vector3*>(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;
    
    /**
     Spherical linear interpolation: linear interpolation along the 
     shortest (3D) great-circle route between two 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 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;

	/** Normalized linear interpolation of quaternion components. */
	Quat nlerp(const Quat& other, float alpha) const;

    /**
     Negates the imaginary part.
     */
    inline Quat conj() const {
        return Quat(-x, -y, -z, w);
    }

    inline float sum() const {
        return x + y + z + w;
    }

    inline float average() const {
        return sum() / 4.0f;
    }

    inline Quat operator*(float s) const {
        return Quat(x * s, y * s, z * s, w * s);
    }

	/** @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);
    }

    inline float dot(const Quat& other) const {
        return (x * other.x) + (y * other.y) + (z * other.z) + (w * other.w);
    }

    /** Note that q<SUP>-1</SUP> = q.conj() for a unit quaternion. 
        @cite Dam99 page 13 */
    inline Quat inverse() const {
        return conj() / dot(*this);
    }

    Quat operator-(const Quat& other) const;

    Quat operator+(const Quat& other) const;

    /**
     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? */
    inline bool isUnit(float tolerance = 1e-5) const {
        return abs(dot(*this) - 1.0f) < tolerance;
    }
    

    inline float magnitude() const {
        return sqrtf(dot(*this));
    }

    inline 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)G3D_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));
        }
    }
    /** log q = [Av, 0] where q = [sin(A) * v, cos(A)].
        Only for unit quaternions 
        debugAssertM(isUnit(), "Log only defined for unit quaternions");
        // Solve for A in q = [sin(A)*v, cos(A)]
        Vector3 u(x, y, z);
        double len = u.magnitude();

        if (len == 0.0) {
            return 
        }
        double A = atan2((double)w, len);
        Vector3 v = u / len;
        
        return Quat(v * A, 0);
    }
    */

    /** 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();
    }


    /**
     @deprecated
     Use toUnit()
     */
    inline Quat unitize() const {
        float mag2 = dot(*this);
        if (G3D::fuzzyEq(mag2, 1.0f)) {
            return *this;
        } else {
            return *this / sqrtf(mag2);
        }
    }

    /**
     Returns a unit quaterion obtained by dividing through by
     the magnitude.
     */
    inline Quat toUnit() const {
        return unitize();
    }

    /**
     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.
     */
    inline 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();

    // 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;

⌨️ 快捷键说明

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