GCC Code Coverage Report


Directory: ./
File: openvdb/openvdb/math/Quat.h
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 80 113 70.8%
Functions: 11 14 78.6%
Branches: 36 127 28.3%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 #ifndef OPENVDB_MATH_QUAT_H_HAS_BEEN_INCLUDED
5 #define OPENVDB_MATH_QUAT_H_HAS_BEEN_INCLUDED
6
7 #include "Mat.h"
8 #include "Mat3.h"
9 #include "Math.h"
10 #include "Vec3.h"
11 #include <openvdb/Exceptions.h>
12 #include <cmath>
13 #include <iostream>
14 #include <sstream>
15 #include <string>
16
17
18 namespace openvdb {
19 OPENVDB_USE_VERSION_NAMESPACE
20 namespace OPENVDB_VERSION_NAME {
21 namespace math {
22
23 template<typename T> class Quat;
24
25 /// Linear interpolation between the two quaternions
26 template <typename T>
27 Quat<T> slerp(const Quat<T> &q1, const Quat<T> &q2, T t, T tolerance=0.00001)
28 {
29 T qdot, angle, sineAngle;
30
31 qdot = q1.dot(q2);
32
33 if (fabs(qdot) >= 1.0) {
34 angle = 0; // not necessary but suppresses compiler warning
35 sineAngle = 0;
36 } else {
37 angle = acos(qdot);
38 sineAngle = sin(angle);
39 }
40
41 //
42 // Denominator close to 0 corresponds to the case where the
43 // two quaternions are close to the same rotation. In this
44 // case linear interpolation is used but we normalize to
45 // guarantee unit length
46 //
47 if (sineAngle <= tolerance) {
48 T s = 1.0 - t;
49
50 Quat<T> qtemp(s * q1[0] + t * q2[0], s * q1[1] + t * q2[1],
51 s * q1[2] + t * q2[2], s * q1[3] + t * q2[3]);
52 //
53 // Check the case where two close to antipodal quaternions were
54 // blended resulting in a nearly zero result which can happen,
55 // for example, if t is close to 0.5. In this case it is not safe
56 // to project back onto the sphere.
57 //
58 double lengthSquared = qtemp.dot(qtemp);
59
60 if (lengthSquared <= tolerance * tolerance) {
61 qtemp = (t < 0.5) ? q1 : q2;
62 } else {
63 qtemp *= 1.0 / sqrt(lengthSquared);
64 }
65 return qtemp;
66 } else {
67
68 T sine = 1.0 / sineAngle;
69 T a = sin((1.0 - t) * angle) * sine;
70 T b = sin(t * angle) * sine;
71 return Quat<T>(a * q1[0] + b * q2[0], a * q1[1] + b * q2[1],
72 a * q1[2] + b * q2[2], a * q1[3] + b * q2[3]);
73 }
74
75 }
76
77 template<typename T>
78 class Quat
79 {
80 public:
81 using value_type = T;
82 using ValueType = T;
83 static const int size = 4;
84
85 /// Trivial constructor, the quaternion is NOT initialized
86 #if OPENVDB_ABI_VERSION_NUMBER >= 8
87 /// @note destructor, copy constructor, assignment operator and
88 /// move constructor are left to be defined by the compiler (default)
89 Quat() = default;
90 #else
91 Quat() {}
92
93 /// Copy constructor
94 Quat(const Quat &q)
95 {
96 mm[0] = q.mm[0];
97 mm[1] = q.mm[1];
98 mm[2] = q.mm[2];
99 mm[3] = q.mm[3];
100
101 }
102
103 /// Assignment operator
104 Quat& operator=(const Quat &q)
105 {
106 mm[0] = q.mm[0];
107 mm[1] = q.mm[1];
108 mm[2] = q.mm[2];
109 mm[3] = q.mm[3];
110
111 return *this;
112 }
113 #endif
114
115 /// Constructor with four arguments, e.g. Quatf q(1,2,3,4);
116 665 Quat(T x, T y, T z, T w)
117 {
118 665 mm[0] = x;
119 665 mm[1] = y;
120 665 mm[2] = z;
121
8/17
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 1 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 21 not taken.
✓ Branch 23 taken 1 times.
✗ Branch 24 not taken.
10 mm[3] = w;
122
123 }
124
125 /// Constructor with array argument, e.g. float a[4]; Quatf q(a);
126 Quat(T *a)
127 {
128 mm[0] = a[0];
129 mm[1] = a[1];
130 mm[2] = a[2];
131 mm[3] = a[3];
132
133 }
134
135 /// Constructor given rotation as axis and angle, the axis must be
136 /// unit vector
137 1 Quat(const Vec3<T> &axis, T angle)
138 {
139 // assert( REL_EQ(axis.length(), 1.) );
140
141 1 T s = T(sin(angle*T(0.5)));
142
143 1 mm[0] = axis.x() * s;
144 1 mm[1] = axis.y() * s;
145 1 mm[2] = axis.z() * s;
146
147 1 mm[3] = T(cos(angle*T(0.5)));
148
149 1 }
150
151 /// Constructor given rotation as axis and angle
152 1 Quat(math::Axis axis, T angle)
153 {
154 T s = T(sin(angle*T(0.5)));
155
156 1 mm[0] = (axis==math::X_AXIS) * s;
157 1 mm[1] = (axis==math::Y_AXIS) * s;
158 1 mm[2] = (axis==math::Z_AXIS) * s;
159
160 1 mm[3] = T(cos(angle*T(0.5)));
161 }
162
163 /// Constructor given a rotation matrix
164 template<typename T1>
165 3 Quat(const Mat3<T1> &rot) {
166
167 // verify that the matrix is really a rotation
168
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if(!isUnitary(rot)) { // unitary is reflection or rotation
169 OPENVDB_THROW(ArithmeticError,
170 "A non-rotation matrix can not be used to construct a quaternion");
171 }
172
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!isApproxEqual(rot.det(), T1(1))) { // rule out reflection
173 OPENVDB_THROW(ArithmeticError,
174 "A reflection matrix can not be used to construct a quaternion");
175 }
176
177 T trace(rot.trace());
178
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (trace > 0) {
179
180 T q_w = 0.5 * std::sqrt(trace+1);
181 T factor = 0.25 / q_w;
182
183 mm[0] = factor * (rot(1,2) - rot(2,1));
184 mm[1] = factor * (rot(2,0) - rot(0,2));
185 mm[2] = factor * (rot(0,1) - rot(1,0));
186 mm[3] = q_w;
187
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 } else if (rot(0,0) > rot(1,1) && rot(0,0) > rot(2,2)) {
188
189 T q_x = 0.5 * sqrt(rot(0,0)- rot(1,1)-rot(2,2)+1);
190 T factor = 0.25 / q_x;
191
192 mm[0] = q_x;
193 mm[1] = factor * (rot(0,1) + rot(1,0));
194 mm[2] = factor * (rot(2,0) + rot(0,2));
195 mm[3] = factor * (rot(1,2) - rot(2,1));
196
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 } else if (rot(1,1) > rot(2,2)) {
197
198 T q_y = 0.5 * sqrt(rot(1,1)-rot(0,0)-rot(2,2)+1);
199 T factor = 0.25 / q_y;
200
201 mm[0] = factor * (rot(0,1) + rot(1,0));
202 mm[1] = q_y;
203 mm[2] = factor * (rot(1,2) + rot(2,1));
204 mm[3] = factor * (rot(2,0) - rot(0,2));
205 } else {
206
207 3 T q_z = 0.5 * sqrt(rot(2,2)-rot(0,0)-rot(1,1)+1);
208 3 T factor = 0.25 / q_z;
209
210 3 mm[0] = factor * (rot(2,0) + rot(0,2));
211 3 mm[1] = factor * (rot(1,2) + rot(2,1));
212 3 mm[2] = q_z;
213 3 mm[3] = factor * (rot(0,1) - rot(1,0));
214 }
215 3 }
216
217 /// Reference to the component, e.g. q.x() = 4.5f;
218 T& x() { return mm[0]; }
219 T& y() { return mm[1]; }
220 T& z() { return mm[2]; }
221 T& w() { return mm[3]; }
222
223 /// Get the component, e.g. float f = q.w();
224 T x() const { return mm[0]; }
225 T y() const { return mm[1]; }
226 T z() const { return mm[2]; }
227 T w() const { return mm[3]; }
228
229 // Number of elements
230 static unsigned numElements() { return 4; }
231
232 /// Array style reference to the components, e.g. q[3] = 1.34f;
233 T& operator[](int i) { return mm[i]; }
234
235 /// Array style constant reference to the components, e.g. float f = q[1];
236 T operator[](int i) const { return mm[i]; }
237
238 /// Cast to T*
239 operator T*() { return mm; }
240 operator const T*() const { return mm; }
241
242 /// Alternative indexed reference to the elements
243 T& operator()(int i) { return mm[i]; }
244
245 /// Alternative indexed constant reference to the elements,
246 T operator()(int i) const { return mm[i]; }
247
248 /// Return angle of rotation
249 2 T angle() const
250 {
251 2 T sqrLength = mm[0]*mm[0] + mm[1]*mm[1] + mm[2]*mm[2];
252
253
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if ( sqrLength > 1.0e-8 ) {
254
255 2 return T(T(2.0) * acos(mm[3]));
256
257 } else {
258
259 return T(0.0);
260 }
261 }
262
263 /// Return axis of rotation
264 2 Vec3<T> axis() const
265 {
266 2 T sqrLength = mm[0]*mm[0] + mm[1]*mm[1] + mm[2]*mm[2];
267
268
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if ( sqrLength > 1.0e-8 ) {
269
270 2 T invLength = T(T(1)/sqrt(sqrLength));
271
272 2 return Vec3<T>( mm[0]*invLength, mm[1]*invLength, mm[2]*invLength );
273 } else {
274
275 return Vec3<T>(1,0,0);
276 }
277 }
278
279
280 /// "this" quaternion gets initialized to [x, y, z, w]
281 Quat& init(T x, T y, T z, T w)
282 {
283 mm[0] = x; mm[1] = y; mm[2] = z; mm[3] = w;
284 return *this;
285 }
286
287 /// "this" quaternion gets initialized to identity, same as setIdentity()
288 Quat& init() { return setIdentity(); }
289
290 /// Set "this" quaternion to rotation specified by axis and angle,
291 /// the axis must be unit vector
292 1 Quat& setAxisAngle(const Vec3<T>& axis, T angle)
293 {
294
295 1 T s = T(sin(angle*T(0.5)));
296
297 1 mm[0] = axis.x() * s;
298 1 mm[1] = axis.y() * s;
299 1 mm[2] = axis.z() * s;
300
301 1 mm[3] = T(cos(angle*T(0.5)));
302
303 1 return *this;
304 } // axisAngleTest
305
306 /// Set "this" vector to zero
307 Quat& setZero()
308 {
309 mm[0] = mm[1] = mm[2] = mm[3] = 0;
310 return *this;
311 }
312
313 /// Set "this" vector to identity
314 Quat& setIdentity()
315 {
316 mm[0] = mm[1] = mm[2] = 0;
317 mm[3] = 1;
318 return *this;
319 }
320
321 /// Returns vector of x,y,z rotational components
322 8 Vec3<T> eulerAngles(RotationOrder rotationOrder) const
323 8 { return math::eulerAngles(Mat3<T>(*this), rotationOrder); }
324
325 /// Equality operator, does exact floating point comparisons
326 bool operator==(const Quat &q) const
327 {
328
2/10
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
6 return (isExactlyEqual(mm[0],q.mm[0]) &&
329
2/10
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
6 isExactlyEqual(mm[1],q.mm[1]) &&
330
4/20
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 5 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 5 times.
✗ Branch 19 not taken.
12 isExactlyEqual(mm[2],q.mm[2]) &&
331 isExactlyEqual(mm[3],q.mm[3]) );
332 }
333
334 /// Test if "this" is equivalent to q with tolerance of eps value
335
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 bool eq(const Quat &q, T eps=1.0e-7) const
336 {
337
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 return isApproxEqual(mm[0],q.mm[0],eps) && isApproxEqual(mm[1],q.mm[1],eps) &&
338
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
4 isApproxEqual(mm[2],q.mm[2],eps) && isApproxEqual(mm[3],q.mm[3],eps) ;
339 } // trivial
340
341 /// Add quaternion q to "this" quaternion, e.g. q += q1;
342 Quat& operator+=(const Quat &q)
343 {
344 mm[0] += q.mm[0];
345 mm[1] += q.mm[1];
346 mm[2] += q.mm[2];
347 mm[3] += q.mm[3];
348
349 return *this;
350 }
351
352 /// Subtract quaternion q from "this" quaternion, e.g. q -= q1;
353 Quat& operator-=(const Quat &q)
354 {
355 mm[0] -= q.mm[0];
356 mm[1] -= q.mm[1];
357 mm[2] -= q.mm[2];
358 mm[3] -= q.mm[3];
359
360 return *this;
361 }
362
363 /// Scale "this" quaternion by scalar, e.g. q *= scalar;
364 Quat& operator*=(T scalar)
365 {
366 1 mm[0] *= scalar;
367 1 mm[1] *= scalar;
368 1 mm[2] *= scalar;
369 1 mm[3] *= scalar;
370
371 return *this;
372 }
373
374 /// Return (this+q), e.g. q = q1 + q2;
375 Quat operator+(const Quat &q) const
376 {
377 return Quat<T>(mm[0]+q.mm[0], mm[1]+q.mm[1], mm[2]+q.mm[2], mm[3]+q.mm[3]);
378 }
379
380 /// Return (this-q), e.g. q = q1 - q2;
381 Quat operator-(const Quat &q) const
382 {
383 return Quat<T>(mm[0]-q.mm[0], mm[1]-q.mm[1], mm[2]-q.mm[2], mm[3]-q.mm[3]);
384 }
385
386 /// Return (this*q), e.g. q = q1 * q2;
387 2 Quat operator*(const Quat &q) const
388 {
389 Quat<T> prod;
390
391 2 prod.mm[0] = mm[3]*q.mm[0] + mm[0]*q.mm[3] + mm[1]*q.mm[2] - mm[2]*q.mm[1];
392 2 prod.mm[1] = mm[3]*q.mm[1] + mm[1]*q.mm[3] + mm[2]*q.mm[0] - mm[0]*q.mm[2];
393 2 prod.mm[2] = mm[3]*q.mm[2] + mm[2]*q.mm[3] + mm[0]*q.mm[1] - mm[1]*q.mm[0];
394 2 prod.mm[3] = mm[3]*q.mm[3] - mm[0]*q.mm[0] - mm[1]*q.mm[1] - mm[2]*q.mm[2];
395
396 2 return prod;
397
398 }
399
400 /// Assigns this to (this*q), e.g. q *= q1;
401 Quat operator*=(const Quat &q)
402 {
403 *this = *this * q;
404 return *this;
405 }
406
407 /// Return (this*scalar), e.g. q = q1 * scalar;
408 Quat operator*(T scalar) const
409 {
410 return Quat<T>(mm[0]*scalar, mm[1]*scalar, mm[2]*scalar, mm[3]*scalar);
411 }
412
413 /// Return (this/scalar), e.g. q = q1 / scalar;
414 Quat operator/(T scalar) const
415 {
416 1 return Quat<T>(mm[0]/scalar, mm[1]/scalar, mm[2]/scalar, mm[3]/scalar);
417 }
418
419 /// Negation operator, e.g. q = -q;
420 Quat operator-() const
421 { return Quat<T>(-mm[0], -mm[1], -mm[2], -mm[3]); }
422
423 /// this = q1 + q2
424 /// "this", q1 and q2 need not be distinct objects, e.g. q.add(q1,q);
425 Quat& add(const Quat &q1, const Quat &q2)
426 {
427 mm[0] = q1.mm[0] + q2.mm[0];
428 mm[1] = q1.mm[1] + q2.mm[1];
429 mm[2] = q1.mm[2] + q2.mm[2];
430 mm[3] = q1.mm[3] + q2.mm[3];
431
432 return *this;
433 }
434
435 /// this = q1 - q2
436 /// "this", q1 and q2 need not be distinct objects, e.g. q.sub(q1,q);
437 Quat& sub(const Quat &q1, const Quat &q2)
438 {
439 mm[0] = q1.mm[0] - q2.mm[0];
440 mm[1] = q1.mm[1] - q2.mm[1];
441 mm[2] = q1.mm[2] - q2.mm[2];
442 mm[3] = q1.mm[3] - q2.mm[3];
443
444 return *this;
445 }
446
447 /// this = q1 * q2
448 /// q1 and q2 must be distinct objects than "this", e.g. q.mult(q1,q2);
449 Quat& mult(const Quat &q1, const Quat &q2)
450 {
451 mm[0] = q1.mm[3]*q2.mm[0] + q1.mm[0]*q2.mm[3] +
452 q1.mm[1]*q2.mm[2] - q1.mm[2]*q2.mm[1];
453 mm[1] = q1.mm[3]*q2.mm[1] + q1.mm[1]*q2.mm[3] +
454 q1.mm[2]*q2.mm[0] - q1.mm[0]*q2.mm[2];
455 mm[2] = q1.mm[3]*q2.mm[2] + q1.mm[2]*q2.mm[3] +
456 q1.mm[0]*q2.mm[1] - q1.mm[1]*q2.mm[0];
457 mm[3] = q1.mm[3]*q2.mm[3] - q1.mm[0]*q2.mm[0] -
458 q1.mm[1]*q2.mm[1] - q1.mm[2]*q2.mm[2];
459
460 return *this;
461 }
462
463 /// this = scalar*q, q need not be distinct object than "this",
464 /// e.g. q.scale(1.5,q1);
465 Quat& scale(T scale, const Quat &q)
466 {
467 mm[0] = scale * q.mm[0];
468 mm[1] = scale * q.mm[1];
469 mm[2] = scale * q.mm[2];
470 mm[3] = scale * q.mm[3];
471
472 return *this;
473 }
474
475 /// Dot product
476 T dot(const Quat &q) const
477 {
478
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
4 return (mm[0]*q.mm[0] + mm[1]*q.mm[1] + mm[2]*q.mm[2] + mm[3]*q.mm[3]);
479 }
480
481 /// Return the quaternion rate corrsponding to the angular velocity omega
482 /// and "this" current rotation
483 Quat derivative(const Vec3<T>& omega) const
484 {
485 return Quat<T>( +w()*omega.x() -z()*omega.y() +y()*omega.z() ,
486 +z()*omega.x() +w()*omega.y() -x()*omega.z() ,
487 -y()*omega.x() +x()*omega.y() +w()*omega.z() ,
488 -x()*omega.x() -y()*omega.y() -z()*omega.z() );
489 }
490
491 /// this = normalized this
492 1 bool normalize(T eps = T(1.0e-8))
493 {
494
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 T d = T(sqrt(mm[0]*mm[0] + mm[1]*mm[1] + mm[2]*mm[2] + mm[3]*mm[3]));
495
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if( isApproxEqual(d, T(0.0), eps) ) return false;
496 1 *this *= ( T(1)/d );
497 1 return true;
498 }
499
500 /// this = normalized this
501 Quat unit() const
502 {
503 T d = sqrt(mm[0]*mm[0] + mm[1]*mm[1] + mm[2]*mm[2] + mm[3]*mm[3]);
504 if( isExactlyEqual(d , T(0.0) ) )
505 OPENVDB_THROW(ArithmeticError,
506 "Normalizing degenerate quaternion");
507 return *this / d;
508 }
509
510 /// returns inverse of this
511 1 Quat inverse(T tolerance = T(0)) const
512 {
513
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 T d = mm[0]*mm[0] + mm[1]*mm[1] + mm[2]*mm[2] + mm[3]*mm[3];
514
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if( isApproxEqual(d, T(0.0), tolerance) )
515 OPENVDB_THROW(ArithmeticError,
516 "Cannot invert degenerate quaternion");
517 1 Quat result = *this/-d;
518 1 result.mm[3] = -result.mm[3];
519 1 return result;
520 }
521
522
523 /// Return the conjugate of "this", same as invert without
524 /// unit quaternion test
525 Quat conjugate() const
526 {
527
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 return Quat<T>(-mm[0], -mm[1], -mm[2], mm[3]);
528 }
529
530 /// Return rotated vector by "this" quaternion
531 Vec3<T> rotateVector(const Vec3<T> &v) const
532 {
533 Mat3<T> m(*this);
534 return m.transform(v);
535 }
536
537 /// Predefined constants, e.g. Quat q = Quat::identity();
538 327 static Quat zero() { return Quat<T>(0,0,0,0); }
539 static Quat identity() { return Quat<T>(0,0,0,1); }
540
541 /// @return string representation of Classname
542 std::string str() const
543 {
544 std::ostringstream buffer;
545
546 buffer << "[";
547
548 // For each column
549 for (unsigned j(0); j < 4; j++) {
550 if (j) buffer << ", ";
551 buffer << mm[j];
552 }
553
554 buffer << "]";
555
556 return buffer.str();
557 }
558
559 /// Output to the stream, e.g. std::cout << q << std::endl;
560 friend std::ostream& operator<<(std::ostream &stream, const Quat &q)
561 {
562 stream << q.str();
563 return stream;
564 }
565
566 friend Quat slerp<>(const Quat &q1, const Quat &q2, T t, T tolerance);
567
568 void write(std::ostream& os) const { os.write(static_cast<char*>(&mm), sizeof(T) * 4); }
569 void read(std::istream& is) { is.read(static_cast<char*>(&mm), sizeof(T) * 4); }
570
571 protected:
572 T mm[4];
573 };
574
575 /// Multiply each element of the given quaternion by @a scalar and return the result.
576 template <typename S, typename T>
577 Quat<T> operator*(S scalar, const Quat<T> &q) { return q*scalar; }
578
579
580 /// @brief Interpolate between m1 and m2.
581 /// Converts to quaternion form and uses slerp
582 /// m1 and m2 must be rotation matrices!
583 template <typename T, typename T0>
584 Mat3<T> slerp(const Mat3<T0> &m1, const Mat3<T0> &m2, T t)
585 {
586 using MatType = Mat3<T>;
587
588 Quat<T> q1(m1);
589 Quat<T> q2(m2);
590
591 if (q1.dot(q2) < 0) q2 *= -1;
592
593 Quat<T> qslerp = slerp<T>(q1, q2, static_cast<T>(t));
594 MatType m = rotation<MatType>(qslerp);
595 return m;
596 }
597
598
599
600 /// Interpolate between m1 and m4 by converting m1 ... m4 into
601 /// quaternions and treating them as control points of a Bezier
602 /// curve using slerp in place of lerp in the De Castlejeau evaluation
603 /// algorithm. Just like a cubic Bezier curve, this will interpolate
604 /// m1 at t = 0 and m4 at t = 1 but in general will not pass through
605 /// m2 and m3. Unlike a standard Bezier curve this curve will not have
606 /// the convex hull property.
607 /// m1 ... m4 must be rotation matrices!
608 template <typename T, typename T0>
609 Mat3<T> bezLerp(const Mat3<T0> &m1, const Mat3<T0> &m2,
610 const Mat3<T0> &m3, const Mat3<T0> &m4,
611 T t)
612 {
613 Mat3<T> m00, m01, m02, m10, m11;
614
615 m00 = slerp(m1, m2, t);
616 m01 = slerp(m2, m3, t);
617 m02 = slerp(m3, m4, t);
618
619 m10 = slerp(m00, m01, t);
620 m11 = slerp(m01, m02, t);
621
622 return slerp(m10, m11, t);
623 }
624
625 using Quats = Quat<float>;
626 using Quatd = Quat<double>;
627
628 #if OPENVDB_ABI_VERSION_NUMBER >= 8
629 OPENVDB_IS_POD(Quats)
630 OPENVDB_IS_POD(Quatd)
631 #endif
632
633 } // namespace math
634
635
636 template<> inline math::Quats zeroVal<math::Quats >() { return math::Quats::zero(); }
637 324 template<> inline math::Quatd zeroVal<math::Quatd >() { return math::Quatd::zero(); }
638
639 } // namespace OPENVDB_VERSION_NAME
640 } // namespace openvdb
641
642 #endif //OPENVDB_MATH_QUAT_H_HAS_BEEN_INCLUDED
643