/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #ifndef OSG_QUAT #define OSG_QUAT 1 #include #include #include namespace osg { /** A quaternion class. It can be used to represent an orientation in 3D space.*/ class SG_EXPORT Quat { public: /* ---------------------------------------------------------- DATA MEMBERS The only data member is a Vec4 which holds the elements In other words, osg:Quat is composed of an osg::Vec4 The osg::Quat aggregates an osg::Vec4 These seem to be different jargon for the same thing :-) ---------------------------------------------------------- */ Vec4 _fv; // a four-vector inline Quat(): _fv(0.0f,0.0f,0.0f,1.0f) {} inline Quat( float x, float y, float z, float w ): _fv(x,y,z,w) {} inline Quat( const Vec4& v ): _fv(v) {} inline Quat( float angle, const Vec3& axis) { makeRotate(angle,axis); } inline Quat( float angle1, const Vec3& axis1, float angle2, const Vec3& axis2, float angle3, const Vec3& axis3) { makeRotate(angle1,axis1,angle2,axis2,angle3,axis3); } /* ---------------------------------- Methods to access data members ---------------------------------- */ inline Vec4& asVec4() { return _fv; } inline const Vec4& asVec4() const { return _fv; } inline const Vec3 asVec3() const { return Vec3(_fv[0], _fv[1], _fv[2]); } inline void set(float x, float y, float z, float w) { _fv.set(x,y,z,w); } inline void set(const osg::Vec4& v) { _fv = v; } inline float& operator [] (int i) { return _fv[i]; } inline float operator [] (int i) const { return _fv[i]; } inline float& x() { return _fv[0]; } inline float& y() { return _fv[1]; } inline float& z() { return _fv[2]; } inline float& w() { return _fv[3]; } inline float x() const { return _fv[0]; } inline float y() const { return _fv[1]; } inline float z() const { return _fv[2]; } inline float w() const { return _fv[3]; } /** return true if the Quat represents a zero rotation, and therefore can be ignored in computations.*/ bool zeroRotation() const { return _fv[0]==0.0f && _fv[1]==0.0f && _fv[2]==0.0f && _fv[3]==1.0f; } /* ------------------------------------------------------------- BASIC ARITHMETIC METHODS Implemented in terms of Vec4s. Some Vec4 operators, e.g. operator* are not appropriate for quaternions (as mathematical objects) so they are implemented differently. Also define methods for conjugate and the multiplicative inverse. ------------------------------------------------------------- */ /// Multiply by scalar inline const Quat operator * (float rhs) const { return Quat(_fv*rhs); } /// Unary multiply by scalar inline Quat& operator *= (float rhs) { _fv*=rhs; return *this; // enable nesting } /// Binary multiply inline const Quat operator*(const Quat& rhs) const { return Quat( rhs._fv[3]*_fv[0] + rhs._fv[0]*_fv[3] + rhs._fv[1]*_fv[2] - rhs._fv[2]*_fv[1], rhs._fv[3]*_fv[1] - rhs._fv[0]*_fv[2] + rhs._fv[1]*_fv[3] + rhs._fv[2]*_fv[0], rhs._fv[3]*_fv[2] + rhs._fv[0]*_fv[1] - rhs._fv[1]*_fv[0] + rhs._fv[2]*_fv[3], rhs._fv[3]*_fv[3] - rhs._fv[0]*_fv[0] - rhs._fv[1]*_fv[1] - rhs._fv[2]*_fv[2] ); } /// Unary multiply inline Quat& operator*=(const Quat& rhs) { float x = rhs._fv[3]*_fv[0] + rhs._fv[0]*_fv[3] + rhs._fv[1]*_fv[2] - rhs._fv[2]*_fv[1]; float y = rhs._fv[3]*_fv[1] - rhs._fv[0]*_fv[2] + rhs._fv[1]*_fv[3] + rhs._fv[2]*_fv[0]; float z = rhs._fv[3]*_fv[2] + rhs._fv[0]*_fv[1] - rhs._fv[1]*_fv[0] + rhs._fv[2]*_fv[3]; _fv[3] = rhs._fv[3]*_fv[3] - rhs._fv[0]*_fv[0] - rhs._fv[1]*_fv[1] - rhs._fv[2]*_fv[2]; _fv[2] = z; _fv[1] = y; _fv[0] = x; return (*this); // enable nesting } /// Divide by scalar inline const Quat operator / (float rhs) const { return Quat(_fv/rhs); } /// Unary divide by scalar inline Quat& operator /= (float rhs) { _fv/=rhs; return *this; } /// Binary divide inline const Quat operator/(const Quat& denom) const { return ( (*this) * denom.inverse() ); } /// Unary divide inline Quat& operator/=(const Quat& denom) { (*this) = (*this) * denom.inverse(); return (*this); // enable nesting } /// Binary addition inline const Quat operator + (const Quat& rhs) const { return Quat( _fv + rhs._fv ); } /// Unary addition inline Quat& operator += (const Quat& rhs) { _fv += rhs._fv; return *this; // enable nesting } /// Binary subtraction inline const Quat operator - (const Quat& rhs) const { return Quat( _fv - rhs._fv ); } /// Unary subtraction inline Quat& operator -= (const Quat& rhs) { _fv-=rhs._fv; return *this; // enable nesting } /** Negation operator - returns the negative of the quaternion. Basically just calls operator - () on the Vec4 */ inline const Quat operator - () const { return Quat ( -_fv ); } /// Length of the quaternion = sqrt( vec . vec ) float length() const { return _fv.length(); } /// Length of the quaternion = vec . vec float length2() const { return _fv.length2(); } /// Conjugate inline Quat conj () const { return Quat( -_fv[0], -_fv[1], -_fv[2], _fv[3] ); } /// Multiplicative inverse method: q^(-1) = q^*/(q.q^*) inline const Quat inverse () const { return conj() / length2(); } /* -------------------------------------------------------- METHODS RELATED TO ROTATIONS Set a quaternion which will perform a rotation of an angle around the axis given by the vector (x,y,z). Should be written to also accept an angle and a Vec3? Define Spherical Linear interpolation method also Not inlined - see the Quat.cpp file for implementation -------------------------------------------------------- */ void makeRotate( float angle, float x, float y, float z ); void makeRotate ( float angle, const Vec3& vec ); void makeRotate ( float angle1, const Vec3& axis1, float angle2, const Vec3& axis2, float angle3, const Vec3& axis3); /** Make a rotation Quat which will rotate vec1 to vec2. Generally take adot product to get the angle between these and then use a cross product to get the rotation axis Watch out for the two special cases of when the vectors are co-incident or opposite in direction.*/ void makeRotate( const Vec3& vec1, const Vec3& vec2 ); /** Return the angle and vector components represented by the quaternion.*/ void getRotate ( float& angle, float& x, float& y, float& z ) const; /** Return the angle and vector represented by the quaternion.*/ void getRotate ( float& angle, Vec3& vec ) const; /** Spherical Linear Interpolation. As t goes from 0 to 1, the Quat object goes from "from" to "to". */ void slerp ( float t, const Quat& from, const Quat& to); /** Set quaternion to be equivalent to specified matrix.*/ void set( const Matrix& m ); /** Get the equivalent matrix for this quaternion.*/ void get( Matrix& m ) const; /** Get the equivalent matrix for this quaternion.*/ Matrix getMatrix() const { Matrix matrix; get(matrix); return matrix; } friend inline std::ostream& operator << (std::ostream& output, const Quat& vec); }; // end of class prototype inline std::ostream& operator << (std::ostream& output, const Quat& vec) { output << vec._fv[0] << " " << vec._fv[1] << " " << vec._fv[2] << " " << vec._fv[3]; return output; // to enable cascading } } // end of namespace #endif