Blender V4.3
BLI_math_quaternion.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
14
15#include "BLI_math_matrix.hh"
16
17namespace blender::math {
18
19/* -------------------------------------------------------------------- */
28template<typename T>
29[[nodiscard]] inline T dot(const QuaternionBase<T> &a, const QuaternionBase<T> &b);
30
36template<typename T> [[nodiscard]] QuaternionBase<T> pow(const QuaternionBase<T> &q, const T &y);
37
43template<typename T> [[nodiscard]] inline QuaternionBase<T> conjugate(const QuaternionBase<T> &a);
44
48template<typename T>
49[[nodiscard]] inline QuaternionBase<T> canonicalize(const QuaternionBase<T> &q);
50
56template<typename T> [[nodiscard]] inline QuaternionBase<T> invert(const QuaternionBase<T> &q);
57
63template<typename T>
64[[nodiscard]] inline QuaternionBase<T> invert_normalized(const QuaternionBase<T> &q);
65
70template<typename T> [[nodiscard]] inline QuaternionBase<T> normalize(const QuaternionBase<T> &q);
71template<typename T>
72[[nodiscard]] inline QuaternionBase<T> normalize_and_get_length(const QuaternionBase<T> &q,
73 T &out_length);
74
79template<typename T>
80[[nodiscard]] inline QuaternionBase<T> interpolate(const QuaternionBase<T> &a,
81 const QuaternionBase<T> &b,
82 T t);
83
86/* -------------------------------------------------------------------- */
93template<typename T>
94[[nodiscard]] inline VecBase<T, 3> transform_point(const QuaternionBase<T> &q,
95 const VecBase<T, 3> &v);
96
99/* -------------------------------------------------------------------- */
106template<typename T> [[nodiscard]] inline bool is_zero(const QuaternionBase<T> &q)
107{
108 return q.w == T(0) && q.x == T(0) && q.y == T(0) && q.z == T(0);
109}
110
114template<typename T>
115[[nodiscard]] inline bool is_equal(const QuaternionBase<T> &a,
116 const QuaternionBase<T> &b,
117 const T epsilon = T(0))
118{
119 return math::abs(a.w - b.w) <= epsilon && math::abs(a.y - b.y) <= epsilon &&
120 math::abs(a.x - b.x) <= epsilon && math::abs(a.z - b.z) <= epsilon;
121}
122
123template<typename T> [[nodiscard]] inline bool is_unit_scale(const QuaternionBase<T> &q)
124{
125 /* Checks are flipped so NAN doesn't assert because we're making sure the value was
126 * normalized and in the case we don't want NAN to be raising asserts since there
127 * is nothing to be done in that case. */
128 const T test_unit = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
129 return (!(math::abs(test_unit - T(1)) >= AssertUnitEpsilon<QuaternionBase<T>>::value) ||
130 !(math::abs(test_unit) >= AssertUnitEpsilon<QuaternionBase<T>>::value));
131}
132
135/* -------------------------------------------------------------------- */
139/* -------------- Conversions -------------- */
140
141template<typename T> AngleRadianBase<T> QuaternionBase<T>::twist_angle(const Axis axis) const
142{
143 /* The calculation requires a canonical quaternion. */
144 const VecBase<T, 4> input_vec(canonicalize(*this));
145
146 return T(2) * AngleRadianBase<T>(input_vec[0], input_vec.yzw()[axis.as_int()]);
147}
148
149template<typename T> QuaternionBase<T> QuaternionBase<T>::swing(const Axis axis) const
150{
151 /* The calculation requires a canonical quaternion. */
152 const QuaternionBase<T> input = canonicalize(*this);
153 /* Compute swing by multiplying the original quaternion by inverted twist. */
154 QuaternionBase<T> swing = input * invert_normalized(input.twist(axis));
155
156 BLI_assert(math::abs(VecBase<T, 4>(swing)[axis.as_int() + 1]) <
157 0.0002f /*BLI_ASSERT_UNIT_EPSILON*/);
158 return swing;
159}
160
161template<typename T> QuaternionBase<T> QuaternionBase<T>::twist(const Axis axis) const
162{
163 /* The calculation requires a canonical quaternion. */
164 const VecBase<T, 4> input_vec(canonicalize(*this));
165
167 input_vec[0], input_vec.yzw()[axis.as_int()]);
168
169 VecBase<T, 4> twist(half_angle.cos(), T(0), T(0), T(0));
170 twist[axis.as_int() + 1] = half_angle.sin();
171 return QuaternionBase<T>(twist);
172}
173
174/* -------------- Methods -------------- */
175
176template<typename T>
178{
180 const QuaternionBase<T> &input = *this;
181 T len;
182 QuaternionBase<T> reference_normalized = normalize_and_get_length(reference, len);
183 /* Skips degenerate case. */
184 if (len < 1e-4f) {
185 return input;
186 }
187 QuaternionBase<T> result = reference * invert_normalized(reference_normalized) * input;
188 return (distance_squared(VecBase<T, 4>(-result), VecBase<T, 4>(reference)) <
189 distance_squared(VecBase<T, 4>(result), VecBase<T, 4>(reference))) ?
190 -result :
191 result;
192}
193
194/* -------------- Functions -------------- */
195
196template<typename T>
197[[nodiscard]] inline T dot(const QuaternionBase<T> &a, const QuaternionBase<T> &b)
198{
199 return a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z;
200}
201
202template<typename T> [[nodiscard]] QuaternionBase<T> pow(const QuaternionBase<T> &q, const T &y)
203{
205 /* Reference material:
206 * https://en.wikipedia.org/wiki/Quaternion
207 *
208 * The power of a quaternion raised to an arbitrary (real) exponent y is given by:
209 * `q^x = ||q||^y * (cos(y * angle * 0.5) + n * sin(y * angle * 0.5))`
210 * where `n` is the unit vector from the imaginary part of the quaternion and
211 * where `angle` is the angle of the rotation given by `angle = 2 * acos(q.w)`.
212 *
213 * q being a unit quaternion, ||q||^y becomes 1 and is canceled out.
214 *
215 * `y * angle * 0.5` expands to `y * 2 * acos(q.w) * 0.5` which simplifies to `y * acos(q.w)`.
216 */
217 const T half_angle = y * math::safe_acos(q.w);
218 return {math::cos(half_angle), math::sin(half_angle) * normalize(q.imaginary_part())};
219}
220
221template<typename T> [[nodiscard]] inline QuaternionBase<T> conjugate(const QuaternionBase<T> &a)
222{
223 return {a.w, -a.x, -a.y, -a.z};
224}
225
226template<typename T>
228{
229 return (q.w < T(0)) ? -q : q;
230}
231
232template<typename T> [[nodiscard]] inline QuaternionBase<T> invert(const QuaternionBase<T> &q)
233{
234 const T length_squared = dot(q, q);
235 if (length_squared == T(0)) {
237 }
238 return conjugate(q) * (T(1) / length_squared);
239}
240
241template<typename T>
243{
245 return conjugate(q);
246}
247
248template<typename T>
250 T &out_length)
251{
252 out_length = math::sqrt(dot(q, q));
253 return (out_length != T(0)) ? (q * (T(1) / out_length)) : QuaternionBase<T>::identity();
254}
255
256template<typename T> [[nodiscard]] inline QuaternionBase<T> normalize(const QuaternionBase<T> &q)
257{
258 T len;
259 return normalize_and_get_length(q, len);
260}
261
270template<typename T>
271[[nodiscard]] inline VecBase<T, 2> interpolate_dot_slerp(const T t, const T cosom)
272{
273 const T eps = T(1e-4);
274
275 BLI_assert(IN_RANGE_INCL(cosom, T(-1.0001), T(1.0001)));
276
278 T abs_cosom = math::abs(cosom);
279 /* Within [-1..1] range, avoid aligned axis. */
280 if (LIKELY(abs_cosom < (T(1) - eps))) {
281 const T omega = math::acos(abs_cosom);
282 const T sinom = math::sin(omega);
283
284 w[0] = math::sin((T(1) - t) * omega) / sinom;
285 w[1] = math::sin(t * omega) / sinom;
286 }
287 else {
288 /* Fallback to lerp */
289 w[0] = T(1) - t;
290 w[1] = t;
291 }
292
293 /* Rotate around shortest angle. */
294 if (cosom < T(0)) {
295 w[0] = -w[0];
296 }
297 return w;
298}
299
300template<typename T>
301[[nodiscard]] inline QuaternionBase<T> interpolate(const QuaternionBase<T> &a,
302 const QuaternionBase<T> &b,
303 T t)
304{
305 using Vec4T = VecBase<T, 4>;
309 return QuaternionBase<T>(w[0] * Vec4T(a) + w[1] * Vec4T(b));
310}
311
312template<typename T>
313[[nodiscard]] inline VecBase<T, 3> transform_point(const QuaternionBase<T> &q,
314 const VecBase<T, 3> &v)
315{
316#if 0 /* Reference. */
318 QuaternionBase<T> R = q * V * conjugate(q);
319 return {R.x, R.y, R.z};
320#else
321 /* `S = q * V`. */
323 S.w = /* q.w * 0.0 */ -q.x * v.x - q.y * v.y - q.z * v.z;
324 S.x = q.w * v.x /* + q.x * 0.0 */ + q.y * v.z - q.z * v.y;
325 S.y = q.w * v.y /* + q.y * 0.0 */ + q.z * v.x - q.x * v.z;
326 S.z = q.w * v.z /* + q.z * 0.0 */ + q.x * v.y - q.y * v.x;
327 /* `R = S * conjugate(q)`. */
329 /* `R.w = S.w * q.w + S.x * q.x + S.y * q.y + S.z * q.z = 0.0`. */
330 R.x = S.w * -q.x + S.x * q.w - S.y * q.z + S.z * q.y;
331 R.y = S.w * -q.y + S.y * q.w - S.z * q.x + S.x * q.z;
332 R.z = S.w * -q.z + S.z * q.w - S.x * q.y + S.y * q.x;
333 return R;
334#endif
335}
336
339/* -------------------------------------------------------------------- */
343/* -------------- Constructors -------------- */
344
345template<typename T>
347 const QuaternionBase<T> &dual)
348 : quat(non_dual), trans(dual), scale_weight(0), quat_weight(1)
349{
350 BLI_assert(is_unit_scale(non_dual));
351}
352
353template<typename T>
355 const QuaternionBase<T> &dual,
356 const MatBase<T, 4, 4> &scale_mat)
357 : quat(non_dual), trans(dual), scale(scale_mat), scale_weight(1), quat_weight(1)
358{
359 BLI_assert(is_unit_scale(non_dual));
360}
361
362/* -------------- Operators -------------- */
363
364template<typename T>
366{
367 DualQuaternionBase<T> &a = *this;
368 /* Sum rotation and translation. */
369
370 /* Make sure we interpolate quaternions in the right direction. */
371 if (dot(a.quat, b.quat) < 0) {
372 a.quat.w -= b.quat.w;
373 a.quat.x -= b.quat.x;
374 a.quat.y -= b.quat.y;
375 a.quat.z -= b.quat.z;
376
377 a.trans.w -= b.trans.w;
378 a.trans.x -= b.trans.x;
379 a.trans.y -= b.trans.y;
380 a.trans.z -= b.trans.z;
381 }
382 else {
383 a.quat.w += b.quat.w;
384 a.quat.x += b.quat.x;
385 a.quat.y += b.quat.y;
386 a.quat.z += b.quat.z;
387
388 a.trans.w += b.trans.w;
389 a.trans.x += b.trans.x;
390 a.trans.y += b.trans.y;
391 a.trans.z += b.trans.z;
392 }
393
394 a.quat_weight += b.quat_weight;
395
396 if (b.scale_weight > T(0)) {
397 if (a.scale_weight > T(0)) {
398 /* Weighted sum of scale matrices (sum of components). */
399 a.scale += b.scale;
400 a.scale_weight += b.scale_weight;
401 }
402 else {
403 /* No existing scale. Replace. */
404 a.scale = b.scale;
405 a.scale_weight = b.scale_weight;
406 }
407 }
408 return *this;
409}
410
412{
413 BLI_assert(t >= 0);
414 DualQuaternionBase<T> &q = *this;
415
416 q.quat.w *= t;
417 q.quat.x *= t;
418 q.quat.y *= t;
419 q.quat.z *= t;
420
421 q.trans.w *= t;
422 q.trans.x *= t;
423 q.trans.y *= t;
424 q.trans.z *= t;
425
426 q.quat_weight *= t;
427
428 if (q.scale_weight > T(0)) {
429 q.scale *= t;
430 q.scale_weight *= t;
431 }
432 return *this;
433}
434
435/* -------------- Functions -------------- */
436
444template<typename T>
446{
447 const T norm_weighted = math::sqrt(dot(dual_quat.quat, dual_quat.quat));
448 /* NOTE(fclem): Should this be an epsilon? */
449 if (norm_weighted == T(0)) {
450 /* The dual-quaternion was zero initialized or is degenerate. Return identity. */
452 }
453
454 const T inv_norm_weighted = T(1) / norm_weighted;
455
456 DualQuaternionBase<T> dq = dual_quat;
457 dq.quat = dq.quat * inv_norm_weighted;
458 dq.trans = dq.trans * inv_norm_weighted;
459
460 /* Handle scale if needed. */
461 if (dq.scale_weight > T(0)) {
462 /* Compensate for any dual quaternions added without scale.
463 * This is an optimization so that we can skip the scale part when not needed. */
464 const float missing_uniform_scale = dq.quat_weight - dq.scale_weight;
465
466 if (missing_uniform_scale > T(0)) {
467 dq.scale[0][0] += missing_uniform_scale;
468 dq.scale[1][1] += missing_uniform_scale;
469 dq.scale[2][2] += missing_uniform_scale;
470 dq.scale[3][3] += missing_uniform_scale;
471 }
472 /* Per component scalar product. */
473 dq.scale *= T(1) / dq.quat_weight;
474 dq.scale_weight = T(1);
475 }
476 dq.quat_weight = T(1);
477 return dq;
478}
479
485template<typename T>
487 const VecBase<T, 3> &point,
488 MatBase<T, 3, 3> *r_crazy_space_mat = nullptr)
489{
498 /* Follow the paper notation. */
499 const T &w0 = dq.quat.w, &x0 = dq.quat.x, &y0 = dq.quat.y, &z0 = dq.quat.z;
500 const T &we = dq.trans.w, &xe = dq.trans.x, &ye = dq.trans.y, &ze = dq.trans.z;
501 /* Part 3.4 - The Final Algorithm. */
503 t[0] = T(2) * (-we * x0 + xe * w0 - ye * z0 + ze * y0);
504 t[1] = T(2) * (-we * y0 + xe * z0 + ye * w0 - ze * x0);
505 t[2] = T(2) * (-we * z0 - xe * y0 + ye * x0 + ze * w0);
506 /* Isolate rotation matrix to easily output crazy-space mat. */
508 M[0][0] = (w0 * w0) + (x0 * x0) - (y0 * y0) - (z0 * z0); /* Same as `1 - 2y0^2 - 2z0^2`. */
509 M[0][1] = T(2) * ((x0 * y0) + (w0 * z0));
510 M[0][2] = T(2) * ((x0 * z0) - (w0 * y0));
511
512 M[1][0] = T(2) * ((x0 * y0) - (w0 * z0));
513 M[1][1] = (w0 * w0) + (y0 * y0) - (x0 * x0) - (z0 * z0); /* Same as `1 - 2x0^2 - 2z0^2`. */
514 M[1][2] = T(2) * ((y0 * z0) + (w0 * x0));
515
516 M[2][1] = T(2) * ((y0 * z0) - (w0 * x0));
517 M[2][2] = (w0 * w0) + (z0 * z0) - (x0 * x0) - (y0 * y0); /* Same as `1 - 2x0^2 - 2y0^2`. */
518 M[2][0] = T(2) * ((x0 * z0) + (w0 * y0));
519
520 VecBase<T, 3> result = point;
521 /* Apply scaling. */
522 if (dq.scale_weight != T(0)) {
523 /* NOTE(fclem): This is weird that this is also adding translation even if it is marked as
524 * scale matrix. Follows the old C implementation for now... */
525 result = transform_point(dq.scale, result);
526 }
527 /* Apply rotation and translation. */
528 result = transform_point(M, result) + t;
529 /* Compute crazy-space correction matrix. */
530 if (r_crazy_space_mat != nullptr) {
531 if (dq.scale_weight) {
532 *r_crazy_space_mat = M * dq.scale.template view<3, 3>();
533 }
534 else {
535 *r_crazy_space_mat = M;
536 }
537 }
538 return result;
539}
540
547template<typename T>
549 const MatBase<T, 4, 4> &basemat)
550{
563 using Mat4T = MatBase<T, 4, 4>;
564 using Vec3T = VecBase<T, 3>;
565
566 /* Split scaling and rotation.
567 * There is probably a faster way to do this. It is currently done like this to correctly get
568 * negative scaling. */
569 Mat4T baseRS = mat * basemat;
570
571 Mat4T R, scale;
572 const bool has_scale = !is_orthonormal(mat) || is_negative(mat) ||
573 length_squared(to_scale(baseRS) - T(1)) > square(1e-4f);
574 if (has_scale) {
575 /* Extract Rotation and Scale. */
576 const Mat4T baseinv = invert(basemat);
577
578 /* Extra orthogonalize, to avoid flipping with stretched bones. */
580
581 Mat4T baseR = from_rotation<Mat4T>(basequat);
582 baseR.location() = baseRS.location();
583
584 R = baseR * baseinv;
585
586 const Mat4T S = invert(baseR) * baseRS;
587 /* Set scaling part. */
588 scale = basemat * S * baseinv;
589 }
590 else {
591 /* Input matrix does not contain scaling. */
592 R = mat;
593 }
594
595 /* Non-dual part. */
597
598 /* Dual part. */
599 const Vec3T &t = R.location().xyz();
601 d.w = T(-0.5) * (+t.x * q.x + t.y * q.y + t.z * q.z);
602 d.x = T(+0.5) * (+t.x * q.w + t.y * q.z - t.z * q.y);
603 d.y = T(+0.5) * (-t.x * q.z + t.y * q.w + t.z * q.x);
604 d.z = T(+0.5) * (+t.x * q.y - t.y * q.x + t.z * q.w);
605
606 if (has_scale) {
607 return DualQuaternionBase<T>(q, d, scale);
608 }
609
610 return DualQuaternionBase<T>(q, d);
611}
612
615} // namespace blender::math
616
617namespace blender::math {
618
619/* -------------------------------------------------------------------- */
623template<typename T, typename AngleT = AngleRadian>
625{
627
628 VecBase<T, 3> axis = VecBase<T, 3>(quat.x, quat.y, quat.z);
629 T cos_half_angle = quat.w;
630 T sin_half_angle = math::length(axis);
631 /* Prevent division by zero for axis conversion. */
632 if (sin_half_angle < T(0.0005)) {
633 using AngleAxisT = typename AxisAngleBase<T, AngleT>::vec3_type;
634 const AngleAxisT identity_axis = AxisAngleBase<T, AngleT>::identity().axis();
635 BLI_assert(abs(cos_half_angle) > 0.0005);
636 AxisAngleBase<T, AngleT> identity(identity_axis * sign(cos_half_angle), AngleT(0));
637 return identity;
638 }
639 /* Normalize the axis. */
640 axis /= sin_half_angle;
641
642 /* Leverage AngleT implementation of double angle. */
643 AngleT angle = AngleT(cos_half_angle, sin_half_angle) * 2;
644
645 return AxisAngleBase<T, AngleT>(axis, angle);
646}
647
650/* -------------------------------------------------------------------- */
654template<typename T> EulerXYZBase<T> to_euler(const QuaternionBase<T> &quat)
655{
656 using Mat3T = MatBase<T, 3, 3>;
658 Mat3T unit_mat = from_rotation<Mat3T>(quat);
659 return to_euler<T>(unit_mat);
660}
661
662template<typename T> Euler3Base<T> to_euler(const QuaternionBase<T> &quat, EulerOrder order)
663{
664 using Mat3T = MatBase<T, 3, 3>;
666 Mat3T unit_mat = from_rotation<Mat3T>(quat);
667 return to_euler<T>(unit_mat, order);
668}
669
672/* -------------------------------------------------------------------- */
676/* Prototype needed to avoid interdependencies of headers. */
677template<typename T, typename AngleT>
678QuaternionBase<T> to_quaternion(const AxisAngleBase<T, AngleT> &axis_angle);
679
681{
682 using AxisAngleT = AxisAngleBase<T, AngleRadianBase<T>>;
683 /* Obtain axis/angle representation. */
684 T angle;
685 const VecBase<T, 3> axis = normalize_and_get_length(expmap, angle);
686 if (LIKELY(angle != T(0))) {
687 return to_quaternion(AxisAngleT(axis, AngleRadianBase<T>(angle).wrapped()));
688 }
690}
691
692template<typename T> VecBase<T, 3> QuaternionBase<T>::expmap() const
693{
694 using AxisAngleT = AxisAngleBase<T, AngleRadianBase<T>>;
696 const AxisAngleT axis_angle = to_axis_angle(*this);
697 return axis_angle.axis() * axis_angle.angle().radian();
698}
699
702} // namespace blender::math
#define BLI_assert(a)
Definition BLI_assert.h:50
#define UNPACK3(a)
#define IN_RANGE_INCL(a, b, c)
#define LIKELY(x)
static AppView * view
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
static constexpr Value Y
local_group_size(16, 16) .push_constant(Type b
int len
#define M
#define T
#define R
QuaternionBase< T > conjugate(const QuaternionBase< T > &a)
T length_squared(const VecBase< T, Size > &a)
T cos(const AngleRadianBase< T > &a)
T pow(const T &x, const T &power)
bool is_normalized(const DualQuaternionBase< T > &dq)
T acos(const T &a)
T sqrt(const T &a)
QuaternionBase< T > to_quaternion(const AxisAngleBase< T, AngleT > &axis_angle)
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
bool is_orthonormal(const MatT &mat)
T sign(const T &a)
T length(const VecBase< T, Size > &a)
QuaternionBase< T > normalize_and_get_length(const QuaternionBase< T > &q, T &out_length)
bool is_unit_scale(const MatBase< T, NumCol, NumRow > &m)
bool is_negative(const MatBase< T, Size, Size > &mat)
bool is_zero(const T &a)
CartesianBasis invert(const CartesianBasis &basis)
T interpolate(const T &a, const T &b, const FactorT &t)
T safe_acos(const T &a)
QuaternionBase< T > invert_normalized(const QuaternionBase< T > &q)
AxisAngleBase< T, AngleT > to_axis_angle(const EulerXYZBase< T > &euler)
VecBase< T, 3 > to_scale(const MatBase< T, NumCol, NumRow > &mat)
QuaternionBase< T > canonicalize(const QuaternionBase< T > &q)
T square(const T &a)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
bool is_equal(const MatBase< T, NumCol, NumRow > &a, const MatBase< T, NumCol, NumRow > &b, const T epsilon=T(0))
T sin(const AngleRadianBase< T > &a)
MatT orthogonalize(const MatT &mat, const Axis axis)
T abs(const T &a)
VecBase< T, 2 > interpolate_dot_slerp(const T t, const T cosom)
MatT from_rotation(const RotationT &rotation)
DualQuaternionBase< T > to_dual_quaternion(const MatBase< T, 4, 4 > &mat, const MatBase< T, 4, 4 > &basemat)
Euler3Base< T > to_euler(const AxisAngleBase< T, AngleT > &axis_angle, EulerOrder order)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
const btScalar eps
Definition poly34.cpp:11
VecBase< T, 3 > yzw() const
static AngleCartesianBase from_point(const T &x, const T &y)
DualQuaternionBase & operator*=(const T &t)
DualQuaternionBase & operator+=(const DualQuaternionBase &b)
const VecBase< T, 3 > & imaginary_part() const
QuaternionBase swing(const Axis axis) const
AngleRadianBase< T > twist_angle(const Axis axis) const
QuaternionBase twist(const Axis axis) const
QuaternionBase wrapped_around(const QuaternionBase &reference) const
ccl_device_inline int abs(int x)
Definition util/math.h:120
CCL_NAMESPACE_BEGIN struct Window V