#pragma once #include #include #include #include #include namespace cgv { namespace math { /** * Quaterions are stored in vectors in the following order: * [w, x, y, z] -> w + x*i + y*j + z*k */ // returns the product of quaternion v and q template vec quat_multiply(const vec& v,const vec& q) { assert(v.dim() == 4); assert(q.dim() == 4); vec r(4); r(0) = v[0]*q(0) - v[1]*q(1) - v[2]*q(2) - v[3]*q(3); r(1) = v[0]*q(1) + v[1]*q(0) + v[2]*q(3) - v[3]*q(2); r(2) = v[0]*q(2) + v[2]*q(0) + v[3]*q(1) - v[1]*q(3); r(3) = v[0]*q(3) + v[3]*q(0) + v[1]*q(2) - v[2]*q(1); return r; } ///returns a quaterion q defined by the given axis and angle template vec axis_angle_2_quat(vec axis, T angle) { angle = (T)angle*3.14159/360.0; T s = (T)sinf((float)angle ); axis.normalize(); vec q(4); q(0) = cos(angle ); q(1) = axis(0) * s; q(2) = axis(1) * s; q(3) = axis(2) * s; return q; } ///extract the axis and angle in degree from quaternion q template void quat_2_axis_angle(const vec& q,vec& axis, T& angle) { axis.resize(3); T s = sqrt((q(1) * q(1)) + (q(2) * q(2)) + (q(3) * q(3))); if (s == 0) { axis(0) = 1; axis(1) = 0; axis(2) = 0; angle = 0; } else { axis(0) = q(1) / s; axis(1) = q(2) / s; axis(2) = q(3) / s; angle = 2.0 * acos(q(0)); } } ///returns the rotation of vector v by quaternion q template vec quat_rotate(const vec&q, const vec& v) { assert(v.dim() >= 3); assert(q.dim() == 4); vec pos(v.dim()); T w = - q(1)*v(0) - q(2)*v(1) - q(3)*v(2); T x = q(0)*v(0) + q(2)*v(2) - q(3)*v(1); T y = q(0)*v(1) + q(3)*v(0) - q(1)*v(2); T z = q(0)*v(2) + q(1)*v(1) - q(2)*v(0); pos(0) = -w*q(1) + x*q(0) - y*q(3) + z*q(2); pos(1) = -w*q(2) + y*q(0) - z*q(1) + x*q(3); pos(2) = -w*q(3) + z*q(0) - x*q(2) + y*q(1); int i; for(i = 3; i < v.dim(); i++) pos(i) = v(i); return pos; } ///returns the conjugate quaternion q template vec quat_conj(const vec& q) { vec r(4); r(0) = q(0); r(1) = -q(1); r(2) = -q(2); r(3) = -q(3); } ///returns a normalize version of quaternion q template vec quat_normalize(const vec& q) { T magnitude = sqrt(q(0)*q(0) + q(1)*q(1) + q(2)*q(2) + q(3)*q(3)); vec r(4); r(0)= q(0) / magnitude; r(1)= q(1) / magnitude; r(2)= q(2) / magnitude; r(3)= q(3) / magnitude; return r; } ///return the inverse of quaterion q template vec quat_inv(const vec& q) { T magnitude = sqrt(q(0)*q(0) + q(1)*q(1) + q(2)*q(2) + q(3)*q(3)); vec r(4); r(0)= q(0) / magnitude; r(1)= -q(1) / magnitude; r(2)= -q(2) / magnitude; r(3)= -q(3) / magnitude; return r; } ///convert unit quaternion to 3x3 rotation matrix template mat quat_2_mat_33(const vec& q) { assert(q.dim() == 4); mat m(3,3); T xx = q[1] * q[1]; T xy = q[1] * q[2]; T xz = q[1] * q[3]; T xw = q[1] * q[0]; T yy = q[2] * q[2]; T yz = q[2] * q[3]; T yw = q[2] * q[0]; T zz = q[3] * q[3]; T zw = q[3] * q[0]; m(0,0) = 1 - 2 * ( yy + zz ); m(0,1) = 2 * ( xy - zw ); m(0,2) = 2 * ( xz + yw ); m(1,0) = 2 * ( xy + zw ); m(1,1) = 1 - 2 * ( xx + zz ); m(1,2) = 2 * ( yz - xw ); m(2,0) = 2 * ( xz - yw ); m(2,1) = 2 * ( yz + xw ); m(2,2) = 1 - 2 * ( xx + yy ); return m; } ///convert unit quaternion to 4x4 rotation matrix template mat quat_2_mat_44(const vec& q) { assert(q.dim() == 4); mat m(4,4); T xx = q[1] * q[1]; T xy = q[1] * q[2]; T xz = q[1] * q[3]; T xw = q[1] * q[0]; T yy = q[2] * q[2]; T yz = q[2] * q[3]; T yw = q[2] * q[0]; T zz = q[3] * q[3]; T zw = q[3] * q[0]; m(0,0) = 1 - 2 * ( yy + zz ); m(0,1) = 2 * ( xy - zw ); m(0,2) = 2 * ( xz + yw ); m(1,0) = 2 * ( xy + zw ); m(1,1) = 1 - 2 * ( xx + zz ); m(1,2) = 2 * ( yz - xw ); m(2,0) = 2 * ( xz - yw ); m(2,1) = 2 * ( yz + xw ); m(2,2) = 1 - 2 * ( xx + yy ); m(3,0) = m(3,1) = m(3,2) = m(0,3) = m(1,3) = m(2,3) = 0; m(3,3) = 1; return m; } /* /// A column vector class. template class quat { private: ///pointer to _data storage T v[4]; public: quat() { v[0] = 0; v[1] = 0; v[2] = 0; v[3] = 1; } quat(const T& x,const T& y,const T& z,const T w) { v[0] = x; v[1] = y; v[2] = z; v[3] = w; } quat(const vec& axis,const T angle) { set(axis,angle); } quat(const quat &q) { for (int i=0; i<4; i++) v[i]=q(i); } quat& operator=(const quat &rhs) { if (this != &rhs) { for (int i=0; i<4; i++) v[i]=rhs(i); } return *this; } void conjugate() { v[0] = -v[0]; v[1] = -v[1]; v[2] = -v[2]; } quat& operator*=(const quat& q) { T w = v[3]*q(3) - v[0]*q(0) - v[1]*q(1) - v[2]*q(2); T x = v[3]*q(0) + v[0]*q(3) + v[1]*q(2) - v[2]*q(1); T y = v[3]*q(1) + v[1]*q(3) + v[2]*q(0) - v[0]*q(2); T z = v[3]*q(2) + v[2]*q(3) + v[0]*q(1) - v[1]*q(0); v[0]=x; v[1]=y; v[2]=z; v[3]=w; return *this; } const quat operator*(const quat& q)const { quat r =*this; r*=q; return r; } T length() { T l =0; for(int i = 0; i < 4;i++) l += v[i]*v[i]; return sqrt(l); } T sqr_length() { T l =0; for(int i = 0; i < 4;i++) l += v[i]*v[i]; return l; } mat to_mat_33() const { mat mat(3,3); T xx = v[0] * v[0]; T xy = v[0] * v[1]; T xz = v[0] * v[2]; T xw = v[0] * v[3]; T yy = v[1] * v[1]; T yz = v[1] * v[2]; T yw = v[1] * v[3]; T zz = v[2] * v[2]; T zw = v[2] * v[3]; mat(0,0) = 1 - 2 * ( yy + zz ); mat(0,1) = 2 * ( xy - zw ); mat(0,2) = 2 * ( xz + yw ); mat(1,0) = 2 * ( xy + zw ); mat(1,1) = 1 - 2 * ( xx + zz ); mat(1,2) = 2 * ( yz - xw ); mat(2,0) = 2 * ( xz - yw ); mat(2,1) = 2 * ( yz + xw ); mat(2,2) = 1 - 2 * ( xx + yy ); return mat; } mat to_mat_44() const { mat mat(4,4); T xx = v[0] * v[0]; T xy = v[0] * v[1]; T xz = v[0] * v[2]; T xw = v[0] * v[3]; T yy = v[1] * v[1]; T yz = v[1] * v[2]; T yw = v[1] * v[3]; T zz = v[2] * v[2]; T zw = v[2] * v[3]; mat(0,0) = 1 - 2 * ( yy + zz ); mat(0,1) = 2 * ( xy - zw ); mat(0,2) = 2 * ( xz + yw ); mat(1,0) = 2 * ( xy + zw ); mat(1,1) = 1 - 2 * ( xx + zz ); mat(1,2) = 2 * ( yz - xw ); mat(2,0) = 2 * ( xz - yw ); mat(2,1) = 2 * ( yz + xw ); mat(2,2) = 1 - 2 * ( xx + yy ); mat(3,0) = mat(3,1) =mat(3,2)=mat(0,3)=mat(1,3)=mat(2,3) = 0; mat(3,3) = 1; return mat; } T& operator()(const int i) //subscripting { return v[i]; } const T& operator()(const int i) const //subscripting { return v[i]; } ///cast into non const array operator T*() { return v; } ///cast into const array operator const T*() const { return v; } ///normalize the vector void normalize() { T l =0; for(int i = 0; i < 4;i++) l += v[i]*v[i]; l=(T)1.0/sqrt(l); for(unsigned i = 0; i<4; i++) operator()(i)=l*operator()(i); } void set(const T& x, const T&y, const T&z,const T&w) { v[0]=x; v[1]=y; v[2]=z; v[3]=w; } void set(vec axis, const T angle) { axis.normalize(); T sin_a = (T)sin( angle / (T)2.0 ); T cos_a = (T)cos( angle / (T)2.0 ); v[0] = axis.x() * sin_a; v[1] = axis.y() * sin_a; v[2] = axis.z() * sin_a; v[3] = cos_a; } void invert() { conjugate(); normalize(); } void rotate(vec& pos) const { T w = - v[0]*pos(0) - v[1]*pos(1) - v[2]*pos(2); T x = v[3]*pos(0) + v[1]*pos(2) - v[2]*pos(1); T y = v[3]*pos(1) + v[2]*pos(0) - v[0]*pos(2); T z = v[3]*pos(2) + v[0]*pos(1) - v[1]*pos(0); pos(0) = -w*v[0] + x*v[3] - y*v[2] + z*v[1]; pos(1) = -w*v[1] + y*v[3] - z*v[0] + x*v[2]; pos(2) = -w*v[2] + z*v[3] - x*v[1] + y*v[0]; } }; template vec rotate(const quat& q,const vec& pos) { vec v = pos; q.rotate(v); return v; } template quat normalize(const quat& q) { quat r = q; r.normalize(); return r; } //output of a vector template std::ostream& operator<<(std::ostream& out, const quat& q) { for (unsigned i=0;i<3;++i) { out << q(i)<<"\t"; } out << q(3); return out; } //input of a vector template std::istream& operator>>(std::istream& in, quat& q) { for (unsigned i=0;i<4;++i) { in >> q(i); } return in; } */ } }