/**************************************************************************** * VCGLib o o * * Visual and Computer Graphics Library o o * * _ O _ * * Copyright(C) 2004 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program 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 * * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * ****************************************************************************/ /**************************************************************************** History $Log: not supported by cvs2svn $ Revision 1.17 2007/02/06 12:24:07 tarini added a missing "Quaternion::" in "FromEulerAngles" Revision 1.16 2007/02/05 13:55:21 corsini add euler angle to quaternion conversion Revision 1.15 2006/06/22 08:00:26 ganovelli toMatrix with matrix33 added Revision 1.14 2005/04/17 21:57:03 ganovelli tolto il const a interpolate Revision 1.13 2005/04/15 09:19:50 ponchio Typo: Point3 -> Point4 Revision 1.12 2005/04/14 17:22:34 ponchio *** empty log message *** Revision 1.11 2005/04/14 11:35:09 ponchio *** empty log message *** Revision 1.10 2004/12/15 18:45:50 tommyfranken *** empty log message *** Revision 1.9 2004/10/22 14:35:42 ponchio m.element(x, y) -> m[x][y] Revision 1.8 2004/10/07 13:54:03 ganovelli added SetIdentity Revision 1.7 2004/04/07 10:48:37 cignoni updated access to matrix44 elements through V() instead simple [] Revision 1.6 2004/03/25 14:57:49 ponchio Microerror. ($LOG$ -> $Log: not supported by cvs2svn $ Microerror. ($LOG$ -> Revision 1.17 2007/02/06 12:24:07 tarini Microerror. ($LOG$ -> added a missing "Quaternion::" in "FromEulerAngles" Microerror. ($LOG$ -> Microerror. ($LOG$ -> Revision 1.16 2007/02/05 13:55:21 corsini Microerror. ($LOG$ -> add euler angle to quaternion conversion Microerror. ($LOG$ -> Microerror. ($LOG$ -> Revision 1.15 2006/06/22 08:00:26 ganovelli Microerror. ($LOG$ -> toMatrix with matrix33 added Microerror. ($LOG$ -> Microerror. ($LOG$ -> Revision 1.14 2005/04/17 21:57:03 ganovelli Microerror. ($LOG$ -> tolto il const a interpolate Microerror. ($LOG$ -> Microerror. ($LOG$ -> Revision 1.13 2005/04/15 09:19:50 ponchio Microerror. ($LOG$ -> Typo: Point3 -> Point4 Microerror. ($LOG$ -> Microerror. ($LOG$ -> Revision 1.12 2005/04/14 17:22:34 ponchio Microerror. ($LOG$ -> *** empty log message *** Microerror. ($LOG$ -> Microerror. ($LOG$ -> Revision 1.11 2005/04/14 11:35:09 ponchio Microerror. ($LOG$ -> *** empty log message *** Microerror. ($LOG$ -> Microerror. ($LOG$ -> Revision 1.10 2004/12/15 18:45:50 tommyfranken Microerror. ($LOG$ -> *** empty log message *** Microerror. ($LOG$ -> Microerror. ($LOG$ -> Revision 1.9 2004/10/22 14:35:42 ponchio Microerror. ($LOG$ -> m.element(x, y) -> m[x][y] Microerror. ($LOG$ -> Microerror. ($LOG$ -> Revision 1.8 2004/10/07 13:54:03 ganovelli Microerror. ($LOG$ -> added SetIdentity Microerror. ($LOG$ -> Microerror. ($LOG$ -> Revision 1.7 2004/04/07 10:48:37 cignoni Microerror. ($LOG$ -> updated access to matrix44 elements through V() instead simple [] Microerror. ($LOG$ -> ****************************************************************************/ #ifndef QUATERNION_H #define QUATERNION_H #include #include #include #include #include namespace vcg { /** Classe quaternion. A quaternion is a point in the unit sphere in four dimension: all rotations in three-dimensional space can be represented by a quaternion. */ template class Quaternion: public Point4 { public: Quaternion() {} Quaternion(const S v0, const S v1, const S v2, const S v3): Point4(v0,v1,v2,v3){} Quaternion(const Point4 p) : Point4(p) {} Quaternion(const S phi, const Point3 &a); Quaternion operator*(const S &s) const; //Quaternion &operator*=(S d); Quaternion operator*(const Quaternion &q) const; Quaternion &operator*=(const Quaternion &q); void Invert(); void SetIdentity(); void FromAxis(const S phi, const Point3 &a); void ToAxis(S &phi, Point3 &a ) const; void FromMatrix(Matrix44 &m); void ToMatrix(Matrix44 &m) const; void ToMatrix(Matrix33 &m) const; void ToEulerAngles(S &alpha, S &beta, S &gamma); void FromEulerAngles(S alpha, S beta, S gamma); Point3 Rotate(const Point3 vec) const; //duplicated ... because of gcc new confoming to ISO template derived classes //do no 'see' parent members (unless explicitly specified) const S & V ( const int i ) const { assert(i>=0 && i<4); return Point4::V(i); } S & V ( const int i ) { assert(i>=0 && i<4); return Point4::V(i); } }; template Quaternion Interpolate( Quaternion a, Quaternion b, double t); template Quaternion &Invert(Quaternion &q); template Quaternion Inverse(const Quaternion &q); //Implementation template void Quaternion::SetIdentity(){ FromAxis(0, Point3(1, 0, 0)); } template Quaternion::Quaternion(const S phi, const Point3 &a) { FromAxis(phi, a); } template Quaternion Quaternion::operator*(const S &s) const { return (Quaternion(V(0)*s,V(1)*s,V(2)*s,V(3)*s)); } template Quaternion Quaternion::operator*(const Quaternion &q) const { Point3 t1(V(1), V(2), V(3)); Point3 t2(q.V(1), q.V(2), q.V(3)); S d = t2 * t1; Point3 t3 = t1 ^ t2; t1 *= q.V(0); t2 *= V(0); Point3 tf = t1 + t2 +t3; Quaternion t; t.V(0) = V(0) * q.V(0) - d; t.V(1) = tf[0]; t.V(2) = tf[1]; t.V(3) = tf[2]; return t; } template Quaternion &Quaternion::operator*=(const Quaternion &q) { S ww = V(0) * q.V(0) - V(1) * q.V(1) - V(2) * q.V(2) - V(3) * q.V(3); S xx = V(0) * q.V(1) + V(1) * q.V(0) + V(2) * q.V(3) - V(3) * q.V(2); S yy = V(0) * q.V(2) - V(1) * q.V(3) + V(2) * q.V(0) + V(3) * q.V(1); V(0) = ww; V(1) = xx; V(2) = yy; V(3) = V(0) * q.V(3) + V(1) * q.V(2) - V(2) * q.V(1) + V(3) * q.V(0); return *this; } template void Quaternion::Invert() { V(1)*=-1; V(2)*=-1; V(3)*=-1; } template void Quaternion::FromAxis(const S phi, const Point3 &a) { Point3 b = a; b.Normalize(); S s = math::Sin(phi/(S(2.0))); V(0) = math::Cos(phi/(S(2.0))); V(1) = b[0]*s; V(2) = b[1]*s; V(3) = b[2]*s; } template void Quaternion::ToAxis(S &phi, Point3 &a) const { S s = math::Asin(V(0))*S(2.0); phi = math::Acos(V(0))*S(2.0); if(s < 0) phi = - phi; a.V(0) = V(1); a.V(1) = V(2); a.V(2) = V(3); a.Normalize(); } template Point3 Quaternion::Rotate(const Point3 p) const { Quaternion co = *this; co.Invert(); Quaternion tmp(0, p.V(0), p.V(1), p.V(2)); tmp = (*this) * tmp * co; return Point3(tmp.V(1), tmp.V(2), tmp.V(3)); } template void Quaternion::ToMatrix(Matrix44 &m) const { S q00 = V(1)*V(1); S q01 = V(1)*V(2); S q02 = V(1)*V(3); S q03 = V(1)*V(0); S q11 = V(2)*V(2); S q12 = V(2)*V(3); S q13 = V(2)*V(0); S q22 = V(3)*V(3); S q23 = V(3)*V(0); m[0][0] = (S)(1.0-(q11 + q22)*2.0); m[1][0] = (S)((q01 - q23)*2.0); m[2][0] = (S)((q02 + q13)*2.0); m[3][0] = (S)0.0; m[0][1] = (S)((q01 + q23)*2.0); m[1][1] = (S)(1.0-(q22 + q00)*2.0); m[2][1] = (S)((q12 - q03)*2.0); m[3][1] = (S)0.0; m[0][2] = (S)((q02 - q13)*2.0); m[1][2] = (S)((q12 + q03)*2.0); m[2][2] = (S)(1.0-(q11 + q00)*2.0); m[3][2] = (S)0.0; m[0][3] = (S)0.0; m[1][3] = (S)0.0; m[2][3] = (S)0.0; m[3][3] = (S)1.0; } template void Quaternion::ToMatrix(Matrix33 &m) const { S q00 = V(1)*V(1); S q01 = V(1)*V(2); S q02 = V(1)*V(3); S q03 = V(1)*V(0); S q11 = V(2)*V(2); S q12 = V(2)*V(3); S q13 = V(2)*V(0); S q22 = V(3)*V(3); S q23 = V(3)*V(0); m[0][0] = (S)(1.0-(q11 + q22)*2.0); m[1][0] = (S)((q01 - q23)*2.0); m[2][0] = (S)((q02 + q13)*2.0); m[0][1] = (S)((q01 + q23)*2.0); m[1][1] = (S)(1.0-(q22 + q00)*2.0); m[2][1] = (S)((q12 - q03)*2.0); m[0][2] = (S)((q02 - q13)*2.0); m[1][2] = (S)((q12 + q03)*2.0); m[2][2] = (S)(1.0-(q11 + q00)*2.0); } ///warning m deve essere una matrice di rotazione pena il disastro. template void Quaternion::FromMatrix(Matrix44 &m) { S Sc; S t = (m.V()[0] + m.V()[5] + m.V()[10] + (S)1.0); if(t > 0) { Sc = (S)0.5 / math::Sqrt(t); V(0) = (S)0.25 / Sc; V(1) = ( m.V()[9] - m.V()[6] ) * Sc; V(2) = ( m.V()[2] - m.V()[8] ) * Sc; V(3) = ( m.V()[4] - m.V()[1] ) * Sc; } else { if(m.V()[0] > m.V()[5] && m.V()[0] > m.V()[10]) { Sc = math::Sqrt( (S)1.0 + m.V()[0] - m.V()[5] - m.V()[10] ) * (S)2.0; V(1) = (S)0.5 / Sc; V(2) = (m.V()[1] + m.V()[4] ) / Sc; V(3) = (m.V()[2] + m.V()[8] ) / Sc; V(0) = (m.V()[6] + m.V()[9] ) / Sc; } else if( m.V()[5] > m.V()[10]) { Sc = math::Sqrt( (S)1.0 + m.V()[5] - m.V()[0] - m.V()[10] ) * (S)2.0; V(1) = (m.V()[1] + m.V()[4] ) / Sc; V(2) = (S)0.5 / Sc; V(3) = (m.V()[6] + m.V()[9] ) / Sc; V(0) = (m.V()[2] + m.V()[8] ) / Sc; } else { Sc = math::Sqrt( (S)1.0 + m.V()[10] - m.V()[0] - m.V()[5] ) * (S)2.0; V(1) = (m.V()[2] + m.V()[8] ) / Sc; V(2) = (m.V()[6] + m.V()[9] ) / Sc; V(3) = (S)0.5 / Sc; V(0) = (m.V()[1] + m.V()[4] ) / Sc; } } } template void Quaternion::ToEulerAngles(S &alpha, S &beta, S &gamma) { //...TODO... } template void Quaternion::FromEulerAngles(S alpha, S beta, S gamma) { S cosalpha = cos(alpha / 2.0); S cosbeta = cos(beta / 2.0); S cosgamma = cos(gamma / 2.0); S sinalpha = sin(alpha / 2.0); S sinbeta = sin(beta / 2.0); S singamma = sin(gamma / 2.0); V(0) = cosalpha * cosbeta * cosgamma + sinalpha * sinbeta * singamma; V(1) = sinalpha * cosbeta * cosgamma - cosalpha * sinbeta * singamma; V(2) = cosalpha * sinbeta * cosgamma + sinalpha * cosbeta * singamma; V(3) = cosalpha * cosbeta * singamma - sinalpha * sinbeta * cosgamma; } template Quaternion &Invert(Quaternion &m) { m.Invert(); return m; } template Quaternion Inverse(const Quaternion &m) { Quaternion a = m; a.Invert(); return a; } template Quaternion Interpolate( Quaternion a , Quaternion b , double t) { double v = a.V(0) * b.V(0) + a.V(1) * b.V(1) + a.V(2) * b.V(2) + a.V(3) * b.V(3); double phi = math::Acos(v); if(phi > 0.01) { a = a * (math::Sin(phi *(1-t))/math::Sin(phi)); b = b * (math::Sin(phi * t)/math::Sin(phi)); } Quaternion c; c.V(0) = a.V(0) + b.V(0); c.V(1) = a.V(1) + b.V(1); c.V(2) = a.V(2) + b.V(2); c.V(3) = a.V(3) + b.V(3); if(v < -0.999) { //almost opposite double d = t * (1 - t); if(c.V(0) == 0) c.V(0) += d; else c.V(1) += d; } c.Normalize(); return c; } typedef Quaternion Quaternionf; typedef Quaternion Quaterniond; } // end namespace #endif