GCC Code Coverage Report


./
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
39 of 54, 0 excluded
72.2%
Functions:
4 of 4, 0 excluded
100.0%
Branches:
28 of 63, 0 excluded
44.4%

libs/base/src/eu/base/transform.cc
Line Branch Exec Source
1 #include "eu/base/transform.h"
2
3 #include <cmath>
4 #include <algorithm>
5
6 namespace eu
7 {
8 namespace
9 {
10 template <typename T, size_t array_size>
11 58 size_t argmax(const std::array<T, array_size>& array)
12 {
13
1/6
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 13 taken 58 times.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 13 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 25 not taken.
58 ASSERT(array.empty() == false);
14 116 return std::distance(array.begin(), std::max_element(array.begin(), array.end()));
15 }
16
17 /// Implements the "Shepperd's method" as described in
18 /// "3-D Computer Graphics A Mathematical Introduction with OpenGL" by Samuel R. Buss (2022)
19 /// in section XII 3.6 Quaternion and rotation matrix conversions on page 465
20 Q
21 58 quat_from_rotation_matrix(const m4& m)
22 {
23 58 const auto m11 = m.get(0, 0);
24 58 const auto m22 = m.get(1, 1);
25 58 const auto m33 = m.get(2, 2);
26
27 // aka trace
28 58 const auto m00 = m11 + m22 + m33;
29
30
3/7
✓ Branch 5 → 6 taken 58 times.
✗ Branch 5 → 56 not taken.
✓ Branch 6 → 7 taken 57 times.
✗ Branch 6 → 18 not taken.
✓ Branch 6 → 29 taken 1 time.
✗ Branch 6 → 40 not taken.
✗ Branch 6 → 51 not taken.
58 switch (argmax(std::array{ m00, m11, m22, m33 }))
31 {
32 57 case 0:
33 {
34 57 const auto d = 0.5f * std::sqrt(m00 + 1.0f);
35
36 57 const auto a = (m.get1(3, 2) - m.get1(2, 3)) / (4.0f * d);
37 57 const auto b = (m.get1(1, 3) - m.get1(3, 1)) / (4.0f * d);
38 57 const auto c = (m.get1(2, 1) - m.get1(1, 2)) / (4.0f * d);
39
40 57 return Q{ d, {a, b, c} };
41 }
42 ✗ case 1:
43 {
44 ✗ const auto a = 0.5f * std::sqrt(2.0f * m11 - m00 + 1.0f);
45
46 ✗ const auto d = (m.get1(3, 2) - m.get1(2, 3)) / (4.0f * a);
47 ✗ const auto b = (m.get1(2, 1) + m.get1(1, 2)) / (4.0f * a);
48 ✗ const auto c = (m.get1(1, 3) + m.get1(3, 1)) / (4.0f * a);
49
50 ✗ return Q{ d, {a, b, c} };
51 }
52 1 case 2:
53 {
54 1 const auto b = 0.5f * std::sqrt(2.0f * m22 - m00 + 1.0f);
55
56 1 const auto d = (m.get1(1, 3) - m.get1(3, 1)) / (4.0f * b);
57 1 const auto a = (m.get1(2, 1) + m.get1(1, 2)) / (4.0f * b);
58 1 const auto c = (m.get1(3, 2) + m.get1(2, 3)) / (4.0f * b);
59
60 1 return Q{ d, {a, b, c} };
61 }
62 ✗ case 3:
63 {
64 ✗ const auto c = 0.5f * std::sqrt(2.0f * m33 - m00 + 1.0f);
65
66 ✗ const auto d = (m.get1(2, 1) - m.get1(1, 2)) / (4.0f * c);
67 ✗ const auto a = (m.get1(1, 3) + m.get1(3, 1)) / (4.0f * c);
68 ✗ const auto b = (m.get1(3, 2) + m.get1(2, 3)) / (4.0f * c);
69
70 ✗ return Q{ d, {a, b, c} };
71 }
72 ✗ default:
73 ✗ DIE("shouldn't happen!!!");
74 ✗ return q_identity;
75 }
76 }
77 }
78
79
80 Transform
81 58 transform_from_matrix(const m4& m)
82 {
83 // heavily inspired by DecomposeMatrixToComponents from imguizmo
84
2/4
✓ Branch 2 → 3 taken 58 times.
✗ Branch 2 → 24 not taken.
✓ Branch 3 → 4 taken 58 times.
✗ Branch 3 → 24 not taken.
58 const auto right = m.get_column(0).to_vec3(0.0f);
85
2/4
✓ Branch 4 → 5 taken 58 times.
✗ Branch 4 → 25 not taken.
✓ Branch 5 → 6 taken 58 times.
✗ Branch 5 → 25 not taken.
58 const auto up = m.get_column(1).to_vec3(0.0f);
86
2/4
✓ Branch 6 → 7 taken 58 times.
✗ Branch 6 → 26 not taken.
✓ Branch 7 → 8 taken 58 times.
✗ Branch 7 → 26 not taken.
58 const auto out = m.get_column(2).to_vec3(0.0f);
87
88 const auto scale = v3
89 {
90 right.get_length(),
91 up.get_length(),
92 out.get_length()
93
3/6
✓ Branch 8 → 9 taken 58 times.
✗ Branch 8 → 31 not taken.
✓ Branch 9 → 10 taken 58 times.
✗ Branch 9 → 31 not taken.
✓ Branch 10 → 11 taken 58 times.
✗ Branch 10 → 31 not taken.
58 };
94
95 // orthonormalize the basis to drop the scale
96
1/2
✓ Branch 12 → 13 taken 58 times.
✗ Branch 12 → 27 not taken.
58 const auto normalized_right = right.get_normalized().value_or(kk::right);
97
1/2
✓ Branch 14 → 15 taken 58 times.
✗ Branch 14 → 28 not taken.
58 const auto normalized_up = up.get_normalized().value_or(kk::up);
98
1/2
✓ Branch 16 → 17 taken 58 times.
✗ Branch 16 → 29 not taken.
58 const auto normalized_out = out.get_normalized().value_or(kk::out);
99
100
1/2
✓ Branch 18 → 19 taken 58 times.
✗ Branch 18 → 31 not taken.
58 const auto rotation_matrix = m4::from_basis(normalized_right, normalized_up, normalized_out);
101
102 return
103 {
104
1/2
✓ Branch 19 → 20 taken 58 times.
✗ Branch 19 → 31 not taken.
58 .position = m.get_translation(),
105
2/4
✓ Branch 20 → 21 taken 58 times.
✗ Branch 20 → 30 not taken.
✓ Branch 21 → 22 taken 58 times.
✗ Branch 21 → 30 not taken.
58 .rotation = quat_from_rotation_matrix(rotation_matrix).get_normalized(),
106 .scale = scale
107 58 };
108 }
109
110
111 m4
112 113 matrix_from_transform(const Transform& t)
113 {
114 // heavily inspired by RecomposeMatrixFromComponents from imguizmo
115
116 const auto rotation = m4::from_basis
117
1/2
✓ Branch 5 → 6 taken 113 times.
✗ Branch 5 → 13 not taken.
113 (
118
1/2
✓ Branch 4 → 5 taken 113 times.
✗ Branch 4 → 13 not taken.
113 t.rotation.get_local_right(),
119
1/2
✓ Branch 3 → 4 taken 113 times.
✗ Branch 3 → 14 not taken.
113 t.rotation.get_local_up(),
120
1/2
✓ Branch 2 → 3 taken 113 times.
✗ Branch 2 → 15 not taken.
113 t.rotation.get_local_out()
121 );
122
123
4/8
✓ Branch 6 → 7 taken 113 times.
✗ Branch 6 → 18 not taken.
✓ Branch 7 → 8 taken 113 times.
✗ Branch 7 → 16 not taken.
✓ Branch 8 → 9 taken 113 times.
✗ Branch 8 → 16 not taken.
✓ Branch 9 → 10 taken 113 times.
✗ Branch 9 → 16 not taken.
113 return m4::from_translation(t.position) * rotation * m4::from_scale(t.scale);
124 }
125 }
126