Subversion Repositories gelsvn

Rev

Rev 323 | Rev 427 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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