Program Listing for File Quaternion.hxx

Return to documentation for file (Utils/Quaternion.hxx)

/*--------------------------------------------------------------------------*\
 |                                                                          |
 |  Copyright (C) 2011                                                      |
 |                                                                          |
 |         , __                 , __                                        |
 |        /|/  \               /|/  \                                       |
 |         | __/ _   ,_         | __/ _   ,_                                |
 |         |   \|/  /  |  |   | |   \|/  /  |  |   |                        |
 |         |(__/|__/   |_/ \_/|/|(__/|__/   |_/ \_/|/                       |
 |                           /|                   /|                        |
 |                           \|                   \|                        |
 |                                                                          |
 |      Enrico Bertolazzi                                                   |
 |      Dipartimento di Ingegneria Industriale                              |
 |      Universita` degli Studi di Trento                                   |
 |      email: enrico.bertolazzi@unitn.it                                   |
 |                                                                          |
\*--------------------------------------------------------------------------*/


namespace Utils {

  #ifndef DOXYGEN_SHOULD_SKIP_THIS
  using std::ostream;
  #endif

  template <typename T>
  class Quaternion {
  public:
    typedef T real_type;

  private:
    real_type m_Q[4];

  public:

    Quaternion() {
      m_Q[0] = m_Q[1] = m_Q[2] = m_Q[3] = 0;
    }

    Quaternion(
      real_type A,
      real_type B,
      real_type C,
      real_type D
    ) {
      m_Q[0] = A;
      m_Q[1] = B;
      m_Q[2] = C;
      m_Q[3] = D;
    }

    void
    setup(
      real_type A,
      real_type B,
      real_type C,
      real_type D
    ) {
      m_Q[0] = A;
      m_Q[1] = B;
      m_Q[2] = C;
      m_Q[3] = D;
    }

    void
    print( ostream & os) const {
      os << "[ "
         << m_Q[0] << ", "
         << m_Q[1] << "i, "
         << m_Q[2] << "j, "
         << m_Q[3] << "k ]";
    }

    real_type
    operator [] (int i) const { return m_Q[i]; }

    void
    conj() { m_Q[1] = -m_Q[1]; m_Q[2] = -m_Q[2]; m_Q[3] = -m_Q[3]; }

    void
    invert() {
      real_type bf = 1/(m_Q[0]*m_Q[0] + m_Q[1]*m_Q[1] + m_Q[2]*m_Q[2] + m_Q[3]*m_Q[3]);
      m_Q[0] *= bf; bf = -bf; m_Q[1] *= bf; m_Q[2] *= bf; m_Q[3] *= bf;
    }

    real_type
    norm() const {
      return sqrt(m_Q[0]*m_Q[0] + m_Q[1]*m_Q[1] + m_Q[2]*m_Q[2] + m_Q[3]*m_Q[3]);
    }

    void
    rotate( real_type const v[3], real_type w[3] ) const {
      w[0] = ( m_Q[0] * m_Q[0] + m_Q[1] * m_Q[1] ) * v[0]
           + ( m_Q[1] * m_Q[2] - m_Q[0] * m_Q[3] ) * v[1]
           + ( m_Q[1] * m_Q[3] + m_Q[0] * m_Q[2] ) * v[2];

      w[1] = ( m_Q[1] * m_Q[2] + m_Q[0] * m_Q[3] ) * v[0]
           + ( m_Q[0] * m_Q[0] + m_Q[2] * m_Q[2] ) * v[1]
           + ( m_Q[2] * m_Q[3] - m_Q[0] * m_Q[1] ) * v[2];

      w[2] = ( m_Q[1] * m_Q[3] - m_Q[0] * m_Q[2] ) * v[0]
           + ( m_Q[2] * m_Q[3] + m_Q[0] * m_Q[1] ) * v[1]
           + ( m_Q[0] * m_Q[0] + m_Q[3] * m_Q[3] ) * v[2];

      w[0] = 2*w[0] - v[0];
      w[1] = 2*w[1] - v[1];
      w[2] = 2*w[2] - v[2];
    }

    real_type
    to_axis( real_type axis[3] ) const {
      real_type sin_phi = sqrt( m_Q[1]*m_Q[1] + m_Q[2]*m_Q[2] + m_Q[3]*m_Q[3] );
      real_type cos_phi = m_Q[0];
      real_type angle   = 2 * atan2( sin_phi, cos_phi );
      if ( sin_phi == 0 ) {
        axis[0] = 1; axis[1] = axis[2] = 0;
      } else {
        axis[0] = m_Q[1] / sin_phi;
        axis[1] = m_Q[2] / sin_phi;
        axis[2] = m_Q[3] / sin_phi;
      }
      return angle;
    }

    void
    to_matrix( real_type mat[3][3] ) const {
      real_type axis[3];
      real_type angle = to_axis( axis );
      real_type ca    = cos( angle );
      real_type sa    = sin( angle );

      mat[0][0] =              axis[0] * axis[0] + ca * ( 1 - axis[0] * axis[0] );
      mat[1][0] = ( 1 - ca ) * axis[0] * axis[1] - sa * axis[2];
      mat[2][0] = ( 1 - ca ) * axis[0] * axis[2] + sa * axis[1];

      mat[0][1] = ( 1 - ca ) * axis[1] * axis[0] + sa * axis[2];
      mat[1][1] =              axis[1] * axis[1] + ca * ( 1 - axis[1] * axis[1] );
      mat[2][1] = ( 1 - ca ) * axis[1] * axis[2] - sa * axis[0];

      mat[0][2] = ( 1 - ca ) * axis[2] * axis[0] - sa * axis[1];
      mat[1][2] = ( 1 - ca ) * axis[2] * axis[1] + sa * axis[0];
      mat[2][2] =              axis[2] * axis[2] + ca * ( 1 - axis[2] * axis[2] );
    }

  };

  template <typename T>
  inline
  Quaternion<T>
  operator * ( Quaternion<T> const & a, Quaternion<T> const & b ) {
    return Quaternion<T>( a[0] * b[0] - a[1] * b[1] - a[2] * b[2] - a[3] * b[3],
                          a[0] * b[1] + a[1] * b[0] + a[2] * b[3] - a[3] * b[2],
                          a[0] * b[2] - a[1] * b[3] + a[2] * b[0] + a[3] * b[1],
                          a[0] * b[3] + a[1] * b[2] - a[2] * b[1] + a[3] * b[0] );
  }

  template <typename T>
  inline
  ostream& operator << ( ostream & os,  Quaternion<T> const & Q ) {
    Q.print(os);
    return os;
  }
}