Quaternion.h
1//-*-C++-*-
2/***************************************************************************
3 *
4 * Copyright (C) 2003-2009 by Willem van Straten
5 * Licensed under the Academic Free License version 2.1
6 *
7 ***************************************************************************/
8
9// epsic/src/util/Quaternion.h
10
11#ifndef __Quaternion_H
12#define __Quaternion_H
13
14#include "Traits.h"
15#include "complex_promote.h"
16#include "Vector.h"
17
19
25enum QBasis { Hermitian, Unitary };
26
28template<typename T, QBasis B = Unitary>
29class Quaternion {
30
31public:
32 T s0,s1,s2,s3;
33
35 Quaternion (const T& a=0.0, const T& b=0.0, const T& c=0.0, const T& d=0.0)
36 : s0(a), s1(b), s2(c), s3(d) { }
37
39 template<typename U> Quaternion (T s, const Vector<3, U>& v)
40 : s0(s), s1(v[0]), s2(v[1]), s3(v[2]) { }
41
43 template<typename U> Quaternion (const Quaternion<U, B>& s)
44 : s0(s.s0), s1(s.s1), s2(s.s2), s3(s.s3) { }
45
47 template<typename U>
49 { s0=T(s.s0); s1=T(s.s1); s2=T(s.s2); s3=T(s.s3); return *this; }
50
52 const Quaternion& operator += (const T& s)
53 { s0+=s; return *this; }
54
56 const Quaternion& operator -= (const T& s)
57 { s0-=s; return *this; }
58
60 const Quaternion& operator *= (const T& a)
61 { s0*=a; s1*=a; s2*=a; s3*=a; return *this; }
62
64 const Quaternion& operator /= (const T& a)
65 { T d(1.0); d/=a; s0*=d; s1*=d; s2*=d; s3*=d; return *this; }
66
68 template<class U>
70 { s0+=s.s0; s1+=s.s1; s2+=s.s2; s3+=s.s3; return *this; }
71
73 template<class U>
75 { s0-=s.s0; s1-=s.s1; s2-=s.s2; s3-=s.s3; return *this; }
76
78 template<class U>
80 { *this = *this * s; return *this; }
81
83 bool operator == (const Quaternion& b) const
84 { return s0==b.s0 && s1==b.s1 && s2==b.s2 && s3==b.s3; }
85
87 bool operator == (T scalar) const
88 { return s0==scalar && s1==0 && s2==0 && s3==0; }
89
91 bool operator != (const Quaternion& b) const
92 { return ! operator==(b); }
93
95 const friend Quaternion operator - (Quaternion s)
96 { s.s0=-s.s0; s.s1=-s.s1; s.s2=-s.s2; s.s3=-s.s3; return s; }
97
99 T& operator [] (int n)
100 { T* val = &s0; return val[n]; }
101
103 T operator [] (int n) const
104 { return *(&s0+n); }
105
107 T get_scalar () const { return s0; }
108
110 void set_scalar (T s) { s0 = s; }
111
113 Vector<3,T> get_vector () const
114 { Vector<3,T> ret; ret[0]=s1; ret[1]=s2; ret[2]=s3; return ret; }
115
117 template<typename U>
118 void set_vector (const Vector<3,U>& v) { s1=v[0]; s2=v[1]; s3=v[2]; }
119
121 static const Quaternion& identity();
122
124 unsigned size () const { return 4; }
125
126};
127
129template<typename T, QBasis B, typename U>
131operator + (const Quaternion<T,B>& a, const Quaternion<U,B>& b)
132{
134 ret+=b;
135 return ret;
136}
137
139template<typename T, QBasis B, typename U>
141operator - (const Quaternion<T,B>& a, const Quaternion<U,B>& b)
142{
144 ret-=b;
145 return ret;
146}
147
149
150template<typename T, QBasis B, typename U>
151const Quaternion<T,B>
152operator * (const Quaternion<T,B>& a, const U& c)
153{
155 ret*=c;
156 return ret;
157}
158
160
161template<typename T, QBasis B, typename U>
162const Quaternion<T,B>
163operator * (const U& c, const Quaternion<T,B>& a)
164{
166 ret*=c;
167 return ret;
168}
169
171template<typename T, QBasis B, typename U>
173operator / (const Quaternion<T,B>& a, const U& c)
174{
176 ret/=c;
177 return ret;
178}
179
181template<typename T, QBasis B>
183{
184 static Quaternion<T,B> I (1,0,0,0);
185 return I;
186}
187
189template<typename T, QBasis B> struct DatumTraits< Quaternion<T,B> >
190{
191 ElementTraits<T> element_traits;
192 static inline unsigned ndim () { return 4; }
193 static inline T& element (Quaternion<T,B>& t, unsigned idim)
194 { return t[idim]; }
195 static inline const T& element (const Quaternion<T,B>& t, unsigned idim)
196 { return t[idim]; }
197};
198
200template<typename T, typename U>
202 Hermitian>
203operator * (const Quaternion<std::complex<T>,Hermitian>& a,
204 const Quaternion<std::complex<U>,Hermitian>& b)
205{
206 typedef std::complex<typename PromoteTraits<T,U>::promote_type> R;
208 ( a.s0*b.s0 + a.s1*b.s1 + a.s2*b.s2 + a.s3*b.s3 ,
209 a.s0*b.s1 + a.s1*b.s0 + ci(a.s2*b.s3) - ci(a.s3*b.s2) ,
210 a.s0*b.s2 - ci(a.s1*b.s3) + a.s2*b.s0 + ci(a.s3*b.s1) ,
211 a.s0*b.s3 + ci(a.s1*b.s2) - ci(a.s2*b.s1) + a.s3*b.s0 );
212}
213
215template<typename T, typename U>
217operator * (const Quaternion<T,Unitary>& a, const Quaternion<U,Unitary>& b)
218{
220 (a.s0*b.s0 - a.s1*b.s1 - a.s2*b.s2 - a.s3*b.s3,
221 a.s0*b.s1 + a.s1*b.s0 - a.s2*b.s3 + a.s3*b.s2,
222 a.s0*b.s2 + a.s1*b.s3 + a.s2*b.s0 - a.s3*b.s1,
223 a.s0*b.s3 - a.s1*b.s2 + a.s2*b.s1 + a.s3*b.s0);
224}
225
226
228template<typename T, QBasis B>
229Quaternion<T,B> real (const Quaternion<std::complex<T>,B>& j)
230{
231 return Quaternion<T,B>
232 (j.s0.real(), j.s1.real(), j.s2.real(), j.s3.real());
233}
234
236template<typename T, QBasis B>
237Quaternion<T,B> imag (const Quaternion<std::complex<T>,B>& j)
238{
239 return Quaternion<T,B>
240 (j.s0.imag(), j.s1.imag(), j.s2.imag(), j.s3.imag());
241}
242
244template<typename T>
246{
248 (myconj(j.s0), myconj(j.s1), myconj(j.s2), -myconj(j.s3));
249}
250
252template<typename T>
254{
256 (myconj(j.s0), -myconj(j.s1), -myconj(j.s2), myconj(j.s3));
257}
258
259
261template<typename T>
263{
265 (myconj(j.s0), myconj(j.s1), myconj(j.s2), myconj(j.s3));
266}
267
268
270template<typename T>
272{
274 (myconj(j.s0), -myconj(j.s1), -myconj(j.s2), -myconj(j.s3));
275}
276
277
279template<typename T, QBasis B>
280Quaternion<T, B> inv (const Quaternion<T,B>& j)
281{
282 T d (-1.0); d/=det(j);
283 return Quaternion<T,B> (-d*j.s0, d*j.s1, d*j.s2, d*j.s3);
284}
285
286
288template<typename T>
289T det (const Quaternion<T,Hermitian>& j)
290{ return j.s0*j.s0 - j.s1*j.s1 - j.s2*j.s2 - j.s3*j.s3; }
291
293template<typename T>
294T det (const Quaternion<T,Unitary>& j)
295{ return j.s0*j.s0 + j.s1*j.s1 + j.s2*j.s2 + j.s3*j.s3; }
296
298template<typename T, QBasis B>
299T trace (const Quaternion<T,B>& j)
300{ return 2.0 * j.s0; }
301
303template<typename T, QBasis B>
304T norm (const Quaternion<std::complex<T>,B>& j)
305{ return 2.0 * (norm(j.s0) + norm(j.s1) + norm(j.s2) + norm(j.s3)); }
306
308template<typename T, QBasis B>
309T norm (const Quaternion<T,B>& j)
310{ return 2.0 * (j.s0*j.s0 + j.s1*j.s1 + j.s2*j.s2 + j.s3*j.s3); }
311
312template<typename T, QBasis B>
313T fabs (const Quaternion<T,B>& j)
314{ return sqrt (norm(j)); }
315
316// Return the positive definite square root of a Hermitian Quaternion
317template<typename T, QBasis B>
318const Quaternion<T,B> sqrt (const Quaternion<T,B>& h)
319{
320 T root_det = sqrt( det(h) );
321 T scalar = sqrt( 0.5 * (h.s0 + root_det) );
322
323 if (scalar == 0.0)
324 return Quaternion<T,B> (0.0);
325
326 return Quaternion<T,B> (scalar, h.get_vector()/(2*scalar));
327}
328
330
358
359template<typename T>
361{
362 T p = norm( q.get_vector() );
363
364 /*
365 q.s0 == 0 is a special case used by calculate_Jacobi and is required
366 for the Jacobi method to work on Hermitian matrices. Unfortunately,
367 at the moment I can't remember how I derived calculate_Jacobi for
368 Hermitian matrices and I can't update it to work in the case of
369 q.s1 < 0 ... another time ...
370
371 Willem van Straten - 30 November 2009
372 */
373 if (q.s1 < 0 && q.s0 != 0)
374 {
375 T m = 1.0 / sqrt( 2.0*p*(p-q.s1) );
376 return Quaternion<T,Unitary> (m*q.s3, -m*q.s2, -m*(p-q.s1), 0.0);
377 }
378 else
379 {
380 T m = 1.0 / sqrt( 2.0*p*(p+q.s1) );
381 return Quaternion<T,Unitary> (m*(p+q.s1), 0.0, -m*q.s3, m*q.s2);
382 }
383}
384
386template<typename T>
387std::ostream& operator<< (std::ostream& ostr, const Quaternion<T,Hermitian>& j)
388{
389 return ostr << "[h:" << j.s0 <<","<< j.s1 <<","<< j.s2 <<","<< j.s3 << "]";
390}
391
393template<typename T>
394std::ostream& operator<< (std::ostream& ostr, const Quaternion<T,Unitary>& j)
395{
396 return ostr << "[u:" << j.s0 <<","<< j.s1 <<","<< j.s2 <<","<< j.s3 << "]";
397}
398
399#endif /* not __Quaternion_H defined */
400
static const Quaternion & identity()
Definition Quaternion.h:182
bool operator!=(const Quaternion &b) const
T & operator[](int n)
unsigned size() const
const Quaternion & operator=(const Quaternion< U, B > &s)
friend const friend Quaternion operator-(Quaternion s)
const Quaternion & operator*=(const T &a)
const Quaternion & operator/=(const T &a)
Vector< 3, T > get_vector() const
void set_scalar(T s)
Quaternion(const T &a=0.0, const T &b=0.0, const T &c=0.0, const T &d=0.0)
const Quaternion & operator-=(const T &s)
T get_scalar() const
void set_vector(const Vector< 3, U > &v)
bool operator==(const Quaternion &b) const
const Quaternion & operator+=(const T &s)
E element_traits
Definition Traits.h:73

Generated using doxygen 1.14.0