Subversion Repositories gelsvn

Rev

Rev 427 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
595 jab 1
/* ----------------------------------------------------------------------- *
2
 * This file is part of GEL, http://www.imm.dtu.dk/GEL
3
 * Copyright (C) the authors and DTU Informatics
4
 * For license and list of authors, see ../../doc/intro.pdf
5
 * ----------------------------------------------------------------------- */
6
 
7
/** @file ArithQuat.h
8
 * Abstract quaternion class
9
 */
10
 
303 bj 11
#ifndef __CGLA_ARITHQUAT_H__
12
#define __CGLA_ARITHQUAT_H__
13
 
14
#include "CGLA.h"
382 jab 15
#include "ArithVecFloat.h"
323 bj 16
#include "ArithSqMatFloat.h"
303 bj 17
#include <cmath>
18
 
19
namespace CGLA {
20
 
21
  /** \brief A T based Quaterinion class. 
22
 
23
	Quaternions are algebraic entities useful for rotation. */
24
 
25
	template<class T, class V, class Q>
26
  class ArithQuat
27
  {
28
  public:
29
 
30
    /// Vector part of quaternion
31
    V qv;
32
 
33
    /// Scalar part of quaternion
34
    T qw;
35
 
36
    /// Construct undefined quaternion
37
#ifndef NDEBUG
38
    ArithQuat() : qw(CGLA_INIT_VALUE) {}
39
#else
40
    ArithQuat() {}
41
#endif
42
 
43
    /// Construct quaternion from vector and scalar
44
    ArithQuat(const V& imaginary, T real = 1.0f) : qv(imaginary) , qw(real) {}
45
 
46
    /// Construct quaternion from four scalars
47
    ArithQuat(T x, T y, T z, T _qw) : qv(x,y,z), qw(_qw) {}
48
 
49
 
50
    /// Assign values to a quaternion
51
    void set(const V& imaginary, T real=1.0f)
52
    {
53
      qv = imaginary;
54
      qw = real;
55
    }
56
 
57
    void set(T x, T y, T z, T _qw) 
58
    {
59
      qv.set(x,y,z);
60
      qw = _qw;
61
    }
62
 
63
    /*void set(const Vec4f& v)
64
    {
65
      qv.set(v[0], v[1], v[2]);
66
      qw = v[3];		  
67
    }*/
68
 
69
    /// Get values from a quaternion
70
    void get(T& x, T& y, T& z, T& _qw) const
71
    {
72
      x  = qv[0];
73
      y  = qv[1];
74
      z  = qv[2];
75
      _qw = qw;
76
    }
77
 
78
    /// Get imaginary part of a quaternion
79
    V get_imaginary_part() const { return qv; }
80
 
81
    /// Get real part of a quaternion
82
    T get_real_part() const { return qw; }
83
 
84
 
85
 
86
    /// Obtain angle of rotation and axis
87
    void get_rot(T& angle, V& v)
88
    {
89
      angle = 2*std::acos(qw);
90
 
91
      if(angle < TINY) 
92
				v = V(static_cast<T>(1.0), static_cast<T>(0.0), static_cast<T>(0.0));
93
      else 
94
				v = qv*(static_cast<T>(1.0)/std::sin(angle));
95
 
96
      if(angle > M_PI)
97
				v = -v;
98
 
99
      v.normalize();      
100
    }
101
 
102
    /// Construct a Quaternion from an angle and axis of rotation.
103
    void make_rot(T angle, const V& v)
104
    {
105
      angle /= static_cast<T>(2.0);
106
      qv = CGLA::normalize(v)*std::sin(angle);
107
      qw = std::cos(angle);
108
    }
109
 
110
    /** Construct a Quaternion rotating from the direction given
111
	by the first argument to the direction given by the second.*/
112
    void make_rot(const V& s,const V& t)
113
    {
114
      T tmp = std::sqrt(2*(1 + dot(s, t)));
115
      qv = cross(s, t)*(1.0/tmp);
116
      qw = tmp/2.0;    
117
    }
118
 
323 bj 119
	/// Construct a Quaternion from a rotation matrix.
120
    template <class VT, class MT, unsigned int ROWS>
121
    void make_rot(ArithSqMatFloat<VT,MT,ROWS>& m)
122
    {
123
      assert(ROWS==3 || ROWS==4);
124
      T trace = m[0][0] + m[1][1] + m[2][2]  + static_cast<T>(1.0);
125
 
126
      //If the trace of the matrix is greater than zero, then
127
      //perform an "instant" calculation.
128
      if ( trace > TINY ) 
129
      {
130
        T S = sqrt(trace) * static_cast<T>(2.0);
131
        qv = V(m[2][1] - m[1][2], m[0][2] - m[2][0], m[1][0] - m[0][1] );
132
        qv /= S;
133
        qw = static_cast<T>(0.25) * S;
134
      }
135
      else
136
      {
137
        //If the trace of the matrix is equal to zero (or negative...) then identify
138
        //which major diagonal element has the greatest value.
139
        //Depending on this, calculate the following:
140
 
141
        if ( m[0][0] > m[1][1] && m[0][0] > m[2][2] )  {	// Column 0: 
142
          T S  = sqrt( static_cast<T>(1.0) + m[0][0] - m[1][1] - m[2][2] ) * static_cast<T>(2.0);
143
          qv[0] = 0.25f * S;
144
          qv[1] = (m[1][0] + m[0][1] ) / S;
145
          qv[2] = (m[0][2] + m[2][0] ) / S;
146
          qw = (m[2][1] - m[1][3] ) / S;
147
        } else if ( m[1][1] > m[2][2] ) {			// Column 1: 
148
          T S  = sqrt( 1.0 + m[1][1] - m[0][0] - m[2][2] ) * 2.0;
149
          qv[0] = (m[1][0] + m[0][1] ) / S;
150
          qv[1] = 0.25 * S;
151
          qv[2] = (m[2][1] + m[1][2] ) / S;
152
          qw = (m[0][2] - m[2][0] ) / S;
153
        } else {						// Column 2:
154
          T S  = sqrt( 1.0 + m[2][2] - m[0][0] - m[1][1] ) * 2.0;
155
          qv[0] = (m[0][2] + m[2][0] ) / S;
156
          qv[1] = (m[2][1] + m[1][2] ) / S;
157
          qv[2] = 0.25 * S;
158
          qw = (m[1][0] - m[0][1] ) / S;
159
        }
160
      }
161
      //The quaternion is then defined as:
162
      //  Q = | X Y Z W |
163
    }
164
 
303 bj 165
    //----------------------------------------------------------------------
166
    // Binary operators
167
    //----------------------------------------------------------------------
168
 
169
    bool operator==(const ArithQuat<T,V,Q>& q) const
170
    {
171
      return qw == q.qw && qv == q.qv;
172
    }
173
 
174
    bool operator!=(const ArithQuat<T,V,Q>& q) const
175
    {
176
      return qw != q.qw || qv != q.qv;
177
    }
178
 
179
    /// Multiply two quaternions. (Combine their rotation)
180
    Q operator*(const ArithQuat<T,V,Q>& q) const
181
    {
182
      return Q(cross(qv, q.qv) + qv*q.qw + q.qv*qw, 
183
		         qw*q.qw - dot(qv, q.qv));      
184
    }
185
 
186
    /// Multiply scalar onto quaternion.
187
    Q operator*(T scalar) const
188
    {
189
      return Q(qv*scalar, qw*scalar);
190
    }
191
 
192
    /// Add two quaternions.
193
    Q operator+(const ArithQuat<T,V,Q>& q) const
194
    {
195
      return Q(qv + q.qv, qw + q.qw);
196
    }
197
 
198
    //----------------------------------------------------------------------
199
    // Unary operators
200
    //----------------------------------------------------------------------
201
 
202
    /// Compute the additive inverse of the quaternion
203
    Q operator-() const { return Q(-qv, -qw); }
204
 
205
    /// Compute norm of quaternion
206
    T norm() const { return dot(qv, qv) + qw*qw; }
207
 
208
    /// Return conjugate quaternion
209
    Q conjugate() const { return Q(-qv, qw); }
210
 
211
    /// Compute the multiplicative inverse of the quaternion
212
    Q inverse() const { return Q(conjugate()*(1/norm())); }
213
 
214
    /// Normalize quaternion.
215
    Q normalize() { return Q((*this)*(1/norm())); }
216
 
217
    //----------------------------------------------------------------------
218
    // Application
219
    //----------------------------------------------------------------------
220
 
221
    /// Rotate vector according to quaternion
222
    V apply(const V& vec) const 
223
    {
224
      return ((*this)*Q(vec)*inverse()).qv;
225
    }
226
 
227
    /// Rotate vector according to unit quaternion
228
    V apply_unit(const V& vec) const
229
    {
427 jrf 230
	  assert(fabs(norm() - 1.0) < SMALL);
303 bj 231
      return ((*this)*Q(vec)*conjugate()).qv;
232
    }
233
  };
234
 
235
  template<class T, class V, class Q>
236
  inline Q operator*(T scalar, const ArithQuat<T,V,Q>& q)
237
  {
238
    return q*scalar;
239
  }
240
 
241
  /** Perform linear interpolation of two quaternions. 
242
      The last argument is the parameter used to interpolate
243
      between the two first. SLERP - invented by Shoemake -
244
      is a good way to interpolate because the interpolation
245
      is performed on the unit sphere. 	
246
  */
247
	template<class T, class V, class Q>
248
  inline Q slerp(const ArithQuat<T,V,Q>& q0, const ArithQuat<T,V,Q>& q1, T t)
249
  {
250
    T angle = std::acos(q0.qv[0]*q1.qv[0] + q0.qv[1]*q1.qv[1] 
251
			    + q0.qv[2]*q1.qv[2] + q0.qw*q1.qw);
252
    return (q0*std::sin((1 - t)*angle) + q1*std::sin(t*angle))*(1/std::sin(angle));
253
  }
254
 
255
  /// Print quaternion to stream.
256
  template<class T, class V, class Q>
257
  inline std::ostream& operator<<(std::ostream&os, const ArithQuat<T,V,Q>& v)
258
  {
259
    os << "[ ";
260
    for(unsigned int i=0;i<3;i++) os << v.qv[i] << " ";
261
    os << "~ " << v.qw << " ";
262
    os << "]";
263
 
264
    return os;
265
  }
266
}
267
 
268
 
269
 
270
 
271
 
272
 
273
 
274
 
275
 
276
 
277
 
278
 
279
 
280
 
281
 
282
 
283
 
284
#endif // __CGLA_ARITHQUAT_H__