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