Blender V4.3
BLI_math_rotation_types_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "testing/testing.h"
6
7#include "DNA_action_types.h"
8
9#include "BLI_math_rotation.h"
10#include "BLI_math_rotation.hh"
12
13namespace blender::tests {
14
15using namespace blender::math;
16
17TEST(math_rotation_types, AxisSignedCross)
18{
19 auto test_fn = [](AxisSigned a, AxisSigned b) {
21 };
22 EXPECT_TRUE(test_fn(AxisSigned::X_POS, AxisSigned::Y_POS));
23 EXPECT_TRUE(test_fn(AxisSigned::X_POS, AxisSigned::Z_POS));
24 EXPECT_TRUE(test_fn(AxisSigned::X_POS, AxisSigned::Y_NEG));
25 EXPECT_TRUE(test_fn(AxisSigned::X_POS, AxisSigned::Z_NEG));
26 EXPECT_TRUE(test_fn(AxisSigned::Y_POS, AxisSigned::X_POS));
27 EXPECT_TRUE(test_fn(AxisSigned::Y_POS, AxisSigned::Z_POS));
28 EXPECT_TRUE(test_fn(AxisSigned::Y_POS, AxisSigned::X_NEG));
29 EXPECT_TRUE(test_fn(AxisSigned::Y_POS, AxisSigned::Z_NEG));
30 EXPECT_TRUE(test_fn(AxisSigned::Z_POS, AxisSigned::X_POS));
31 EXPECT_TRUE(test_fn(AxisSigned::Z_POS, AxisSigned::Y_POS));
32 EXPECT_TRUE(test_fn(AxisSigned::Z_POS, AxisSigned::X_NEG));
33 EXPECT_TRUE(test_fn(AxisSigned::Z_POS, AxisSigned::Y_NEG));
34 EXPECT_TRUE(test_fn(AxisSigned::X_NEG, AxisSigned::Y_POS));
35 EXPECT_TRUE(test_fn(AxisSigned::X_NEG, AxisSigned::Z_POS));
36 EXPECT_TRUE(test_fn(AxisSigned::X_NEG, AxisSigned::Y_NEG));
37 EXPECT_TRUE(test_fn(AxisSigned::X_NEG, AxisSigned::Z_NEG));
38 EXPECT_TRUE(test_fn(AxisSigned::Y_NEG, AxisSigned::X_POS));
39 EXPECT_TRUE(test_fn(AxisSigned::Y_NEG, AxisSigned::Z_POS));
40 EXPECT_TRUE(test_fn(AxisSigned::Y_NEG, AxisSigned::X_NEG));
41 EXPECT_TRUE(test_fn(AxisSigned::Y_NEG, AxisSigned::Z_NEG));
42 EXPECT_TRUE(test_fn(AxisSigned::Z_NEG, AxisSigned::X_POS));
43 EXPECT_TRUE(test_fn(AxisSigned::Z_NEG, AxisSigned::Y_POS));
44 EXPECT_TRUE(test_fn(AxisSigned::Z_NEG, AxisSigned::X_NEG));
45 EXPECT_TRUE(test_fn(AxisSigned::Z_NEG, AxisSigned::Y_NEG));
46}
47
62
63TEST(math_rotation_types, AxisConvertToVec)
64{
68}
69
70TEST(math_rotation_types, Euler3Order)
71{
72 /* Asserts those match.
73 * Do not do it in the header to avoid including the DNA header everywhere.
74 */
75 BLI_STATIC_ASSERT(int(EulerOrder::XYZ) == int(eRotationModes::ROT_MODE_XYZ), "");
76 BLI_STATIC_ASSERT(int(EulerOrder::XZY) == int(eRotationModes::ROT_MODE_XZY), "");
77 BLI_STATIC_ASSERT(int(EulerOrder::YXZ) == int(eRotationModes::ROT_MODE_YXZ), "");
78 BLI_STATIC_ASSERT(int(EulerOrder::YZX) == int(eRotationModes::ROT_MODE_YZX), "");
79 BLI_STATIC_ASSERT(int(EulerOrder::ZXY) == int(eRotationModes::ROT_MODE_ZXY), "");
80 BLI_STATIC_ASSERT(int(EulerOrder::ZYX) == int(eRotationModes::ROT_MODE_ZYX), "");
81
82 EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::XYZ).ijk()), float3(0, 1, 2));
83 EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::XZY).ijk()), float3(0, 2, 1));
84 EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::YXZ).ijk()), float3(1, 0, 2));
85 EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::YZX).ijk()), float3(1, 2, 0));
86 EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::ZXY).ijk()), float3(2, 0, 1));
87 EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::ZYX).ijk()), float3(2, 1, 0));
88
89 EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::XYZ).xyz()), float3(0, 1, 2));
90 EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::XZY).xyz()), float3(0, 1, 2));
91 EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::YXZ).xyz()), float3(0, 1, 2));
92 EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::YZX).xyz()), float3(0, 1, 2));
93 EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::ZXY).xyz()), float3(0, 1, 2));
94 EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::ZYX).xyz()), float3(0, 1, 2));
95
96 EXPECT_EQ(float3(Euler3(EulerOrder::XYZ).ijk() = {0, 1, 2}), float3(0, 1, 2));
97 EXPECT_EQ(float3(Euler3(EulerOrder::XZY).ijk() = {0, 1, 2}), float3(0, 2, 1));
98 EXPECT_EQ(float3(Euler3(EulerOrder::YXZ).ijk() = {0, 1, 2}), float3(1, 0, 2));
99 EXPECT_EQ(float3(Euler3(EulerOrder::YZX).ijk() = {0, 1, 2}), float3(1, 2, 0));
100 EXPECT_EQ(float3(Euler3(EulerOrder::ZXY).ijk() = {0, 1, 2}), float3(2, 0, 1));
101 EXPECT_EQ(float3(Euler3(EulerOrder::ZYX).ijk() = {0, 1, 2}), float3(2, 1, 0));
102}
103
104TEST(math_rotation_types, DualQuaternionUniformScaleConstructor)
105{
109 EXPECT_EQ(q.scale_weight, 0.0f);
110 EXPECT_EQ(q.quat_weight, 1.0f);
111}
112
113TEST(math_rotation_types, DualQuaternionNonUniformScaleConstructor)
114{
119 EXPECT_EQ(q.scale_weight, 1.0f);
120 EXPECT_EQ(q.quat_weight, 1.0f);
121}
122
123TEST(math_rotation_types, DualQuaternionOperators)
124{
125 DualQuaternion sum = DualQuaternion(Quaternion(0, 0, 1, 0), Quaternion(0, 1, 0, 1)) * 2.0f;
126
127 EXPECT_EQ(sum.quat, Quaternion(0, 0, 2, 0));
128 EXPECT_EQ(sum.trans, Quaternion(0, 2, 0, 2));
129 EXPECT_EQ(sum.scale_weight, 0.0f);
130 EXPECT_EQ(sum.quat_weight, 2.0f);
131
132 sum += DualQuaternion(Quaternion(1, 0, 0, 0), Quaternion(1, 1, 1, 1), float4x4::identity()) *
133 4.0f;
134
135 EXPECT_EQ(sum.quat, Quaternion(4, 0, 2, 0));
136 EXPECT_EQ(sum.trans, Quaternion(4, 6, 4, 6));
137 EXPECT_EQ(sum.scale, float4x4::identity() * 4.0f);
138 EXPECT_EQ(sum.scale_weight, 4.0f);
139 EXPECT_EQ(sum.quat_weight, 6.0f);
140
141 sum += 3.0f *
142 DualQuaternion(Quaternion(1, 0, 0, 0), Quaternion(1, 0, 0, 0), float4x4::identity());
143
144 EXPECT_EQ(sum.quat, Quaternion(7, 0, 2, 0));
145 EXPECT_EQ(sum.trans, Quaternion(7, 6, 4, 6));
146 EXPECT_EQ(sum.scale, float4x4::identity() * 7.0f);
147 EXPECT_EQ(sum.scale_weight, 7.0f);
148 EXPECT_EQ(sum.quat_weight, 9.0f);
149}
150
151TEST(math_rotation_types, QuaternionDefaultConstructor)
152{
153 Quaternion q{};
154 EXPECT_EQ(q.w, 0.0f);
155 EXPECT_EQ(q.x, 0.0f);
156 EXPECT_EQ(q.y, 0.0f);
157 EXPECT_EQ(q.z, 0.0f);
158}
159
160TEST(math_rotation_types, QuaternionStaticConstructor)
161{
163 EXPECT_EQ(q.w, 1.0f);
164 EXPECT_EQ(q.x, 0.0f);
165 EXPECT_EQ(q.y, 0.0f);
166 EXPECT_EQ(q.z, 0.0f);
167}
168
169TEST(math_rotation_types, QuaternionVectorConstructor)
170{
171 Quaternion q{1.0f, 2.0f, 3.0f, 4.0f};
172 EXPECT_EQ(q.w, 1.0f);
173 EXPECT_EQ(q.x, 2.0f);
174 EXPECT_EQ(q.y, 3.0f);
175 EXPECT_EQ(q.z, 4.0f);
176}
177
178TEST(math_rotation_types, QuaternionProduct)
179{
180 Quaternion q1{1.0f, 2.0f, 3.0f, 4.0f};
181 Quaternion q2{3.0f, 4.0f, 5.0f, 6.0f};
182 Quaternion result = q1 * q2;
183 EXPECT_EQ(result.w, -44.0f);
184 EXPECT_EQ(result.x, 8.0f);
185 EXPECT_EQ(result.y, 18.0f);
186 EXPECT_EQ(result.z, 16.0f);
187
188 Quaternion result2 = q1 * 4.0f;
189 EXPECT_EQ(result2.w, 4.0f);
190 EXPECT_EQ(result2.x, 8.0f);
191 EXPECT_EQ(result2.y, 12.0f);
192 EXPECT_EQ(result2.z, 16.0f);
193}
194
195TEST(math_rotation_types, QuaternionUnaryMinus)
196{
197 Quaternion q{1.0f, 2.0f, 3.0f, 4.0f};
198 Quaternion result = -q;
199 EXPECT_EQ(result.w, -1.0f);
200 EXPECT_EQ(result.x, -2.0f);
201 EXPECT_EQ(result.y, -3.0f);
202 EXPECT_EQ(result.z, -4.0f);
203}
204
205TEST(math_rotation_types, QuaternionExpmap)
206{
207 Quaternion q(0.927091f, 0.211322f, -0.124857f, 0.283295f);
208 float3 expmap = normalize(q).expmap();
209 EXPECT_V3_NEAR(expmap, float3(0.433225f, -0.255966f, 0.580774f), 1e-4f);
210 EXPECT_V4_NEAR(float4(Quaternion::expmap(expmap)), float4(q), 1e-4f);
211}
212
213TEST(math_rotation_types, QuaternionTwistSwing)
214{
215 Quaternion q(0.927091f, 0.211322f, -0.124857f, 0.283295f);
216 EXPECT_NEAR(float(q.twist_angle(Axis::X)), 0.448224, 1e-4);
217 EXPECT_NEAR(float(q.twist_angle(Axis::Y)), -0.267741, 1e-4);
218 EXPECT_NEAR(float(q.twist_angle(Axis::Z)), 0.593126, 1e-4);
219
220 EXPECT_V4_NEAR(float4(q.twist(Axis::X)), float4(0.974992, 0.222241, 0, 0), 1e-4);
221 EXPECT_V4_NEAR(float4(q.twist(Axis::Y)), float4(0.991053, 0, -0.133471, 0), 1e-4);
222 EXPECT_V4_NEAR(float4(q.twist(Axis::Z)), float4(0.956347, 0, 0, 0.292235), 1e-4);
223 EXPECT_V4_NEAR(float4(q.swing(Axis::X)), float4(0.950871, 0, -0.184694, 0.248462), 1e-4);
224 EXPECT_V4_NEAR(float4(q.swing(Axis::Y)), float4(0.935461, 0.17162, 0, 0.308966), 1e-4);
225 EXPECT_V4_NEAR(float4(q.swing(Axis::Z)), float4(0.969409, 0.238585, -0.0576509, 0), 1e-4);
226 EXPECT_V4_NEAR(float4(q.swing(Axis::Z) * q.twist(Axis::Z)), float4(q), 1e-4);
227}
228
229TEST(math_rotation_types, AngleMethods)
230{
231 EXPECT_NEAR(float(AngleRadian(M_PI * -2.5).wrapped()), -M_PI * 0.5, 1e-4f);
232 EXPECT_NEAR(float(AngleRadian(M_PI * -1.5).wrapped()), M_PI * 0.5, 1e-4f);
233 EXPECT_NEAR(float(AngleRadian(M_PI * -0.5).wrapped()), -M_PI * 0.5, 1e-4f);
234 EXPECT_NEAR(float(AngleRadian(M_PI * 0.5).wrapped()), M_PI * 0.5, 1e-4f);
235 EXPECT_NEAR(float(AngleRadian(M_PI * 2.0).wrapped()), 0.0, 1e-4f);
236 EXPECT_NEAR(float(AngleRadian(M_PI * 2.5).wrapped()), M_PI * 0.5, 1e-4f);
237 EXPECT_NEAR(float(AngleRadian(M_PI * 1.5).wrapped()), M_PI * -0.5, 1e-4f);
238 EXPECT_NEAR(float(AngleRadian(M_PI * 0.5).wrapped_around(-M_PI)), -M_PI * 1.5, 1e-4f);
239 EXPECT_NEAR(float(AngleRadian(M_PI * 1.0).wrapped_around(M_PI * 0.5)), M_PI, 1e-4f);
240}
241
242TEST(math_rotation_types, AngleFraction)
243{
244 using T = float;
246 auto pi = AngleFraction::pi();
247 auto tau = AngleFraction::tau();
248 EXPECT_EQ(AngleFraction::identity().radian(), 0);
249 EXPECT_EQ(pi.radian(), T(M_PI));
250 EXPECT_EQ(tau.radian(), T(M_PI * 2));
251 /* Doesn't work with standard float angles. */
252 EXPECT_EQ((pi / 5 + pi * 4 / 5).radian(), T(M_PI));
253 EXPECT_EQ((pi * 2 / 3).radian(), T(M_PI * 2 / 3));
254 EXPECT_EQ(cos(pi * 2 / 3), cos(2 * pi + pi * 2 / 3));
255 EXPECT_EQ(sin(pi * 3 / 2), T(-1));
256 EXPECT_EQ(sin(pi * 1574051 / 2), T(-1));
257 EXPECT_EQ((-pi * 4 / 2).wrapped(), (+pi * 0 / 2));
258 EXPECT_EQ((-pi * 3 / 2).wrapped(), (+pi * 1 / 2));
259 EXPECT_EQ((-pi * 2 / 2).wrapped(), (-pi * 2 / 2));
260 EXPECT_EQ((-pi * 1 / 2).wrapped(), (-pi * 1 / 2));
261 EXPECT_EQ((+pi * 0 / 2).wrapped(), (+pi * 0 / 2));
262 EXPECT_EQ((+pi * 1 / 2).wrapped(), (+pi * 1 / 2));
263 EXPECT_EQ((+pi * 2 / 2).wrapped(), (+pi * 2 / 2));
264 EXPECT_EQ((+pi * 3 / 2).wrapped(), (-pi * 1 / 2));
265 EXPECT_EQ((+pi * 4 / 2).wrapped(), (-pi * 0 / 2));
266 EXPECT_EQ((+pi * 0 / 2).wrapped_around(pi), (+pi * 0 / 2));
267 EXPECT_EQ((+pi * 1 / 2).wrapped_around(pi), (+pi * 1 / 2));
268 EXPECT_EQ((+pi * 2 / 2).wrapped_around(pi), (+pi * 2 / 2));
269 EXPECT_EQ((+pi * 3 / 2).wrapped_around(pi), (+pi * 3 / 2));
270 EXPECT_EQ((+pi * 4 / 2).wrapped_around(pi), (+pi * 4 / 2));
271
272 for (int i = 0; i < 32; i++) {
273 AngleCartesian angle(+pi * i / 16);
274 EXPECT_NEAR(angle.cos(), cos((T(M_PI) * i) / 16), 1e-6f);
275 EXPECT_NEAR(angle.sin(), sin((T(M_PI) * i) / 16), 1e-6f);
276
277 /* Ensure symmetry. */
278 AngleCartesian angle_opposite(pi + pi * i / 16);
279 EXPECT_EQ(angle.cos(), -angle_opposite.cos());
280 EXPECT_EQ(angle.sin(), -angle_opposite.sin());
281
282 AngleCartesian angle_phase(pi / 2 + pi * i / 16);
283 EXPECT_EQ(angle.cos(), angle_phase.sin());
284 EXPECT_EQ(angle.sin(), -angle_phase.cos());
285
286 /* Ensure Periodicity. */
287 AngleCartesian angle_per(tau + pi * i / 16);
288 EXPECT_EQ(angle.cos(), angle_per.cos());
289 EXPECT_EQ(angle.sin(), angle_per.sin());
290 }
291 /* Ensure exact values. */
292 EXPECT_EQ(AngleCartesian(+pi * 0 / 2).cos(), +1.0f);
293 EXPECT_EQ(AngleCartesian(+pi * 1 / 2).cos(), +0.0f);
294 EXPECT_EQ(AngleCartesian(+pi * 2 / 2).cos(), -1.0f);
295 EXPECT_EQ(AngleCartesian(+pi * 3 / 2).cos(), +0.0f);
296 EXPECT_EQ(AngleCartesian(+pi * 4 / 2).cos(), +1.0f);
297
298 EXPECT_EQ(AngleCartesian(+pi * 0 / 2).sin(), +0.0f);
299 EXPECT_EQ(AngleCartesian(+pi * 1 / 2).sin(), +1.0f);
300 EXPECT_EQ(AngleCartesian(+pi * 2 / 2).sin(), +0.0f);
301 EXPECT_EQ(AngleCartesian(+pi * 3 / 2).sin(), -1.0f);
302 EXPECT_EQ(AngleCartesian(+pi * 4 / 2).sin(), +0.0f);
303
304 EXPECT_EQ(AngleCartesian(+pi * 1 / 4).cos(), T(M_SQRT1_2));
305 EXPECT_EQ(AngleCartesian(+pi * 3 / 4).cos(), T(-M_SQRT1_2));
306 EXPECT_EQ(AngleCartesian(-pi * 1 / 4).cos(), T(M_SQRT1_2));
307 EXPECT_EQ(AngleCartesian(-pi * 3 / 4).cos(), T(-M_SQRT1_2));
308
309 EXPECT_EQ(AngleCartesian(+pi * 1 / 4).sin(), T(M_SQRT1_2));
310 EXPECT_EQ(AngleCartesian(+pi * 3 / 4).sin(), T(M_SQRT1_2));
311 EXPECT_EQ(AngleCartesian(-pi * 1 / 4).sin(), T(-M_SQRT1_2));
312 EXPECT_EQ(AngleCartesian(-pi * 3 / 4).sin(), T(-M_SQRT1_2));
313}
314
315TEST(math_rotation_types, TypeConversion)
316{
317 /* All the same rotation. */
318 Quaternion quaternion(0.927091f, 0.211322f, -0.124857f, 0.283295f);
319 EulerXYZ euler_xyz(AngleRadian::from_degree(20.0559),
320 AngleRadian::from_degree(-20.5632f),
321 AngleRadian::from_degree(30.3091f));
322 AxisAngle axis_angle(normalize(float3{0.563771, -0.333098, 0.755783}),
323 AngleRadian::from_degree(44.0284f));
324
325 EXPECT_V4_NEAR(float4(to_quaternion(euler_xyz)), float4(quaternion), 1e-4);
326 EXPECT_V3_NEAR(to_axis_angle(euler_xyz).axis(), axis_angle.axis(), 1e-4);
327 EXPECT_NEAR(float(to_axis_angle(euler_xyz).angle()), float(axis_angle.angle()), 1e-4);
328
329 EXPECT_V3_NEAR(float3(to_euler(quaternion)), float3(euler_xyz), 1e-4);
330 EXPECT_V3_NEAR(to_axis_angle(quaternion).axis(), axis_angle.axis(), 1e-4);
331 EXPECT_NEAR(float(to_axis_angle(quaternion).angle()), float(axis_angle.angle()), 1e-4);
332
333 EXPECT_V3_NEAR(float3(to_euler(axis_angle)), float3(euler_xyz), 1e-4);
334 EXPECT_V4_NEAR(float4(to_quaternion(axis_angle)), float4(quaternion), 1e-4);
335}
336
337TEST(math_rotation_types, Euler3Conversion)
338{
339 /* All the same rotation. */
340 float3 xyz{0.350041, -0.358896, 0.528994};
341 Euler3 euler3_xyz(xyz, EulerOrder::XYZ);
342 Euler3 euler3_xzy(xyz, EulerOrder::XZY);
343 Euler3 euler3_yxz(xyz, EulerOrder::YXZ);
344 Euler3 euler3_yzx(xyz, EulerOrder::YZX);
345 Euler3 euler3_zxy(xyz, EulerOrder::ZXY);
346 Euler3 euler3_zyx(xyz, EulerOrder::ZYX);
347
348 Quaternion quat_xyz(0.927091f, 0.211322f, -0.124857f, 0.283295f);
349 Quaternion quat_xzy(0.943341f, 0.119427f, -0.124857f, 0.283295f);
350 Quaternion quat_yxz(0.943341f, 0.211322f, -0.124857f, 0.223297f);
351 Quaternion quat_yzx(0.927091f, 0.211322f, -0.214438f, 0.223297f);
352 Quaternion quat_zxy(0.927091f, 0.119427f, -0.214438f, 0.283295f);
353 Quaternion quat_zyx(0.943341f, 0.119427f, -0.214438f, 0.223297f);
354
355 float3x3 mat_xyz = transpose(float3x3{{0.80831, -0.57805, -0.111775},
356 {0.47251, 0.750174, -0.462572},
357 {0.35124, 0.321087, 0.879508}});
358 float3x3 mat_xzy = transpose(float3x3{{0.80831, -0.56431, -0.167899},
359 {0.504665, 0.810963, -0.296063},
360 {0.303231, 0.154577, 0.940296}});
361 float3x3 mat_yxz = transpose(float3x3{{0.869098, -0.474061, -0.14119},
362 {0.368521, 0.810963, -0.454458},
363 {0.329941, 0.342937, 0.879508}});
364 float3x3 mat_yzx = transpose(float3x3{{0.80831, -0.504665, -0.303231},
365 {0.323403, 0.810963, -0.487596},
366 {0.491982, 0.296063, 0.818719}});
367 float3x3 mat_zxy = transpose(float3x3{{0.747521, -0.576499, -0.329941},
368 {0.474061, 0.810963, -0.342937},
369 {0.465272, 0.0999405, 0.879508}});
370 float3x3 mat_zyx = transpose(float3x3{{0.80831, -0.47251, -0.35124},
371 {0.370072, 0.871751, -0.321087},
372 {0.457911, 0.129553, 0.879508}});
373
374 EXPECT_V4_NEAR(float4(to_quaternion(euler3_xyz)), float4(quat_xyz), 1e-4);
375 EXPECT_V4_NEAR(float4(to_quaternion(euler3_xzy)), float4(quat_xzy), 1e-4);
376 EXPECT_V4_NEAR(float4(to_quaternion(euler3_yxz)), float4(quat_yxz), 1e-4);
377 EXPECT_V4_NEAR(float4(to_quaternion(euler3_yzx)), float4(quat_yzx), 1e-4);
378 EXPECT_V4_NEAR(float4(to_quaternion(euler3_zxy)), float4(quat_zxy), 1e-4);
379 EXPECT_V4_NEAR(float4(to_quaternion(euler3_zyx)), float4(quat_zyx), 1e-4);
380
381 EXPECT_V3_NEAR(float3(to_euler(quat_xyz, EulerOrder::XYZ).xyz()), xyz, 1e-4);
382 EXPECT_V3_NEAR(float3(to_euler(quat_xzy, EulerOrder::XZY).xyz()), xyz, 1e-4);
383 EXPECT_V3_NEAR(float3(to_euler(quat_yxz, EulerOrder::YXZ).xyz()), xyz, 1e-4);
384 EXPECT_V3_NEAR(float3(to_euler(quat_yzx, EulerOrder::YZX).xyz()), xyz, 1e-4);
385 EXPECT_V3_NEAR(float3(to_euler(quat_zxy, EulerOrder::ZXY).xyz()), xyz, 1e-4);
386 EXPECT_V3_NEAR(float3(to_euler(quat_zyx, EulerOrder::ZYX).xyz()), xyz, 1e-4);
387
388 EXPECT_M3_NEAR(from_rotation<float3x3>(euler3_xyz), mat_xyz, 1e-4);
389 EXPECT_M3_NEAR(from_rotation<float3x3>(euler3_xzy), mat_xzy, 1e-4);
390 EXPECT_M3_NEAR(from_rotation<float3x3>(euler3_yxz), mat_yxz, 1e-4);
391 EXPECT_M3_NEAR(from_rotation<float3x3>(euler3_yzx), mat_yzx, 1e-4);
392 EXPECT_M3_NEAR(from_rotation<float3x3>(euler3_zxy), mat_zxy, 1e-4);
393 EXPECT_M3_NEAR(from_rotation<float3x3>(euler3_zyx), mat_zyx, 1e-4);
394
395 EXPECT_V3_NEAR(float3(to_euler(mat_xyz, EulerOrder::XYZ).xyz()), xyz, 1e-4);
396 EXPECT_V3_NEAR(float3(to_euler(mat_xzy, EulerOrder::XZY).xyz()), xyz, 1e-4);
397 EXPECT_V3_NEAR(float3(to_euler(mat_yxz, EulerOrder::YXZ).xyz()), xyz, 1e-4);
398 EXPECT_V3_NEAR(float3(to_euler(mat_yzx, EulerOrder::YZX).xyz()), xyz, 1e-4);
399 EXPECT_V3_NEAR(float3(to_euler(mat_zxy, EulerOrder::ZXY).xyz()), xyz, 1e-4);
400 EXPECT_V3_NEAR(float3(to_euler(mat_zyx, EulerOrder::ZYX).xyz()), xyz, 1e-4);
401
402 AxisAngle axis_angle_xyz = {normalize(float3{0.563771, -0.333098, 0.755783}), 0.76844f};
403 AxisAngle axis_angle_xzy = {normalize(float3{0.359907, -0.376274, 0.853747}), 0.676476f};
404 AxisAngle axis_angle_yxz = {normalize(float3{0.636846, -0.376274, 0.672937}), 0.676476f};
405 AxisAngle axis_angle_yzx = {normalize(float3{0.563771, -0.572084, 0.59572}), 0.76844f};
406 AxisAngle axis_angle_zxy = {normalize(float3{0.318609, -0.572084, 0.755783}), 0.76844f};
407 AxisAngle axis_angle_zyx = {normalize(float3{0.359907, -0.646237, 0.672937}), 0.676476f};
408
409 EXPECT_V3_NEAR(to_axis_angle(euler3_xyz).axis(), axis_angle_xyz.axis(), 1e-4);
410 EXPECT_V3_NEAR(to_axis_angle(euler3_xzy).axis(), axis_angle_xzy.axis(), 1e-4);
411 EXPECT_V3_NEAR(to_axis_angle(euler3_yxz).axis(), axis_angle_yxz.axis(), 1e-4);
412 EXPECT_V3_NEAR(to_axis_angle(euler3_yzx).axis(), axis_angle_yzx.axis(), 1e-4);
413 EXPECT_V3_NEAR(to_axis_angle(euler3_zxy).axis(), axis_angle_zxy.axis(), 1e-4);
414 EXPECT_V3_NEAR(to_axis_angle(euler3_zyx).axis(), axis_angle_zyx.axis(), 1e-4);
415
416 EXPECT_NEAR(float(to_axis_angle(euler3_xyz).angle()), float(axis_angle_xyz.angle()), 1e-4);
417 EXPECT_NEAR(float(to_axis_angle(euler3_xzy).angle()), float(axis_angle_xzy.angle()), 1e-4);
418 EXPECT_NEAR(float(to_axis_angle(euler3_yxz).angle()), float(axis_angle_yxz.angle()), 1e-4);
419 EXPECT_NEAR(float(to_axis_angle(euler3_yzx).angle()), float(axis_angle_yzx.angle()), 1e-4);
420 EXPECT_NEAR(float(to_axis_angle(euler3_zxy).angle()), float(axis_angle_zxy.angle()), 1e-4);
421 EXPECT_NEAR(float(to_axis_angle(euler3_zyx).angle()), float(axis_angle_zyx.angle()), 1e-4);
422
423 EXPECT_V3_NEAR(float3(to_euler(axis_angle_xyz, EulerOrder::XYZ).xyz()), xyz, 1e-4);
424 EXPECT_V3_NEAR(float3(to_euler(axis_angle_xzy, EulerOrder::XZY).xyz()), xyz, 1e-4);
425 EXPECT_V3_NEAR(float3(to_euler(axis_angle_yxz, EulerOrder::YXZ).xyz()), xyz, 1e-4);
426 EXPECT_V3_NEAR(float3(to_euler(axis_angle_yzx, EulerOrder::YZX).xyz()), xyz, 1e-4);
427 EXPECT_V3_NEAR(float3(to_euler(axis_angle_zxy, EulerOrder::ZXY).xyz()), xyz, 1e-4);
428 EXPECT_V3_NEAR(float3(to_euler(axis_angle_zyx, EulerOrder::ZYX).xyz()), xyz, 1e-4);
429}
430
431TEST(math_rotation_types, AngleSinCosOperators)
432{
434 EXPECT_NEAR((AngleCartesian(M_PI_2) + AngleCartesian(M_PI)).radian(),
435 AngleRadian(M_PI_2 + M_PI).wrapped().radian(),
436 1e-4);
437 EXPECT_NEAR((AngleCartesian(M_PI_2) - AngleCartesian(M_PI)).radian(),
438 AngleRadian(M_PI_2 - M_PI).wrapped().radian(),
439 1e-4);
440 EXPECT_NEAR((-AngleCartesian(M_PI_2)).radian(), AngleRadian(-M_PI_2).radian(), 1e-4);
441 EXPECT_NEAR((AngleCartesian(M_PI_4) * 2).radian(), AngleRadian(M_PI_4 * 2).radian(), 1e-4);
442 EXPECT_NEAR((AngleCartesian(M_PI_4) * 3).radian(), AngleRadian(M_PI_4 * 3).radian(), 1e-4);
443 EXPECT_NEAR((AngleCartesian(-M_PI_4) * 2).radian(), AngleRadian(-M_PI_4 * 2).radian(), 1e-4);
444 EXPECT_NEAR((AngleCartesian(-M_PI_4) * 3).radian(), AngleRadian(-M_PI_4 * 3).radian(), 1e-4);
445 EXPECT_NEAR((AngleCartesian(M_PI_4) / 2).radian(), AngleRadian(M_PI_4 / 2).radian(), 1e-4);
446 EXPECT_NEAR((AngleCartesian(-M_PI_4) / 2).radian(), AngleRadian(-M_PI_4 / 2).radian(), 1e-4);
447}
448
449} // namespace blender::tests
#define BLI_STATIC_ASSERT(a, msg)
Definition BLI_assert.h:87
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
#define M_PI_2
#define M_SQRT1_2
#define M_PI
#define M_PI_4
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
btMatrix3x3 transpose() const
Return the transpose of the matrix.
static T sum(const btAlignedObjectArray< T > &items)
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
static constexpr Value Z
static constexpr Value X
static constexpr Value Y
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
#define T
AngleCartesianBase< float > AngleCartesian
AngleRadianBase< float > AngleRadian
QuaternionBase< float > Quaternion
T cos(const AngleRadianBase< T > &a)
QuaternionBase< T > to_quaternion(const AxisAngleBase< T, AngleT > &axis_angle)
T to_vector(const Axis axis)
AxisSigned cross(const AxisSigned a, const AxisSigned b)
DualQuaternionBase< float > DualQuaternion
AxisAngleBase< T, AngleT > to_axis_angle(const EulerXYZBase< T > &euler)
T sin(const AngleRadianBase< T > &a)
Euler3Base< float > Euler3
MatT from_rotation(const RotationT &rotation)
Euler3Base< T > to_euler(const AxisAngleBase< T, AngleT > &axis_angle, EulerOrder order)
TEST(any, DefaultConstructor)
VecBase< float, 4 > float4
VecBase< float, 2 > float2
VecBase< float, 3 > float3
static AngleRadianBase from_degree(const T &degrees)
QuaternionBase swing(const Axis axis) const
AngleRadianBase< T > twist_angle(const Axis axis) const
QuaternionBase twist(const Axis axis) const