gKit2 light
Loading...
Searching...
No Matches
quaternion.h
1/****************************************************************************
2Copyright (C) 2010-2020 Alexandre Meyer
3
4This file is part of library.
5
6gkit2light is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
10
11gkit2light is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with gkit2light. If not, see <http://www.gnu.org/licenses/>.
18*****************************************************************************/
19
20#ifndef _QUATERNION_H
21#define _QUATERNION_H
22
23
24#ifndef _USE_MATH_DEFINES
25#define _USE_MATH_DEFINES
26#endif
27#include <cmath>
28#include <iostream>
29#include <cstdlib>
30
31
35 template<typename Real, typename Vec3Real>
37 {
38 public:
41
43 { q[0]=q[1]=q[2]=0.0; q[3]=1.0; }
44
46 TQuaternion(const Vec3Real& axis, const Real angle)
47 {
48 setAxisAngle(axis, angle);
49 }
50
51 TQuaternion(const Vec3Real& from, const Vec3Real& to)
52 {
53 const Real epsilon = 1E-10f;
54
55 const Real fromSqNorm = from.squaredNorm();
56 const Real toSqNorm = to.squaredNorm();
57 // Identity TQuaternion when one vector is null
58 if ((fromSqNorm < epsilon) || (toSqNorm < epsilon))
59 {
60 q[0]=q[1]=q[2]=0.0;
61 q[3]=1.0;
62 }
63 else
64 {
65 Vec3Real axis = cross(from, to);
66 const Real axisSqNorm = axis.squaredNorm();
67
68 // Aligned vectors, pick any axis, not aligned with from or to
69 if (axisSqNorm < epsilon)
70 {
71 axis = Vec3Real(1.0, 0.0, 0.0);
72 if (axis*from < 0.1*sqrt(fromSqNorm))
73 axis = Vec3Real(0.0, 1.0, 0.0);
74 }
75
76 Real angle = asin(sqrt(axisSqNorm / (fromSqNorm * toSqNorm)));
77
78 if (from*to < 0.0)
79 angle = M_PI-angle;
80
81 setAxisAngle(axis, angle);
82 }
83 }
84
85
90 TQuaternion(Real q0, Real q1, Real q2, Real q3)
91 { q[0]=q0; q[1]=q1; q[2]=q2; q[3]=q3; }
92
95 { for (int i=0; i<4; ++i) q[i] = Q.q[i]; }
96
99 {
100 for (int i=0; i<4; ++i)
101 q[i] = Q.q[i];
102 return (*this);
103 }
104
105 TQuaternion& operator+=(const TQuaternion& Q)
106 {
107 for (int i = 0; i < 4; ++i)
108 q[i] += Q.q[i];
109 return (*this);
110 }
111
112
116 void setAxisAngle(const Vec3Real& axis, const Real angle)
117 {
118 const Real norm = length(axis); // axis.norm();
119 if (norm < 1E-8)
120 {
121 // Null rotation
122 q[0] = 0.0;
123 q[1] = 0.0;
124 q[2] = 0.0;
125 q[3] = 1.0;
126 }
127 else
128 {
129 const Real sin_half_angle = sin(angle / 2.0);
130 q[0] = sin_half_angle*axis.x/norm;
131 q[1] = sin_half_angle*axis.y/norm;
132 q[2] = sin_half_angle*axis.z/norm;
133 q[3] = cos(angle / 2.0);
134 }
135 }
136
138 void setValue(Real q0, Real q1, Real q2, Real q3)
139 { q[0]=q0; q[1]=q1; q[2]=q2; q[3]=q3; }
140
141
142 template<typename MAT>
143 void setFromRotationMatrix(const MAT& m)
144 {
145 // First, find largest diagonal in matrix:
146 int i = 2;
147 if (m[0][0] > m[1][1])
148 {
149 if (m[0][0] > m[2][2])
150 {
151 i = 0;
152 }
153 }
154 else
155 {
156 if (m[1][1] > m[2][2])
157 {
158 i = 1;
159 }
160 }
161
162 if (m[0][0]+m[1][1]+m[2][2] > m[i][i])
163 {
164 // Compute w first:
165 q[3] = sqrt(m[0][0]+m[1][1]+m[2][2]+1.0)/2.0;
166 // And compute other values:
167 q[0] = (m[2][1]-m[1][2])/(4.0*q[3]);
168 q[1] = (m[0][2]-m[2][0])/(4.0*q[3]);
169 q[2] = (m[1][0]-m[0][1])/(4.0*q[3]);
170 }
171 else
172 {
173 // Compute x, y, or z first:
174 int j = (i+1)%3;
175 int k = (i+2)%3;
176
177 // Compute first value:
178 q[i] = sqrt(m[i][i]-m[j][j]-m[k][k]+1.0)/2.0;
179
180 // And the others:
181 q[j] = (m[i][j]+m[j][i])/(4.0*q[i]);
182 q[k] = (m[i][k]+m[k][i])/(4.0*q[i]);
183
184 q[3] = (m[k][j]-m[j][k])/(4.0*q[i]);
185 }
186 }
187
188 void setFromRotatedBase(const Vec3Real& X, const Vec3Real& Y, const Vec3Real& Z)
189 {
190 Real m[3][3];
191 Real normX = X.norm();
192 Real normY = Y.norm();
193 Real normZ = Z.norm();
194
195 for (int i=0; i<3; ++i)
196 {
197 m[i][0] = X[i] / normX;
198 m[i][1] = Y[i] / normY;
199 m[i][2] = Z[i] / normZ;
200 }
201 setFromRotationMatrix(m);
202 }
203
205
206
209 Vec3Real axis() const
210 {
211 Vec3Real res = Vec3Real(q[0], q[1], q[2]);
212 const Real sinus = res.norm();
213 if (sinus > 1E-8)
214 res /= sinus;
215 return (acos(q[3]) <= M_PI/2.0) ? res : -res;
216 }
217
218
219 Real angle() const
220 {
221 const Real angle = 2.0 * acos(q[3]);
222 return (angle <= M_PI) ? angle : 2.0*M_PI - angle;
223 }
224
225
226 void getAxisAngle(Vec3Real& axis, Real& angle) const
227 {
228 angle = 2.0*acos(q[3]);
229 axis = Vec3Real(q[0], q[1], q[2]);
230 const Real sinus = axis.norm();
231 if (sinus > 1E-8)
232 axis /= sinus;
233
234 if (angle > M_PI)
235 {
236 angle = 2.0*M_PI - angle;
237 axis = -axis;
238 }
239 }
240
241
243 Real operator[](int i) const { return q[i]; }
244
246 Real& operator[](int i) { return q[i]; }
248
249
250
252 friend TQuaternion operator*(const Real a, const TQuaternion& b)
253 {
254 return TQuaternion<Real,Vec3Real>(a*b[0],a*b[1],a*b[2],a*b[3]);
255 }
256
257
260
268 friend TQuaternion operator*(const TQuaternion& a, const TQuaternion& b)
269 {
270 return TQuaternion(a.q[3]*b.q[0] + b.q[3]*a.q[0] + a.q[1]*b.q[2] - a.q[2]*b.q[1],
271 a.q[3]*b.q[1] + b.q[3]*a.q[1] + a.q[2]*b.q[0] - a.q[0]*b.q[2],
272 a.q[3]*b.q[2] + b.q[3]*a.q[2] + a.q[0]*b.q[1] - a.q[1]*b.q[0],
273 a.q[3]*b.q[3] - b.q[0]*a.q[0] - a.q[1]*b.q[1] - a.q[2]*b.q[2]);
274 }
275
283 {
284 *this = (*this)*q;
285 return *this;
286 }
287
291 friend Vec3Real operator*(const TQuaternion& q, const Vec3Real& v)
292 {
293 return q.rotate(v);
294 }
295
296
297
298 Vec3Real rotate(const Vec3Real& v) const
299 {
300 const Real q00 = 2.0l * q[0] * q[0];
301 const Real q11 = 2.0l * q[1] * q[1];
302 const Real q22 = 2.0l * q[2] * q[2];
303
304 const Real q01 = 2.0l * q[0] * q[1];
305 const Real q02 = 2.0l * q[0] * q[2];
306 const Real q03 = 2.0l * q[0] * q[3];
307
308 const Real q12 = 2.0l * q[1] * q[2];
309 const Real q13 = 2.0l * q[1] * q[3];
310
311 const Real q23 = 2.0l * q[2] * q[3];
312
313 return Vec3Real((1.0 - q11 - q22)*v.x + ( q01 - q23)*v.y + ( q02 + q13)*v.z,
314 ( q01 + q23)*v.x + (1.0 - q22 - q00)*v.y + ( q12 - q03)*v.z,
315 ( q02 - q13)*v.x + ( q12 + q03)*v.y + (1.0 - q11 - q00)*v.z );
316 }
317
318
319 Vec3Real inverseRotate(const Vec3Real& v) const
320 {
321 return inverse().rotate(v);
322 }
323
324
325
327
328
331
337 TQuaternion inverse() const { return TQuaternion(-q[0], -q[1], -q[2], q[3]); }
338
342 void invert() { q[0] = -q[0]; q[1] = -q[1]; q[2] = -q[2]; }
343
352 void negate() { invert(); q[3] = -q[3]; }
353
359 {
360 const Real norm = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
361 for (int i=0; i<4; ++i)
362 q[i] /= norm;
363 return norm;
364 }
365
366
367
370
381 const Real* matrix() const
382 {
383 static Real m[4][4];
384 getMatrix44(m);
385 return (const Real*)(m);
386 }
387
388
393 //void getMatrix(Real m[4][4]) const
394 template<typename MAT>
395 void getMatrix44(MAT& m) const
396 {
397 const Real q00 = 2.0l * q[0] * q[0];
398 const Real q11 = 2.0l * q[1] * q[1];
399 const Real q22 = 2.0l * q[2] * q[2];
400
401 const Real q01 = 2.0l * q[0] * q[1];
402 const Real q02 = 2.0l * q[0] * q[2];
403 const Real q03 = 2.0l * q[0] * q[3];
404
405 const Real q12 = 2.0l * q[1] * q[2];
406 const Real q13 = 2.0l * q[1] * q[3];
407
408 const Real q23 = 2.0l * q[2] * q[3];
409
410 m[0][0] = 1.0l - q11 - q22;
411 m[1][0] = q01 - q23;
412 m[2][0] = q02 + q13;
413
414 m[0][1] = q01 + q23;
415 m[1][1] = 1.0l - q22 - q00;
416 m[2][1] = q12 - q03;
417
418 m[0][2] = q02 - q13;
419 m[1][2] = q12 + q03;
420 m[2][2] = 1.0l - q11 - q00;
421
422 m[0][3] = 0.0l;
423 m[1][3] = 0.0l;
424 m[2][3] = 0.0l;
425
426 m[3][0] = 0.0l;
427 m[3][1] = 0.0l;
428 m[3][2] = 0.0l;
429 m[3][3] = 1.0l;
430 }
431
436 //void getMatrix(Real m[4][4]) const
437 template<typename MAT>
438 void getMatrix33(MAT& m) const
439 {
440 const Real q00 = 2.0l * q[0] * q[0];
441 const Real q11 = 2.0l * q[1] * q[1];
442 const Real q22 = 2.0l * q[2] * q[2];
443
444 const Real q01 = 2.0l * q[0] * q[1];
445 const Real q02 = 2.0l * q[0] * q[2];
446 const Real q03 = 2.0l * q[0] * q[3];
447
448 const Real q12 = 2.0l * q[1] * q[2];
449 const Real q13 = 2.0l * q[1] * q[3];
450
451 const Real q23 = 2.0l * q[2] * q[3];
452
453 m[0][0] = 1.0l - q11 - q22;
454 m[1][0] = q01 - q23;
455 m[2][0] = q02 + q13;
456
457 m[0][1] = q01 + q23;
458 m[1][1] = 1.0l - q22 - q00;
459 m[2][1] = q12 - q03;
460
461 m[0][2] = q02 - q13;
462 m[1][2] = q12 + q03;
463 m[2][2] = 1.0l - q11 - q00;
464 }
465
466 void getMatrix16(Real m[16]) const
467 {
468 static Real mat[4][4];
469 getMatrix44(mat);
470 int count = 0;
471 for (int i=0; i<4; ++i)
472 for (int j=0; j<4; ++j)
473 m[count++] = mat[i][j];
474 }
475
476
481 void getRotationMatrix(Real m[3][3]) const
482 {
483 static Real mat[4][4];
484 getMatrix(mat);
485 for (int i=0; i<3; ++i)
486 for (int j=0; j<3; ++j)
487 // Beware of transposition
488 m[i][j] = mat[j][i];
489 }
490
497 const Real* inverseMatrix() const
498 {
499 static Real m[4][4];
501 return (const Real*)(m);
502 }
503
508 void getInverseMatrix(Real m[4][4]) const
509 {
510 inverse().getMatrix(m);
511 }
512
513
514 void getInverseMatrix(Real m[16]) const
515 {
516 inverse().getMatrix(m);
517 }
518
519
524 void getInverseRotationMatrix(Real m[3][3]) const
525 {
526 static Real mat[4][4];
527 getInverseMatrix(mat);
528 for (int i=0; i<3; ++i)
529 for (int j=0; j<3; ++j)
530 // Beware of transposition
531 m[i][j] = mat[j][i];
532 }
533
534
535
538 static TQuaternion slerp(const TQuaternion& a, const TQuaternion& b, Real t, bool allowFlip=true)
539 {
540 Real cosAngle = TQuaternion::dot(a, b);
541
542 Real c1, c2;
543 // Linear interpolation for close orientations
544 if ((1.0 - fabs(cosAngle)) < 0.01)
545 {
546 c1 = 1.0 - t;
547 c2 = t;
548 }
549 else
550 {
551 // Spherical interpolation
552 Real angle = acos(fabs(cosAngle));
553 Real sinAngle = sin(angle);
554 c1 = sin(angle * (1.0 - t)) / sinAngle;
555 c2 = sin(angle * t) / sinAngle;
556 }
557
558 // Use the shortest path
559 if (allowFlip && (cosAngle < 0.0))
560 c1 = -c1;
561
562 return TQuaternion(c1*a[0] + c2*b[0], c1*a[1] + c2*b[1], c1*a[2] + c2*b[2], c1*a[3] + c2*b[3]);
563 }
564
565
566 static TQuaternion squad(const TQuaternion& a, const TQuaternion& tgA, const TQuaternion& tgB, const TQuaternion& b, Real t)
567 {
568 TQuaternion ab = TQuaternion::slerp(a, b, t);
569 TQuaternion tg = TQuaternion::slerp(tgA, tgB, t, false);
570 return TQuaternion::slerp(ab, tg, 2.0*t*(1.0-t), false);
571 }
572
573
574
576 static Real dot(const TQuaternion& a, const TQuaternion& b) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3]; }
577
578 TQuaternion log()
579 {
580 Real len = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2]);
581
582 if (len < 1E-6)
583 return TQuaternion(q[0], q[1], q[2], 0.0);
584 else
585 {
586 Real coef = acos(q[3]) / len;
587 return TQuaternion(q[0]*coef, q[1]*coef, q[2]*coef, 0.0);
588 }
589 }
590
591
592 TQuaternion exp()
593 {
594 Real theta = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2]);
595
596 if (theta < 1E-6)
597 return TQuaternion(q[0], q[1], q[2], cos(theta));
598 else
599 {
600 Real coef = sin(theta) / theta;
601 return TQuaternion(q[0]*coef, q[1]*coef, q[2]*coef, cos(theta));
602 }
603 }
604
605
606 static TQuaternion lnDif(const TQuaternion& a, const TQuaternion& b)
607 {
608 TQuaternion dif = a.inverse()*b;
609 dif.normalize();
610 return dif.log();
611 }
612
613
614 static TQuaternion squadTangent(const TQuaternion& before, const TQuaternion& center, const TQuaternion& after)
615 {
616 TQuaternion l1 = TQuaternion::lnDif(center,before);
617 TQuaternion l2 = TQuaternion::lnDif(center,after);
618 TQuaternion e;
619 for (int i=0; i<4; ++i)
620 e.q[i] = -0.25 * (l1.q[i] + l2.q[i]);
621 e = center*(e.exp());
622
623 // if (TQuaternion::dot(e,b) < 0.0)
624 // e.negate();
625
626 return e;
627 }
629
632 static TQuaternion randomQuaternion()
633 {
634 // The rand() function is not very portable and may not be available on your system.
635 // Add the appropriate include or replace by an other random function in case of problem.
636 Real seed = rand()/(Real)RAND_MAX;
637 Real r1 = sqrt(1.0 - seed);
638 Real r2 = sqrt(seed);
639 Real t1 = 2.0 * M_PI * (rand()/(Real)RAND_MAX);
640 Real t2 = 2.0 * M_PI * (rand()/(Real)RAND_MAX);
641 return TQuaternion(sin(t1)*r1, cos(t1)*r1, sin(t2)*r2, cos(t2)*r2);
642 }
644
647 //~ explicit TQuaternion(const QDomElement& element);
648 //~ QDomElement domElement(const QString& name, QDomDocument& document) const;
649 //~ void initFromDOMElement(const QDomElement& element);
651
652 #ifdef DOXYN
655
660 inline std::ostream& operator<<(std::ostream& o, const qglviewer::Vec&);
662 #endif
663
664 //template<typename C>
665 friend inline std::ostream& operator<<(std::ostream& o, const TQuaternion& Q)
666 {
667 o << "(" << Q[0] << ',' << Q[1] << ',' << Q[2] << ',' << Q[3] << ")";
668 return o;
669 }
670
671
672 private:
674 Real q[4];
675 };
676
677 typedef TQuaternion<float, Vector> Quaternion;
678 //typedef TQuaternion<double, Vector> Quaterniond;
679
680
681
682
683#endif // _QUATERNION_H
684
A Quaternion class.
Definition quaternion.h:37
void negate()
Definition quaternion.h:352
void getInverseMatrix(Real m[4][4]) const
Definition quaternion.h:508
Real operator[](int i) const
Definition quaternion.h:243
TQuaternion(const TQuaternion &Q)
Definition quaternion.h:94
void getMatrix33(MAT &m) const
Definition quaternion.h:438
void setAxisAngle(const Vec3Real &axis, const Real angle)
Definition quaternion.h:116
static Real dot(const TQuaternion &a, const TQuaternion &b)
Definition quaternion.h:576
Real normalize()
Definition quaternion.h:358
friend Vec3Real operator*(const TQuaternion &q, const Vec3Real &v)
Definition quaternion.h:291
const Real * matrix() const
Definition quaternion.h:381
friend TQuaternion operator*(const TQuaternion &a, const TQuaternion &b)
Definition quaternion.h:268
void getRotationMatrix(Real m[3][3]) const
Definition quaternion.h:481
void getMatrix44(MAT &m) const
Definition quaternion.h:395
TQuaternion inverse() const
Definition quaternion.h:337
TQuaternion(Real q0, Real q1, Real q2, Real q3)
Definition quaternion.h:90
void invert()
Definition quaternion.h:342
TQuaternion & operator=(const TQuaternion &Q)
Definition quaternion.h:98
Real & operator[](int i)
Definition quaternion.h:246
TQuaternion & operator*=(const TQuaternion &q)
Definition quaternion.h:282
friend TQuaternion operator*(const Real a, const TQuaternion &b)
Definition quaternion.h:252
const Real * inverseMatrix() const
Definition quaternion.h:497
TQuaternion(const Vec3Real &axis, const Real angle)
Definition quaternion.h:46
void setValue(Real q0, Real q1, Real q2, Real q3)
Definition quaternion.h:138
void getInverseRotationMatrix(Real m[3][3]) const
Definition quaternion.h:524
Point center(const Point &a, const Point &b)
renvoie le milieu du segment ab.
Definition vec.cpp:24
Vector cross(const Vector &u, const Vector &v)
renvoie le produit vectoriel de 2 vecteurs.
Definition vec.cpp:173