5#include "testing/testing.h"
21 float in_quat[4] = {
w,
x,
y,
z};
22 float norm_quat[4], matrix[3][3], out_quat[4];
33 EXPECT_V4_NEAR(norm_quat, out_quat, FLT_EPSILON);
36TEST(math_rotation, quat_to_mat_to_quat_rot180)
44TEST(math_rotation, quat_to_mat_to_quat_rot180n)
52TEST(math_rotation, quat_to_mat_to_quat_rot90)
54 const float s2 = 1 /
sqrtf(2);
63TEST(math_rotation, quat_to_mat_to_quat_rot90n)
65 const float s2 = 1 /
sqrtf(2);
74TEST(math_rotation, quat_to_mat_to_quat_bad_T83196)
83TEST(math_rotation, quat_to_mat_to_quat_bad_negative)
89TEST(math_rotation, quat_to_mat_to_quat_near_1000)
103TEST(math_rotation, quat_to_mat_to_quat_near_0100)
117TEST(math_rotation, quat_to_mat_to_quat_near_0010)
131TEST(math_rotation, quat_to_mat_to_quat_near_0001)
146TEST(math_rotation, quat_to_mat_to_quat_zeroed_matrix)
148 float matrix_zeroed[3][3] = {{0.0f}};
149 float matrix_result[3][3];
150 float matrix_unit[3][3];
157 EXPECT_M3_NEAR(matrix_unit, matrix_result, FLT_EPSILON);
160TEST(math_rotation, quat_split_swing_and_twist_negative)
162 const float input[4] = {-0.5f, 0,
sqrtf(3) / 2, 0};
163 const float expected_swing[4] = {1.0f, 0, 0, 0};
164 const float expected_twist[4] = {0.5f, 0, -
sqrtf(3) / 2, 0};
165 float swing[4], twist[4];
169 EXPECT_NEAR(twist_angle, -
M_PI * 2 / 3, FLT_EPSILON);
170 EXPECT_V4_NEAR(swing, expected_swing, FLT_EPSILON);
171 EXPECT_V4_NEAR(twist, expected_twist, FLT_EPSILON);
174TEST(math_rotation, mat3_normalized_to_quat_fast_degenerate)
180 const float input[3][3] = {
181 {1.0000000000, -0.0000006315, -0.0000000027},
182 {0.0000009365, 1.0000000000, -0.0000000307},
183 {0.0000001964, 0.2103530765, 0.9776254892},
185 const float expect_quat[4] = {
187 -0.052810292690992355,
188 4.9985139582986449e-08,
189 -3.93654971730939e-07,
191 ASSERT_FLOAT_EQ(1.0f,
dot_qtqt(expect_quat, expect_quat))
192 <<
"expected quaternion should be normal";
194 float actual_quat[4];
196 EXPECT_FLOAT_EQ(1.0f,
dot_qtqt(actual_quat, actual_quat));
197 EXPECT_V4_NEAR(expect_quat, actual_quat, FLT_EPSILON);
206 for (
int i = 0;
i < range;
i++) {
210 const float sin_cos_test_fl[2] = {
sinf(phi),
cosf(phi)};
211 EXPECT_V2_NEAR(sin_cos_fl, sin_cos_test_fl, expected_eps);
216TEST(math_rotation, sin_cos_from_fraction_accuracy)
218 for (
int range = 1; range <= 64; range++) {
231 } multiple_of = (range & 1) ? MULTIPLE_OF_1 : ((range & 3) ? MULTIPLE_OF_2 : MULTIPLE_OF_4);
235 for (
int i = 0;
i < range;
i++) {
238 switch (multiple_of) {
239 case MULTIPLE_OF_1: {
240 sin_cos_fl[0] =
fabsf(sin_cos_fl[0]);
243 case MULTIPLE_OF_2: {
244 sin_cos_fl[0] =
fabsf(sin_cos_fl[0]);
245 sin_cos_fl[1] =
fabsf(sin_cos_fl[1]);
248 case MULTIPLE_OF_4: {
249 sin_cos_fl[0] =
fabsf(sin_cos_fl[0]);
250 sin_cos_fl[1] =
fabsf(sin_cos_fl[1]);
251 if (sin_cos_fl[0] > sin_cos_fl[1]) {
252 std::swap(sin_cos_fl[0], sin_cos_fl[1]);
261 float delta = b[0] - a[0];
267 int unique_coords_count = 1;
270 for (
int i = 1;
i < range; i_prev =
i++) {
271 if (coords[i_prev] != coords[
i]) {
272 unique_coords_count += 1;
276 switch (multiple_of) {
277 case MULTIPLE_OF_1: {
278 EXPECT_EQ(unique_coords_count, (range / 2) + 1);
281 case MULTIPLE_OF_2: {
282 EXPECT_EQ(unique_coords_count, (range / 4) + 1);
285 case MULTIPLE_OF_4: {
286 EXPECT_EQ(unique_coords_count, (range / 8) + 1);
292TEST(math_rotation, sin_cos_from_fraction_symmetry)
294 for (
int range = 1; range <= 64; range++) {
303TEST(math_rotation, DefaultConstructor)
317TEST(math_rotation, RotateDirectionAroundAxis)
320 EXPECT_NEAR(a.x, 0.0f, FLT_EPSILON);
321 EXPECT_NEAR(a.y, 1.0f, FLT_EPSILON);
322 EXPECT_NEAR(a.z, 0.0f, FLT_EPSILON);
324 EXPECT_NEAR(
b.x, -1.0f, FLT_EPSILON);
325 EXPECT_NEAR(
b.y, 0.0f, FLT_EPSILON);
326 EXPECT_NEAR(
b.z, 0.0f, FLT_EPSILON);
328 EXPECT_NEAR(c.x, 0.0f, FLT_EPSILON);
329 EXPECT_NEAR(c.y, 0.0f, FLT_EPSILON);
330 EXPECT_NEAR(c.z, 1.0f, FLT_EPSILON);
333TEST(math_rotation, AxisAngleConstructors)
336 EXPECT_V3_NEAR(a.axis(),
float3(0, 0, 1), 1
e-4);
337 EXPECT_NEAR(
float(a.angle()),
M_PI_2, 1
e-4);
338 EXPECT_NEAR(
sin(a.angle()), 1.0f, 1
e-4);
339 EXPECT_NEAR(
cos(a.angle()), 0.0f, 1
e-4);
342 EXPECT_V3_NEAR(
b.axis(),
float3(0, 0, 1), 1
e-4);
343 EXPECT_NEAR(
float(
b.angle()),
M_PI_2, 1
e-4);
344 EXPECT_NEAR(
b.angle().sin(), 1.0f, 1
e-4);
345 EXPECT_NEAR(
b.angle().cos(), 0.0f, 1
e-4);
351 AxisAngle c({1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f});
352 EXPECT_V3_NEAR(c.axis(),
float3(0, 0, 1), 1
e-4);
353 EXPECT_NEAR(
float(c.angle()),
M_PI_2, 1
e-4);
355 AxisAngle d({1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f});
356 EXPECT_V3_NEAR(d.axis(),
float3(0, 0, -1), 1
e-4);
357 EXPECT_NEAR(
float(d.angle()),
M_PI_2, 1
e-4);
360TEST(math_rotation, QuaternionDot)
367TEST(math_rotation, QuaternionConjugate)
373TEST(math_rotation, QuaternionNormalize)
377 float4(0.1825741827, 0.3651483654, 0.5477225780, 0.7302967309),
381TEST(math_rotation, QuaternionInvert)
384 EXPECT_V4_NEAR(
float4(
invert(q1)),
float4(0.0333333f, -0.0666667f, -0.1f, -0.133333f), 1e-4f);
386 Quaternion q2(0.927091f, 0.211322f, -0.124857f, 0.283295f);
388 EXPECT_V4_NEAR(
float4(
result),
float4(0.927091f, -0.211322f, 0.124857f, -0.283295f), 1e-4f);
391TEST(math_rotation, QuaternionCanonicalize)
394 float4(0.5f, 2.0f, 3.0f, 4.0f),
397 float4(0.5f, -2.0f, -3.0f, -4.0f),
401TEST(math_rotation, QuaternionAngleBetween)
406 EXPECT_V4_NEAR(
float4(q3),
float4(-0.394478f, 0.00330195f, 0.284119f, -0.873872f), 1e-4f);
407 EXPECT_NEAR(
float(
angle_of(q1)), 0.76844f, 1e-4f);
408 EXPECT_NEAR(
float(
angle_of(q2)), 3.30854f, 1e-4f);
409 EXPECT_NEAR(
float(
angle_of(q3)), 3.95259f, 1e-4f);
417TEST(math_rotation, QuaternionPower)
440TEST(math_rotation, QuaternionFromTriangle)
442 float3 v1(0.927091f, 0.211322f, -0.124857f);
443 float3 v2(-0.051681f, 0.498261f, -0.86146f);
444 float3 v3(0.211322f, -0.124857f, 0.283295f);
446 float4(0.255566f, -0.213799f, 0.454253f, 0.826214f),
449 float4(0.103802f, 0.295067f, -0.812945f, 0.491204f),
453TEST(math_rotation, QuaternionFromVector)
455 float3 v1(0.927091f, 0.211322f, -0.124857f);
456 float3 v2(-0.051681f, 0.498261f, -0.86146f);
458 float4(0.129047, 0, -0.50443, -0.853755),
461 float4(0.12474, 0.0330631, -0.706333, -0.696017),
464 float4(0.111583, -0.0648251, -0.00729451, -0.991612),
467 float4(0.476074, 0.580363, -0.403954, 0.522832),
470 float4(0.62436, 0.104259, 0, 0.774148),
473 float4(0.622274, 0.0406802, 0.0509963, 0.780077),
476 float4(0.747014, 0.0737433, -0.655337, 0.0840594),
479 float4(0.751728, 0.146562, -0.642981, 0),
482 float4(0.751728, 0.146562, -0.642981, 0),
485 float4(0.991638, 0, 0.0656442, 0.111104),
488 float4(0.706333, 0.696017, 0.12474, 0.0330631),
491 float4(0.991612, -0.0072946, 0.0648251, 0.111583),
494 float4(0.580363, -0.476074, -0.522832, -0.403954),
497 float4(0.781137, -0.083334, 0, -0.618774),
500 float4(0.780077, -0.0509963, 0.0406802, -0.622274),
503 float4(0.0737433, -0.747014, -0.0840594, -0.655337),
506 float4(0.659473, -0.167065, 0.732929, 0),
509 float4(0.659473, -0.167065, 0.732929, 0),
513 float4(0.725211, 0, -0.596013, -0.344729),
516 float4(0.691325, 0.219092, -0.672309, -0.148561),
519 float4(0.643761, -0.333919, -0.370346, -0.580442),
522 float4(0.320473, 0.593889, 0.383792, 0.630315),
525 float4(0.499999, 0.864472, 0, -0.0518617),
528 float4(0.0447733, 0.0257574, -0.49799, -0.865643),
531 float4(0.646551, 0.193334, -0.174318, 0.717082),
534 float4(0.965523, 0.258928, 0.0268567, 0),
537 float4(0.965523, 0.258928, 0.0268567, 0),
540 float4(0.688527, 0, 0.627768, 0.363095),
543 float4(0.672309, 0.148561, 0.691325, 0.219092),
546 float4(0.580442, -0.370345, 0.333919, 0.643761),
549 float4(0.593889, -0.320473, -0.630315, 0.383792),
552 float4(0.866026, -0.499102, 0, 0.0299423),
555 float4(0.865643, -0.49799, -0.0257574, 0.0447733),
558 float4(0.193334, -0.646551, -0.717082, -0.174318),
561 float4(0.260317, -0.960371, -0.0996123, 0),
564 float4(0.260317, -0.960371, -0.0996123, 0),
568TEST(math_rotation, QuaternionWrappedAround)
578TEST(math_rotation, QuaternionFromTracking)
585 if (forward_axis.
axis() == up_axis) {
603TEST(math_rotation, EulerWrappedAround)
611TEST(math_rotation, Euler3ToGimbal)
614 float3 ijk{0.350041, -0.358896, 0.528994};
623 float3x3({0.808309, -0.504665, 0}, {0.47251, 0.863315, 0}, {0.351241, 0, 1}));
625 float3x3({0.808309, 0, -0.351241}, {0.504665, 1, -0}, {0.303232, 0, 0.936285}));
627 float3x3({0.863315, -0.474062, 0}, {0.504665, 0.810963, 0}, {-0, 0.342936, 1}));
629 float3x3({1, -0.504665, 0}, {0, 0.810963, -0.342936}, {0, 0.296062, 0.939359}));
631 float3x3({0.936285, 0, -0.329941}, {0, 1, -0.342936}, {0.351241, 0, 0.879508}));
633 float3x3({1, -0, -0.351241}, {0, 0.939359, -0.321086}, {0, 0.342936, 0.879508}));
654 if ((
abs(src_forward) ==
abs(src_up)) || (
abs(dst_forward) ==
abs(dst_up))) {
660 if (src_forward == dst_forward && src_up == dst_up) {
676 if (src_forward == dst_forward) {
687 float3 point(1.0f, 2.0f, 3.0f);
699 Quaternion q(0.927091f, 0.211322f, -0.124857f, 0.283295f);
701 float3 p(0.576f, -0.6546f, 46.354f);
703 EXPECT_V3_NEAR(
result,
float3(-4.33722f, -21.661f, 40.7608f), 1e-4f);
706 float3 p2(1.0f, 2.0f, 3.0f);
721TEST(math_rotation, DualQuaternionNormalize)
735 EXPECT_V4_NEAR(
float4(
sum.trans), (
float4(0.777778, 0.666667, 0.444444, 0.666667) /
len), 1e-4f);
741TEST(math_rotation, DualQuaternionFromMatrix)
745 {-1.28264, 2.87361, 0.0230992, 12.8871},
746 {3.27343, 0.812993, -0.895575, -13.5216},
749 {0.16104, -0.406549, 0.899324, 22.8871},
750 {0.981987, -0.0252451, -0.187255, -3.52155},
753 {-0.445021, 2.97151, -0.250095, -42.5586},
754 {0.146173, 0.473002, 1.62645, -9.75092},
758 EXPECT_V4_NEAR(
float4(dq.
quat),
float4(0.502368, 0.0543716, -0.854483, -0.120535), 1e-4f);
759 EXPECT_V4_NEAR(
float4(dq.
trans),
float4(22.674, -0.878616, 11.2762, 14.167), 1e-4f);
760 EXPECT_M4_NEAR(dq.
scale, expected_scale_mat, 1e-4f);
766 {-1.04583, -0.150756, -0.385074, -22.2225},
767 {-0.123402, 2.32698, 1.66357, 5.397},
770 {-0.271734, 0.421514, -0.865151, -12.2225},
771 {-0.960477, -0.0623834, 0.27128, 15.397},
774 {0.971507, -0.382422, 1.09917, -69.5943},
775 {-0.331274, 0.8794, 2.67787, -2.88715},
779 EXPECT_V4_NEAR(
float4(dq.
quat),
float4(0.149898, -0.319339, -0.0441496, -0.934668), 1e-4f);
780 EXPECT_V4_NEAR(
float4(dq.
trans),
float4(-2.20019, 39.6236, 49.052, -16.2077), 1e-4f);
781 EXPECT_M4_NEAR(dq.
scale, expected_scale_mat, 1e-4f);
787 for (
int i = 0;
i < 1000;
i++) {
788 auto frand = []() {
return (std::rand() - RAND_MAX / 2) /
float(RAND_MAX); };
794 mat.
location() + 10,
EulerXYZ{frand() * 10.0f, frand() * 10.0f, frand() * 10.0f});
802 EXPECT_M4_NEAR(dq.
scale, expect.
scale, 2e-4f);
808TEST(math_rotation, DualQuaternionTransform)
812 {-0.445021, 2.97151, -0.250095, -42.5586},
813 {0.146173, 0.473002, 1.62645, -9.75092},
817 {22.674, -0.878616, 11.2762, 14.167},
820 float3 p0{51.0f, 1647.0f, 12.0f};
821 float3 p1{58.0f, 0.0054f, 10.0f};
822 float3 p2{0.0f, 7854.0f, 111.0f};
837 {-1.28264, 2.87361, 0.0230978},
838 {3.27343, 0.812991, -0.895574}))};
840 EXPECT_V3_NEAR(p0_result, p0_expect, 1e-2f);
841 EXPECT_V3_NEAR(p1_result, p1_expect, 1e-2f);
842 EXPECT_V3_NEAR(p2_result, p2_expect, 1e-2f);
843 EXPECT_M3_NEAR(crazy_space_mat, expected_crazy_space_mat, 1e-4f);
847 {0.971507, -0.382422, 1.09917, -69.5943},
848 {-0.331274, 0.8794, 2.67787, -2.88715},
852 {-2.20019, 39.6236, 49.052, -16.207},
855 float3 p0{51.0f, 1647.0f, 12.0f};
856 float3 p1{58.0f, 0.0054f, 10.0f};
857 float3 p2{0.0f, 7854.0f, 111.0f};
872 {-1.04583, -0.150754, -0.385079},
873 {-0.123401, 2.32698, 1.66357}))};
875 EXPECT_V3_NEAR(p0_result,
float3(-2591.83, -328.472, 3851.6), 1e-2f);
876 EXPECT_V3_NEAR(p1_result,
float3(46.6121, -86.7318, 14.8882), 1e-2f);
877 EXPECT_V3_NEAR(p2_result,
float3(-12309.5, -1248.99, 18466.1), 6e-2f);
878 EXPECT_M3_NEAR(crazy_space_mat, expected_crazy_space_mat, 1e-4f);
882TEST(math_axis_angle, AxisAngleFromQuaternion)
888 EXPECT_V3_NEAR(axis_angle.axis(), from_quaternion.axis(), 1
e-6);
889 EXPECT_NEAR(axis_angle.angle().radian(), from_quaternion.angle().radian(), 1
e-6);
895 EXPECT_V3_NEAR(axis_angle.axis(), from_quaternion.axis(), 1
e-6);
896 EXPECT_NEAR(axis_angle.angle().radian(), from_quaternion.angle().radian(), 1
e-6);
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
void unit_m3(float m[3][3])
void quat_to_mat3(float m[3][3], const float q[4])
void sin_cos_from_fraction(int numerator, int denominator, float *r_sin, float *r_cos)
void mul_qt_fl(float q[4], float f)
float normalize_qt_qt(float r[4], const float q[4])
float dot_qtqt(const float a[4], const float b[4])
float quat_split_swing_and_twist(const float q_in[4], int axis, float r_swing[4], float r_twist[4])
void mat4_to_dquat(DualQuat *dq, const float basemat[4][4], const float mat[4][4])
bool mat3_from_axis_conversion(int src_forward, int src_up, int dst_forward, int dst_up, float r_mat[3][3])
void mul_v3m3_dq(float r[3], float R[3][3], DualQuat *dq)
void quat_apply_track(float quat[4], short axis, short upflag)
void mat3_normalized_to_quat_fast(float q[4], const float mat[3][3])
void mat3_normalized_to_quat(float q[4], const float mat[3][3])
bool mat3_from_axis_conversion_single(int src_axis, int dst_axis, float r_mat[3][3])
TEST(math_rotation, quat_to_mat_to_quat_rot180)
static void test_sin_cos_from_fraction_accuracy(const int range, const float expected_eps)
static void test_quat_to_mat_to_quat(float w, float x, float y, float z)
static void test_sin_cos_from_fraction_symmetry(const int range)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
static T sum(const btAlignedObjectArray< T > &items)
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
void append_unchecked(const T &value)
void reserve(const int64_t min_capacity)
constexpr int as_int() const
static constexpr Value Z_POS
static constexpr Value Y_NEG
static constexpr Value Z_NEG
static constexpr AxisSigned from_int(int axis_int)
static constexpr Value X_NEG
static constexpr Value Y_POS
static constexpr Value X_POS
constexpr Axis axis() const
constexpr int as_int() const
static constexpr Axis from_int(const int axis_int)
VecBase< float, D > normalize(VecOp< float, D >) RET
MatBase< R, C > transpose(MatBase< C, R >) RET
TEST(math_rotation, DefaultConstructor)
AngleCartesianBase< float > AngleCartesian
QuaternionBase< T > from_triangle(const VecBase< T, 3 > &v1, const VecBase< T, 3 > &v2, const VecBase< T, 3 > &v3, const VecBase< T, 3 > &normal)
AngleRadianBase< float > AngleRadian
QuaternionBase< T > conjugate(const QuaternionBase< T > &a)
QuaternionBase< float > Quaternion
T pow(const T &x, const T &power)
QuaternionBase< T > from_vector(const VecBase< T, 3 > &vector, const AxisSigned track_flag, const Axis up_flag)
QuaternionBase< T > to_quaternion(const AxisAngleBase< T, AngleT > &axis_angle)
CartesianBasis rotation_between(const CartesianBasis &a, const CartesianBasis &b)
AngleRadianBase< T > angle_between(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
MatT from_loc_rot(const typename MatT::loc_type &location, const RotationT &rotation)
AxisAngleBase< float, AngleRadianBase< float > > AxisAngle
AngleRadianBase< T > angle_between_signed(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
EulerXYZBase< float > EulerXYZ
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
MatBase< T, 3, 3 > to_gimbal_axis(const Euler3Base< T > &rotation)
CartesianBasis invert(const CartesianBasis &basis)
float3 rotate_direction_around_axis(const float3 &direction, const float3 &axis, float angle)
AngleRadianBase< T > angle_of(const QuaternionBase< T > &q)
DualQuaternionBase< float > DualQuaternion
QuaternionBase< T > invert_normalized(const QuaternionBase< T > &q)
AxisAngleBase< T, AngleT > to_axis_angle(const EulerXYZBase< T > &euler)
AxisAngleBase< float, AngleCartesianBase< float > > AxisAngleCartesian
QuaternionBase< T > canonicalize(const QuaternionBase< T > &q)
Euler3Base< float > Euler3
AngleRadianBase< T > angle_of_signed(const QuaternionBase< T > &q)
CartesianBasis from_orthonormal_axes(const AxisSigned forward, const AxisSigned up)
MatT from_rotation(const RotationT &rotation)
DualQuaternionBase< T > to_dual_quaternion(const MatBase< T, 4, 4 > &mat, const MatBase< T, 4, 4 > &basemat)
MatT from_loc_rot_scale(const typename MatT::loc_type &location, const RotationT &rotation, const VecBase< typename MatT::base_type, ScaleDim > &scale)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< float, 2 > float2
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
const c_style_mat & ptr() const
static MatBase identity()
const AngleT & angle() const
const vec3_type & axis() const
QuaternionBase< T > trans
EulerXYZBase wrapped_around(const EulerXYZBase &reference) const
static QuaternionBase identity()
QuaternionBase wrapped_around(const QuaternionBase &reference) const