cgv
Loading...
Searching...
No Matches
quaternion.h
1#pragma once
2
3// make sure this is the first thing the compiler sees, while preventing warnings if
4// it happened to already be defined by something else including this header
5#ifndef _USE_MATH_DEFINES
6 #define _USE_MATH_DEFINES 1
7#endif
8#include "fvec.h"
9#include "fmat.h"
10#include "functions.h"
11
12namespace cgv {
13 namespace math {
14
15// floating point comparison epsilon
16#define EPSILON 1e-6
17
19template <typename T>
20class quaternion : public fvec<T,4>
21{
22public:
28 typedef T coord_type;
30 enum AxisEnum { X_AXIS, Y_AXIS, Z_AXIS };
38
42 quaternion() : fvec<T,4>(T(0),T(0),T(0),T(1)) {}
46 template <typename S>
47 quaternion(const quaternion<S>& q) : fvec<T,4>(q) {}
54 quaternion(AxisEnum axis, coord_type angle) { set(axis, angle); }
56 quaternion(const vec_type& axis, coord_type angle) { set(axis, angle); }
58 template <class rot_mat_type>
59 quaternion(const rot_mat_type& matrix) { set(matrix); }
64 base_type& vec() { return *this; }
65 const base_type& vec() const { return *this; }
67
70 void set(AxisEnum axis, coord_type angle)
71 {
72 vec_type v(0,0,0);
73 v((int)axis) = 1;
74 set(v, angle);
75 }
77 void set(const vec_type& axis, coord_type angle)
78 {
79 angle *= (coord_type)0.5;
80 set(cos(angle), coord_type(sin(angle))*axis);
81 }
83 void set(const quaternion<T>& quat) { *this = quat; }
85 template <class rot_mat_type>
86 void set(const rot_mat_type &M)
87 {
88 // compile-time check that matrix layout is supported
89 static_assert(
90 (rot_mat_type::nrows() == 3 && (rot_mat_type::ncols()==3 || rot_mat_type::ncols()==4))
91 || (rot_mat_type::nrows() == 4 && rot_mat_type::ncols() == 4), "matrix layout not supported"
92 );
93
94 // convenience constant
95 constexpr typename rot_mat_type::value_type _1o4 = .25;
96
97 this->w() = sqrt((T)plus(_1o4*( M(0, 0) + M(1, 1) + M(2, 2) + 1)));
98 this->x() = sqrt((T)plus(_1o4*( M(0, 0) - M(1, 1) - M(2, 2) + 1)));
99 this->y() = sqrt((T)plus(_1o4*(-M(0, 0) + M(1, 1) - M(2, 2) + 1)));
100 this->z() = sqrt((T)plus(_1o4*(-M(0, 0) - M(1, 1) + M(2, 2) + 1)));
101 if (this->w() >= this->x() && this->w() >= this->y() && this->w() >= this->z()) {
102 this->x() *= (T)cgv::math::sign(M(2, 1) - M(1, 2));
103 this->y() *= (T)cgv::math::sign(M(0, 2) - M(2, 0));
104 this->z() *= (T)cgv::math::sign(M(1, 0) - M(0, 1));
105 }
106 else if (this->x() >= this->y() && this->x() >= this->z()) {
107 this->w() *= (T)cgv::math::sign(M(2, 1) - M(1, 2));
108 this->y() *= (T)cgv::math::sign(M(0, 1) + M(1, 0));
109 this->z() *= (T)cgv::math::sign(M(2, 0) + M(0, 2));
110 }
111 else if (this->y() >= this->z()) {
112 this->w() *= (T)cgv::math::sign(M(0, 2) - M(2, 0));
113 this->x() *= (T)cgv::math::sign(M(0, 1) + M(1, 0));
114 this->z() *= (T)cgv::math::sign(M(1, 2) + M(2, 1));
115 }
116 else {
117 this->w() *= (T)cgv::math::sign(M(1, 0) - M(0, 1));
118 this->x() *= (T)cgv::math::sign(M(0, 2) + M(2, 0));
119 this->y() *= (T)cgv::math::sign(M(1, 2) + M(2, 1));
120 }
121 }
124 {
125 this->x() = ix;
126 this->y() = iy;
127 this->z() = iz;
128 this->w() = re;
129 }
131 void set(coord_type re, const vec_type& im)
132 {
133 set(re, im.x(), im.y(), im.z());
134 }
136
139 void put_matrix(mat_type& M) const
140 {
141 M(0, 0) = 1 - 2 * this->y()*this->y() - 2 * this->z()*this->z();
142 M(0, 1) = 2 * this->x()*this->y() - 2 * this->w()*this->z();
143 M(0, 2) = 2 * this->x()*this->z() + 2 * this->w()*this->y();
144 M(1, 0) = 2 * this->x()*this->y() + 2 * this->w()*this->z();
145 M(1, 1) = 1 - 2 * this->x()*this->x() - 2 * this->z()*this->z();
146 M(1, 2) = 2 * this->y()*this->z() - 2 * this->w()*this->x();
147 M(2, 0) = 2 * this->x()*this->z() - 2 * this->w()*this->y();
148 M(2, 1) = 2 * this->y()*this->z() + 2 * this->w()*this->x();
149 M(2, 2) = 1-2*this->x()*this->x()-2*this->y()*this->y();
150 }
152 mat_type get_matrix() const { mat_type M; put_matrix(M); return M; }
155 {
156 M(0, 0) = 1 - 2 * this->y()*this->y() - 2 * this->z()*this->z();
157 M(0, 1) = 2 * this->x()*this->y() - 2 * this->w()*this->z();
158 M(0, 2) = 2 * this->x()*this->z() + 2 * this->w()*this->y();
159 M(1, 0) = 2 * this->x()*this->y() + 2 * this->w()*this->z();
160 M(1, 1) = 1 - 2 * this->x()*this->x() - 2 * this->z()*this->z();
161 M(1, 2) = 2 * this->y()*this->z() - 2 * this->w()*this->x();
162 M(2, 0) = 2 * this->x()*this->z() - 2 * this->w()*this->y();
163 M(2, 1) = 2 * this->y()*this->z() + 2 * this->w()*this->x();
164 M(2, 2) = 1 - 2 * this->x()*this->x() - 2 * this->y()*this->y();
165 M(3,0) = M(3,1) = M(3,2) = M(0,3) = M(1, 3) = M(2, 3) = M(3, 3) = 0;
166 M(3,3) = 1;
167 }
171 void set_normal(const vec_type& n)
172 {
173 coord_type cosfac = 1-n.x();
174 if (fabs(cosfac)<EPSILON)
175 set(1,0,0,0);
176 else {
177 cosfac = sqrt(cosfac);
178 coord_type sinfac = sqrt(n.y()*n.y() + n.z()*n.z());
179 static coord_type fac = (coord_type)(1/sqrt(2.0));
180 coord_type tmp = fac*cosfac/sinfac;
181 set(fac*sinfac/cosfac, 0, -n.z()*tmp, n.y()*tmp);
182 }
183 }
186 {
187 n[0] = 1-2*(this->y()*this->y()+ this->z()*this->z());
188 n[1] = 2*(this->w()*this->z() + this->x()*this->y());
189 n[2] = 2*(this->x()*this->z() - this->w()*this->y());
190 }
192 void put_image(const vec_type& preimage, vec_type& image) const
193 {
194 image = cross(im(), preimage);
195 image = dot(preimage,im())*im() + re()*(re()*preimage + (coord_type)2*image) + cross(im(),image);
196 }
198 void rotate(vec_type& v) const { vec_type tmp; put_image(v, tmp); v = tmp; }
200 vec_type get_rotated(const vec_type& v) const { vec_type tmp; put_image(v, tmp); return tmp; }
202 void rotate(mat_type& m) const
203 {
204 m.set_col(0, get_rotated(m.col(0)));
205 m.set_col(1, get_rotated(m.col(1)));
206 m.set_col(2, get_rotated(m.col(2)));
207 }
209 mat_type get_rotated(const mat_type& M) const { mat_type tmp = M; rotate(tmp); return tmp; }
211 void put_preimage(const vec_type& image, vec_type& preimage) const
212 {
213 preimage = cross(-im(), image);
214 preimage = dot(image,-im())*(-im()) + re()*(re()*image + (coord_type)2*preimage) + cross(-im(),preimage);
215 }
217 void inverse_rotate(vec_type& image) const { vec_type tmp; put_preimage(image, tmp); image = tmp; }
219 vec_type apply(const vec_type& v) const { vec_type tmp; put_image(v, tmp); return tmp; }
221
224 quaternion<T> conj() const { return quaternion<T>(re(), -im()); }
226 quaternion<T> negated() const { return quaternion<T>(-re(), -im()); }
228 void negate() { conjugate(); re() = -re(); }
230 void conjugate() { this->x() = -this->x(); this->y() = -this->y(); this->z() = -this->z(); }
232 quaternion<T> inverse() const { quaternion<T> tmp(*this); tmp.invert(); return tmp; }
234 void invert()
235 {
236 conjugate();
237 coord_type sn = this->sqr_length();
238 if (sn < EPSILON*EPSILON)
240 else
242 }
244 void affin(const quaternion<T>& p, coord_type t, const quaternion<T>& q)
245 {
246 coord_type omega, cosom, sinom, sclp, sclq;
247 *this = q*p;
248 cosom = this->sqr_length();
249 if ( ( 1 + cosom) > EPSILON ) {
250 if ( ( 1 - cosom) > EPSILON ) {
251 omega = acos( cosom );
252 sinom = sin ( omega );
253 sclp = sin ( (1-t) * omega ) / sinom;
254 sclq = sin ( t*omega ) / sinom;
255 }
256 else
257 {
258 sclp = 1 - t;
259 sclq = t;
260 }
261 set(sclp*p.w() + sclq*q.w(), sclp*p.x() + sclq*q.x(), sclp*p.y() + sclq*q.y(), sclp*p.z() + sclq*q.z());
262 }
263 else {
264 sclp = (T)sin ( (1-t)*M_PI/2 );
265 sclq = (T)sin ( t * M_PI/2 );
266 set(p.z(), sclp*p.x() - sclq*p.y(), sclp*p.y() + sclq*p.x(), sclp*p.z() - sclq*p.w());
267 }
268 }
270 void affin(coord_type s, const quaternion<T>& q) { quaternion<T> tmp; tmp.affin(*this, s, q); *this = tmp; }
272 quaternion<T> operator - () const { return negated(); }
275 {
276 // Fastmul-Alg. siehe Seidel-Paper p.4
277 coord_type s[9], t;
278 s[0] = (this->z()-this->y())*(q.y()-q.z());
279 s[1] = (this->w()+this->x())*(q.w()+q.x());
280 s[2] = (this->w()-this->x())*(q.y()+q.z());
281 s[3] = (this->z()+this->y())*(q.w()-q.x());
282 s[4] = (this->z()-this->x())*(q.x()-q.y());
283 s[5] = (this->z()+this->x())*(q.x()+q.y());
284 s[6] = (this->w()+this->y())*(q.w()-q.z());
285 s[7] = (this->w()-this->y())*(q.w()+q.z());
286 s[8] = s[5]+s[6]+s[7];
287 t = (s[4] +s[8])/2;
288 set(s[0]+t-s[5], s[1]+t-s[8], s[2]+t-s[7], s[3]+t-s[6]);
289 return *this;
290 }
292 quaternion<T> operator * (const quaternion<T>& q) const { quaternion<T> tmp(*this); tmp*=q; return tmp; }
294 quaternion<T>& operator *= (const T& s) { for (unsigned i=0;i<4;++i) this->v[i] *= s; return *this; }
296 quaternion<T> operator * (const T& s) const { quaternion<T> r = *this; r *= s; return r; }
298
301 coord_type re() const { return this->w(); }
303 coord_type& re() { return this->w(); }
305 void put_im(vec_type& vector) const { vector.x() = this->x(); vector.y() = this->y(); vector.z() = this->z(); }
307 vec_type im() const { return vec_type(this->x(),this->y(),this->z()); }
309 coord_type put_axis(vec_type& v) const
310 {
311 if (re() > 1) {
312 quaternion<T> q(*this);
313 q.normalize();
314 return q.put_axis(v);
315 }
316 coord_type angle = 2 * acos(re());
317 coord_type s = sqrt(1 - re()*re());
318 if (s < (coord_type)EPSILON) {
319 v = vec_type(0,0,1);
320 return 0;
321 }
322 v = im()/s;
323/* if (2*angle > M_PI) {
324 angle -= (coord_type)(2*M_PI);
325 v = -v;
326 }*/
327 return angle;
328 }
331 {
332 T m = im().length();
333 quaternion<T> quat(cos(m), im()*(sin(m) / m));
334 (typename quaternion<T>::base_type&) quat *= exp(re());
335 return quat;
336 }
339 {
340 T R = this->length();
341 typename quaternion<T>::vec_type v(im());
342 T sinTimesR = v.length();
343 if (sinTimesR < EPSILON)
344 v /= sinTimesR;
345 else {
346 v = typename quaternion<T>::vec_type(0, 0, 0);
347 sinTimesR = 0;
348 }
349 return quaternion<T>(::log(R), atan2(sinTimesR, re()*v));
350 }
352};
353
355#define CGV_MATH_QUATERNION_DECLARED
356
358template <typename T>
359quaternion<T> operator * (const T& s, const quaternion<T>& v)
360{
361 quaternion<T> r = v; r *= s; return r;
362}
363
364} // namespace math
365
368
373
375
376}// namespace cgv
matrix of fixed size dimensions
Definition fmat.h:23
fvec< T, N > & col(unsigned j)
reference a column of the matrix as a vector
Definition fmat.h:209
void set_col(unsigned j, const fvec< T, N > &v)
set column j of the matrix to vector v
Definition fmat.h:217
A vector with zero based index.
Definition fvec.h:26
T & z()
third element
Definition fvec.h:163
T & y()
second element
Definition fvec.h:159
T normalize()
normalize the vector using the L2-Norm and return the length
Definition fvec.h:302
fvec< T, N > & operator*=(const T &s)
in place multiplication with s
Definition fvec.h:193
fvec< T, N > & operator/=(const T &s)
in place division by scalar s
Definition fvec.h:195
T sqr_length() const
square length of vector
Definition fvec.h:294
T length() const
length of the vector L2-Norm
Definition fvec.h:249
fvec & operator=(const fvec< T, N > &rhs)
assign vector rhs, if vector and rhs have different sizes, vector has been resized to match the size ...
Definition fvec.h:119
T & x()
first element
Definition fvec.h:155
T & w()
fourth element
Definition fvec.h:167
implements a quaternion.
Definition quaternion.h:21
vec_type im() const
return this as vector
Definition quaternion.h:307
quaternion(const vec_type &axis, coord_type angle)
construct quaternion from axis and rotation angle
Definition quaternion.h:56
quaternion< T > & operator=(const quaternion< T > &quat)
assignement operator
Definition quaternion.h:49
quaternion(const rot_mat_type &matrix)
construct quaternion from 3x3 rotation or rotational part of homogeneous 3x4 / 4x4 matrix
Definition quaternion.h:59
void put_im(vec_type &vector) const
put imaginary part
Definition quaternion.h:305
T coord_type
coordinate type
Definition quaternion.h:28
fvec< T, 3 > vec_type
type of 3d axis
Definition quaternion.h:32
vec_type get_rotated(const vec_type &v) const
return rotated vector
Definition quaternion.h:200
quaternion(AxisEnum axis, coord_type angle)
construct quaternion from coordinate axis and rotation angle
Definition quaternion.h:54
coord_type re() const
return real part
Definition quaternion.h:301
quaternion< T > operator-() const
negation operator
Definition quaternion.h:272
void put_normal(coord_type *n)
extract normal vector
Definition quaternion.h:185
void inverse_rotate(vec_type &image) const
rotate vector according to the inverse quaternion
Definition quaternion.h:217
quaternion(const quaternion< S > &q)
copy constructor with type conversion
Definition quaternion.h:47
void put_image(const vec_type &preimage, vec_type &image) const
rotate preimage according to quaternion into image
Definition quaternion.h:192
quaternion< T > exp() const
exponential map
Definition quaternion.h:330
coord_type & re()
return reference to real part
Definition quaternion.h:303
void rotate(mat_type &m) const
Rotate a frame according to quaternion.
Definition quaternion.h:202
void affin(coord_type s, const quaternion< T > &q)
compute affin combination with angular interpolation
Definition quaternion.h:270
void set(const rot_mat_type &M)
set quaternion from 3x3 rotation or rotational part of homogeneous 3x4 / 4x4 matrix
Definition quaternion.h:86
coord_type put_axis(vec_type &v) const
put rotation axis and return rotation angle
Definition quaternion.h:309
void set(coord_type re, const vec_type &im)
set quaternion from real part and vector
Definition quaternion.h:131
fmat< T, 3, 3 > mat_type
type of 3x3 matrix
Definition quaternion.h:34
quaternion< T > & operator*=(const quaternion< T > &q)
field multiplication
Definition quaternion.h:274
hmat_type get_homogeneous_matrix() const
return equivalent 4x4 rotation matrix
Definition quaternion.h:169
void conjugate()
compute conjugate
Definition quaternion.h:230
quaternion(coord_type re, const vec_type &im)
construct quaternion from real part and vector
Definition quaternion.h:63
void set(AxisEnum axis, coord_type angle)
set quaternion from coordinate axis and rotation angle
Definition quaternion.h:70
fmat< T, 4, 4 > hmat_type
type of 4x4 matrix
Definition quaternion.h:36
void set_normal(const vec_type &n)
initialize quaternion from normal vector
Definition quaternion.h:171
mat_type get_matrix() const
return equivalent 3x3 rotation matrix
Definition quaternion.h:152
mat_type get_rotated(const mat_type &M) const
Rotate source frame s into destination frame d.
Definition quaternion.h:209
quaternion< T > inverse() const
return the inverse
Definition quaternion.h:232
vec_type apply(const vec_type &v) const
rotate vector according to quaternion
Definition quaternion.h:219
void affin(const quaternion< T > &p, coord_type t, const quaternion< T > &q)
compute affin combination with angular interpolation
Definition quaternion.h:244
quaternion< T > log() const
logarithmic map
Definition quaternion.h:338
void put_preimage(const vec_type &image, vec_type &preimage) const
rotate image according to quaternion into preimage
Definition quaternion.h:211
void set(coord_type re, coord_type ix, coord_type iy, coord_type iz)
set quaternion directly
Definition quaternion.h:123
AxisEnum
enumeration of the three coordinate axes
Definition quaternion.h:30
quaternion(const quaternion< T > &quat)
copy constructor
Definition quaternion.h:44
quaternion< T > conj() const
return the conjugate
Definition quaternion.h:224
void rotate(vec_type &v) const
rotate vector according to quaternion
Definition quaternion.h:198
quaternion< T > operator*(const quaternion< T > &q) const
field multiplication
Definition quaternion.h:292
void invert()
compute inverse
Definition quaternion.h:234
fvec< T, 4 > base_type
base class type
Definition quaternion.h:26
void set(const quaternion< T > &quat)
setter from quaternion
Definition quaternion.h:83
void put_homogeneous_matrix(hmat_type &M) const
compute equivalent homogeneous 4x4 rotation matrix
Definition quaternion.h:154
quaternion< T > negated() const
return the negated quaternion
Definition quaternion.h:226
void set(const vec_type &axis, coord_type angle)
set quaternion from axis and rotation angle
Definition quaternion.h:77
void put_matrix(mat_type &M) const
compute equivalent 3x3 rotation matrix
Definition quaternion.h:139
quaternion(coord_type w, coord_type x, coord_type y, coord_type z)
construct quaternion directly
Definition quaternion.h:61
quaternion()
standard constructor initializes to unit quaternion
Definition quaternion.h:42
void negate()
negate the quaternion
Definition quaternion.h:228
A column vector class.
Definition vec.h:28
the cgv namespace
Definition print.h:11
cgv::math::quaternion< double > dquat
declare type of double quaternion
Definition quaternion.h:372
cgv::math::quaternion< float > quat
declare type of quaternion
Definition quaternion.h:370