Subversion Repositories gelsvn

Rev

Rev 306 | Go to most recent revision | Details | 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"
5
#include <cmath>
6
 
7
namespace CGLA {
8
 
9
  /** \brief A T based Quaterinion class. 
10
 
11
	Quaternions are algebraic entities useful for rotation. */
12
 
13
	template<class T, class V, class Q>
14
  class ArithQuat
15
  {
16
  public:
17
 
18
    /// Vector part of quaternion
19
    V qv;
20
 
21
    /// Scalar part of quaternion
22
    T qw;
23
 
24
    /// Construct undefined quaternion
25
#ifndef NDEBUG
26
    ArithQuat() : qw(CGLA_INIT_VALUE) {}
27
#else
28
    ArithQuat() {}
29
#endif
30
 
31
    /// Construct quaternion from vector and scalar
32
    ArithQuat(const V& imaginary, T real = 1.0f) : qv(imaginary) , qw(real) {}
33
 
34
    /// Construct quaternion from four scalars
35
    ArithQuat(T x, T y, T z, T _qw) : qv(x,y,z), qw(_qw) {}
36
 
37
 
38
    /// Assign values to a quaternion
39
    void set(const V& imaginary, T real=1.0f)
40
    {
41
      qv = imaginary;
42
      qw = real;
43
    }
44
 
45
    void set(T x, T y, T z, T _qw) 
46
    {
47
      qv.set(x,y,z);
48
      qw = _qw;
49
    }
50
 
51
    /*void set(const Vec4f& v)
52
    {
53
      qv.set(v[0], v[1], v[2]);
54
      qw = v[3];		  
55
    }*/
56
 
57
    /// Get values from a quaternion
58
    void get(T& x, T& y, T& z, T& _qw) const
59
    {
60
      x  = qv[0];
61
      y  = qv[1];
62
      z  = qv[2];
63
      _qw = qw;
64
    }
65
 
66
    /// Get imaginary part of a quaternion
67
    V get_imaginary_part() const { return qv; }
68
 
69
    /// Get real part of a quaternion
70
    T get_real_part() const { return qw; }
71
 
72
 
73
 
74
    /// Obtain angle of rotation and axis
75
    void get_rot(T& angle, V& v)
76
    {
77
      angle = 2*std::acos(qw);
78
 
79
      if(angle < TINY) 
80
				v = V(static_cast<T>(1.0), static_cast<T>(0.0), static_cast<T>(0.0));
81
      else 
82
				v = qv*(static_cast<T>(1.0)/std::sin(angle));
83
 
84
      if(angle > M_PI)
85
				v = -v;
86
 
87
      v.normalize();      
88
    }
89
 
90
    /// Construct a Quaternion from an angle and axis of rotation.
91
    void make_rot(T angle, const V& v)
92
    {
93
      angle /= static_cast<T>(2.0);
94
      qv = CGLA::normalize(v)*std::sin(angle);
95
      qw = std::cos(angle);
96
    }
97
 
98
    /** Construct a Quaternion rotating from the direction given
99
	by the first argument to the direction given by the second.*/
100
    void make_rot(const V& s,const V& t)
101
    {
102
      T tmp = std::sqrt(2*(1 + dot(s, t)));
103
      qv = cross(s, t)*(1.0/tmp);
104
      qw = tmp/2.0;    
105
    }
106
 
107
    //----------------------------------------------------------------------
108
    // Binary operators
109
    //----------------------------------------------------------------------
110
 
111
    bool operator==(const ArithQuat<T,V,Q>& q) const
112
    {
113
      return qw == q.qw && qv == q.qv;
114
    }
115
 
116
    bool operator!=(const ArithQuat<T,V,Q>& q) const
117
    {
118
      return qw != q.qw || qv != q.qv;
119
    }
120
 
121
    /// Multiply two quaternions. (Combine their rotation)
122
    Q operator*(const ArithQuat<T,V,Q>& q) const
123
    {
124
      return Q(cross(qv, q.qv) + qv*q.qw + q.qv*qw, 
125
		         qw*q.qw - dot(qv, q.qv));      
126
    }
127
 
128
    /// Multiply scalar onto quaternion.
129
    Q operator*(T scalar) const
130
    {
131
      return Q(qv*scalar, qw*scalar);
132
    }
133
 
134
    /// Add two quaternions.
135
    Q operator+(const ArithQuat<T,V,Q>& q) const
136
    {
137
      return Q(qv + q.qv, qw + q.qw);
138
    }
139
 
140
    //----------------------------------------------------------------------
141
    // Unary operators
142
    //----------------------------------------------------------------------
143
 
144
    /// Compute the additive inverse of the quaternion
145
    Q operator-() const { return Q(-qv, -qw); }
146
 
147
    /// Compute norm of quaternion
148
    T norm() const { return dot(qv, qv) + qw*qw; }
149
 
150
    /// Return conjugate quaternion
151
    Q conjugate() const { return Q(-qv, qw); }
152
 
153
    /// Compute the multiplicative inverse of the quaternion
154
    Q inverse() const { return Q(conjugate()*(1/norm())); }
155
 
156
    /// Normalize quaternion.
157
    Q normalize() { return Q((*this)*(1/norm())); }
158
 
159
    //----------------------------------------------------------------------
160
    // Application
161
    //----------------------------------------------------------------------
162
 
163
    /// Rotate vector according to quaternion
164
    V apply(const V& vec) const 
165
    {
166
      return ((*this)*Q(vec)*inverse()).qv;
167
    }
168
 
169
    /// Rotate vector according to unit quaternion
170
    V apply_unit(const V& vec) const
171
    {
172
      return ((*this)*Q(vec)*conjugate()).qv;
173
    }
174
  };
175
 
176
  template<class T, class V, class Q>
177
  inline Q operator*(T scalar, const ArithQuat<T,V,Q>& q)
178
  {
179
    return q*scalar;
180
  }
181
 
182
  /** Perform linear interpolation of two quaternions. 
183
      The last argument is the parameter used to interpolate
184
      between the two first. SLERP - invented by Shoemake -
185
      is a good way to interpolate because the interpolation
186
      is performed on the unit sphere. 	
187
  */
188
	template<class T, class V, class Q>
189
  inline Q slerp(const ArithQuat<T,V,Q>& q0, const ArithQuat<T,V,Q>& q1, T t)
190
  {
191
    T angle = std::acos(q0.qv[0]*q1.qv[0] + q0.qv[1]*q1.qv[1] 
192
			    + q0.qv[2]*q1.qv[2] + q0.qw*q1.qw);
193
    return (q0*std::sin((1 - t)*angle) + q1*std::sin(t*angle))*(1/std::sin(angle));
194
  }
195
 
196
  /// Print quaternion to stream.
197
  template<class T, class V, class Q>
198
  inline std::ostream& operator<<(std::ostream&os, const ArithQuat<T,V,Q>& v)
199
  {
200
    os << "[ ";
201
    for(unsigned int i=0;i<3;i++) os << v.qv[i] << " ";
202
    os << "~ " << v.qw << " ";
203
    os << "]";
204
 
205
    return os;
206
  }
207
}
208
 
209
 
210
 
211
 
212
 
213
 
214
 
215
 
216
 
217
 
218
 
219
 
220
 
221
 
222
 
223
 
224
 
225
#endif // __CGLA_ARITHQUAT_H__