Advertisement
Guest User

vec.h

a guest
Jan 18th, 2014
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.51 KB | None | 0 0
  1. //
  2. // Quaternion Class
  3. //
  4. #ifndef CQuat_h
  5. #define CQuat_h
  6.  
  7. #include "vec3.h"
  8.  
  9. const float TO_HALF_RAD = 3.14159265f / 360.0f;
  10. const float MINVAL = 0.005f;
  11.  
  12. class CQuat
  13. {
  14. public:
  15.     float x,y,z,w;
  16.  
  17.     CQuat( ) : x(0), y(0), z(0), w(1)
  18.     {
  19.     }
  20.  
  21.     CQuat( float fx, float fy, float fz, float fw ) : x(fx), y(fy), z(fz), w(fw)
  22.     {
  23.     }
  24.  
  25.     // This just took four floats initially to avoid dependence on the vector class
  26.     // but I decided avoiding confusion with the value setting constructor was more important
  27.     CQuat( float Angle, const CVec3& Axis )
  28.     {
  29.         SetAxis( Angle, Axis.x, Axis.y, Axis.z );
  30.     }
  31.  
  32.     // No rotation
  33.     void Reset( )
  34.     {
  35.         x = 0;
  36.         y = 0;
  37.         z = 0;
  38.         w = 1;
  39.     }
  40.  
  41.     // Set Quat from axis-angle
  42.     void SetAxis( float degrees, float fX, float fY, float fZ )
  43.     {
  44.         float HalfAngle = degrees * TO_HALF_RAD; // Get half angle in radians from angle in degrees
  45.         float sinA = (float)sin( HalfAngle ) ;
  46.         w = (float)cos( HalfAngle );
  47.         x = fX * sinA;
  48.         y = fY * sinA;
  49.         z = fZ * sinA;
  50.     }
  51.  
  52.     CQuat Invert( ) const
  53.     {
  54.         return CQuat( -x, -y, -z, w );
  55.     }
  56.  
  57.     // Note that order matters with concatenating Quaternion rotations
  58.     inline CQuat operator* (const CQuat &b) const
  59.     {
  60.         CQuat r;
  61.  
  62.         r.w = w*b.w - x*b.x  -  y*b.y  -  z*b.z;
  63.         r.x = w*b.x + x*b.w  +  y*b.z  -  z*b.y;
  64.         r.y = w*b.y + y*b.w  +  z*b.x  -  x*b.z;
  65.         r.z = w*b.z + z*b.w  +  x*b.y  -  y*b.x;
  66.  
  67.         return r;
  68.     }
  69.  
  70.     // You could add an epsilon to this equality test if needed
  71.     inline bool operator== ( const CQuat &b ) const
  72.     {
  73.         return (x == b.x && y == b.y && z == b.z && w == b.w);
  74.     }
  75.  
  76.     int IsIdentity( ) const
  77.     {
  78.         return (x == 0.0f && y == 0.0f && z == 0.0f && w==1.0f);
  79.     }
  80.  
  81.     // Can be used the determine Quaternion neighbourhood
  82.     float Dot( const CQuat& a ) const
  83.     {
  84.         return x * a.x + y * a.y + z * a.z + w * a.w;
  85.     }
  86.  
  87.     // Scalar multiplication
  88.     CQuat operator*( float s ) const
  89.     {
  90.         return CQuat(x * s, y * s, z * s, w * s );
  91.     }
  92.  
  93.     // Addition
  94.     CQuat operator+ ( const CQuat& b ) const
  95.     {
  96.         return CQuat( x + b.x, y + b.y, z + b.z, w + b.w );
  97.     }
  98.  
  99.     // ------------------------------------
  100.     // Simple Euler Angle to Quaternion conversion, this could be made faster
  101.     // ------------------------------------
  102.     void FromEuler( float rx, float ry, float rz )
  103.     {
  104.         CQuat qx(-rx, CVec3( 1, 0, 0 ) );
  105.         CQuat qy(-ry, CVec3( 0, 1, 0 ) );
  106.         CQuat qz(-rz, CVec3( 0, 0, 1 ) );
  107.         qz = qy * qz;
  108.         *this = qx * qz;
  109.     }
  110.  
  111.     // ------------------------------------
  112.     // Quaternions store scale as well as rotation, but usually we just want rotation, so we can normalize.
  113.     // ------------------------------------
  114.     int Normalize( )
  115.     {
  116.         float lengthSq = x * x + y * y + z * z + w * w;
  117.  
  118.         if (lengthSq == 0.0 ) return -1;
  119.         if (lengthSq != 1.0 )
  120.             {
  121.             float scale = ( 1.0f / sqrtf( lengthSq ) );
  122.             x *= scale;
  123.             y *= scale;
  124.             z *= scale;
  125.             w *= scale;
  126.             return 1;
  127.             }
  128.         return 0;
  129.     }
  130.  
  131.     // ------------------------------------
  132.     // Creates a value for this Quaternion from spherical linear interpolation
  133.     // t is the interpolation value from 0 to 1
  134.     // if bReduceTo360 is true, the interpolation will take the shortest path for a 360 deg angle range (max delta rotation = 180 degrees)
  135.     // if bReduceTo360 is false, the interpolation will take the shortest path for a 720 deg angle range (max delta rotation = 360 degrees)
  136.     // ------------------------------------
  137.     void Slerp(const CQuat& a, const CQuat& b, float t, const bool bReduceTo360 )
  138.     {
  139.       float w1, w2;
  140.       int bFlip = 0;
  141.  
  142.       float cosTheta = a.Dot(b);
  143.       if ( bReduceTo360 && cosTheta < 0.0f ) { // We need to flip a quaternion for shortest path interpolation
  144.           cosTheta = -cosTheta;
  145.           bFlip = 1;
  146.       }
  147.       float theta    = acos(cosTheta);
  148.       float sinTheta = sin(theta);
  149.  
  150.       if( sinTheta > MINVAL )
  151.       {
  152.         w1 = sin( (1.0f-t)*theta ) / sinTheta;
  153.         w2 = sin( t*theta) / sinTheta;
  154.       } else {
  155.         // They're almost the same quaternion
  156.         w1 = 1.0f - t;
  157.         w2 = t;
  158.       }
  159.  
  160.       if ( bFlip )
  161.           w2 = -w2;
  162.  
  163.       *this = a*w1 + b*w2;
  164.     }
  165.  
  166.     #define EPSILON 0.00001f
  167.  
  168.     void QuaternionSlerp(const CQuat& quat0, const CQuat& quat1, float t)
  169.     {
  170.         float cosineom, sineom, scalar_x, scalar_y, scalar_z, scalar_w;
  171.         float omega, scale0, scale1;
  172.  
  173.         CQuat newquat;
  174.  
  175.         if ((fabs(quat0.x - quat1.x) < EPSILON)&&(fabs(quat0.y - quat1.y) < EPSILON)&&
  176.            (fabs(quat0.z - quat1.z) < EPSILON)&&(fabs(quat0.w - quat1.w) < EPSILON))
  177.         {
  178.             newquat.x = quat1.x;
  179.             newquat.y = quat1.y;
  180.             newquat.z = quat1.z;
  181.             newquat.w = quat1.w;
  182.             *this = newquat;
  183.         }
  184.  
  185.         cosineom = quat0.x*quat1.x + quat0.y*quat1.y + quat0.z*quat1.z + quat0.w*quat1.w;
  186.  
  187.         if (cosineom<=0)
  188.         {
  189.             cosineom = -cosineom;
  190.             scalar_x = -quat1.x;
  191.             scalar_y = -quat1.y;
  192.             scalar_z = -quat1.z;
  193.             scalar_w = -quat1.w;
  194.         }
  195.         else
  196.         {
  197.             scalar_x = quat1.x;
  198.             scalar_y = quat1.y;
  199.             scalar_z = quat1.z;
  200.             scalar_w = quat1.w;
  201.         }
  202.  
  203.         if ((1.0f - cosineom) > EPSILON)
  204.         {   // do this whole SLerp thing
  205.             omega = acosf(cosineom);
  206.             sineom = sinf(omega);
  207.             scale0 = sinf((1.0f - t)*omega)/sineom;
  208.             scale1 = sinf(t*omega)/sineom;
  209.         }
  210.         else
  211.         {   // close enough to do a straight up linear interpolation
  212.             scale0 = 1.0f - t;
  213.             scale1 = t;
  214.         }
  215.  
  216.         newquat.x=scale0*quat0.x + scale1*scalar_x;
  217.         newquat.y=scale0*quat0.y + scale1*scalar_y;
  218.         newquat.z=scale0*quat0.z + scale1*scalar_z;
  219.         newquat.w=scale0*quat0.w + scale1*scalar_w;
  220.  
  221.         *this = newquat;
  222.     }
  223.     // ------------------------------------
  224.     // linearly interpolate each component, then normalize the Quaternion
  225.     // Unlike spherical interpolation, this does not rotate at a constant velocity,
  226.     // although that's not necessarily a bad thing
  227.     // ------------------------------------
  228.     void Nlerp(const CQuat &a, const CQuat &b, float t, const bool bReduceTo360 )
  229.     {
  230.         float t1 = 1.0f - t;
  231.  
  232.         if ( bReduceTo360 && a.Dot(b) < 0.0f )
  233.             *this = a * t1 + b * -t;
  234.         else
  235.             *this = a * t1 + b * t;
  236.  
  237.         Normalize();
  238.     }
  239.  
  240.     // ------------------------------------
  241.     // Set a 4x4 matrix with the rotation of this Quaternion
  242.     // ------------------------------------
  243.     void inline ToMatrix( float mf[16] ) const
  244.     {
  245.         float x2 = 2.0f * x,  y2 = 2.0f * y,  z2 = 2.0f * z;
  246.  
  247.         float xy = x2 * y,  xz = x2 * z;
  248.         float yy = y2 * y,  yw = y2 * w;
  249.         float zw = z2 * w,  zz = z2 * z;
  250.  
  251.         mf[ 0] = 1.0f - ( yy + zz );
  252.         mf[ 1] = ( xy - zw );
  253.         mf[ 2] = ( xz + yw );
  254.         mf[ 3] = 0.0f;
  255.  
  256.         float xx = x2 * x,  xw = x2 * w,  yz = y2 * z;
  257.  
  258.         mf[ 4] = ( xy +  zw );
  259.         mf[ 5] = 1.0f - ( xx + zz );
  260.         mf[ 6] = ( yz - xw );
  261.         mf[ 7] = 0.0f;
  262.  
  263.         mf[ 8] = ( xz - yw );
  264.         mf[ 9] = ( yz + xw );
  265.         mf[10] = 1.0f - ( xx + yy );
  266.         mf[11] = 0.0f;
  267.  
  268.         mf[12] = 0.0f;
  269.         mf[13] = 0.0f;
  270.         mf[14] = 0.0f;
  271.         mf[15] = 1.0f;
  272.     }
  273.  
  274.     // ------------------------------------
  275.     // Set this Quat to aim the Z-Axis along the vector from P1 to P2
  276.     // ------------------------------------
  277.     void AimZAxis( const CVec3& P1, const CVec3& P2 )
  278.     {
  279.         CVec3 vAim = P2 - P1;
  280.         vAim.Normalize();
  281.  
  282.         x = vAim.y;
  283.         y = -vAim.x;
  284.         z = 0.0f;
  285.         w = 1.0f + vAim.z;
  286.  
  287.         if ( x == 0.0f && y == 0.0f && z == 0.0f && w == 0.0f ) {
  288.             *this = CQuat( 0, 1, 0, 0 ); // If we can't normalize it, just set it
  289.         } else {
  290.             Normalize();
  291.         }
  292.     }
  293. };
  294.  
  295. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement