1 | // Copyright 2013 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | #include "flutter/fml/build_config.h" |
6 | |
7 | #if defined(OS_WIN) |
8 | #define _USE_MATH_DEFINES |
9 | #endif |
10 | #include <cmath> |
11 | |
12 | #include "flutter/flow/matrix_decomposition.h" |
13 | #include "gtest/gtest.h" |
14 | |
15 | namespace flutter { |
16 | namespace testing { |
17 | |
18 | TEST(MatrixDecomposition, Rotation) { |
19 | SkM44 matrix; |
20 | |
21 | const auto angle = M_PI_4; |
22 | matrix.setRotate({0.0, 0.0, 1.0}, angle); |
23 | |
24 | flutter::MatrixDecomposition decomposition(matrix); |
25 | ASSERT_TRUE(decomposition.IsValid()); |
26 | |
27 | const auto sine = sin(angle * 0.5); |
28 | |
29 | ASSERT_FLOAT_EQ(0, decomposition.rotation().x); |
30 | ASSERT_FLOAT_EQ(0, decomposition.rotation().y); |
31 | ASSERT_FLOAT_EQ(sine, decomposition.rotation().z); |
32 | ASSERT_FLOAT_EQ(cos(angle * 0.5), decomposition.rotation().w); |
33 | } |
34 | |
35 | TEST(MatrixDecomposition, Scale) { |
36 | SkM44 matrix; |
37 | |
38 | const auto scale = 5.0; |
39 | matrix.setScale(scale + 0, scale + 1, scale + 2); |
40 | |
41 | flutter::MatrixDecomposition decomposition(matrix); |
42 | ASSERT_TRUE(decomposition.IsValid()); |
43 | |
44 | ASSERT_FLOAT_EQ(scale + 0, decomposition.scale().x); |
45 | ASSERT_FLOAT_EQ(scale + 1, decomposition.scale().y); |
46 | ASSERT_FLOAT_EQ(scale + 2, decomposition.scale().z); |
47 | } |
48 | |
49 | TEST(MatrixDecomposition, Translate) { |
50 | SkM44 matrix; |
51 | |
52 | const auto translate = 125.0; |
53 | matrix.setTranslate(translate + 0, translate + 1, translate + 2); |
54 | |
55 | flutter::MatrixDecomposition decomposition(matrix); |
56 | ASSERT_TRUE(decomposition.IsValid()); |
57 | |
58 | ASSERT_FLOAT_EQ(translate + 0, decomposition.translation().x); |
59 | ASSERT_FLOAT_EQ(translate + 1, decomposition.translation().y); |
60 | ASSERT_FLOAT_EQ(translate + 2, decomposition.translation().z); |
61 | } |
62 | |
63 | TEST(MatrixDecomposition, Combination) { |
64 | const auto rotation = M_PI_4; |
65 | const auto scale = 5; |
66 | const auto translate = 125.0; |
67 | |
68 | SkM44 m1; |
69 | m1.setRotate({0, 0, 1}, rotation); |
70 | |
71 | SkM44 m2; |
72 | m2.setScale(scale, scale, scale); |
73 | |
74 | SkM44 m3; |
75 | m3.setTranslate(translate, translate, translate); |
76 | |
77 | SkM44 combined = m3 * m2 * m1; |
78 | |
79 | flutter::MatrixDecomposition decomposition(combined); |
80 | ASSERT_TRUE(decomposition.IsValid()); |
81 | |
82 | ASSERT_FLOAT_EQ(translate, decomposition.translation().x); |
83 | ASSERT_FLOAT_EQ(translate, decomposition.translation().y); |
84 | ASSERT_FLOAT_EQ(translate, decomposition.translation().z); |
85 | |
86 | ASSERT_FLOAT_EQ(scale, decomposition.scale().x); |
87 | ASSERT_FLOAT_EQ(scale, decomposition.scale().y); |
88 | ASSERT_FLOAT_EQ(scale, decomposition.scale().z); |
89 | |
90 | const auto sine = sin(rotation * 0.5); |
91 | |
92 | ASSERT_FLOAT_EQ(0, decomposition.rotation().x); |
93 | ASSERT_FLOAT_EQ(0, decomposition.rotation().y); |
94 | ASSERT_FLOAT_EQ(sine, decomposition.rotation().z); |
95 | ASSERT_FLOAT_EQ(cos(rotation * 0.5), decomposition.rotation().w); |
96 | } |
97 | |
98 | TEST(MatrixDecomposition, ScaleFloatError) { |
99 | constexpr float scale_increment = 0.00001f; |
100 | float scale = 0.0001f; |
101 | while (scale < 2.0f) { |
102 | SkM44 matrix; |
103 | matrix.setScale(scale, scale, 1.0f); |
104 | |
105 | flutter::MatrixDecomposition decomposition3(matrix); |
106 | ASSERT_TRUE(decomposition3.IsValid()); |
107 | |
108 | ASSERT_FLOAT_EQ(scale, decomposition3.scale().x); |
109 | ASSERT_FLOAT_EQ(scale, decomposition3.scale().y); |
110 | ASSERT_FLOAT_EQ(1.f, decomposition3.scale().z); |
111 | ASSERT_FLOAT_EQ(0, decomposition3.rotation().x); |
112 | ASSERT_FLOAT_EQ(0, decomposition3.rotation().y); |
113 | ASSERT_FLOAT_EQ(0, decomposition3.rotation().z); |
114 | scale += scale_increment; |
115 | } |
116 | |
117 | SkM44 matrix; |
118 | const auto scale1 = 1.7734375f; |
119 | matrix.setScale(scale1, scale1, 1.f); |
120 | |
121 | // Bug upper bound (empirical) |
122 | const auto scale2 = 1.773437559603f; |
123 | SkM44 matrix2; |
124 | matrix2.setScale(scale2, scale2, 1.f); |
125 | |
126 | // Bug lower bound (empirical) |
127 | const auto scale3 = 1.7734374403954f; |
128 | SkM44 matrix3; |
129 | matrix3.setScale(scale3, scale3, 1.f); |
130 | |
131 | flutter::MatrixDecomposition decomposition(matrix); |
132 | ASSERT_TRUE(decomposition.IsValid()); |
133 | |
134 | flutter::MatrixDecomposition decomposition2(matrix2); |
135 | ASSERT_TRUE(decomposition2.IsValid()); |
136 | |
137 | flutter::MatrixDecomposition decomposition3(matrix3); |
138 | ASSERT_TRUE(decomposition3.IsValid()); |
139 | |
140 | ASSERT_FLOAT_EQ(scale1, decomposition.scale().x); |
141 | ASSERT_FLOAT_EQ(scale1, decomposition.scale().y); |
142 | ASSERT_FLOAT_EQ(1.f, decomposition.scale().z); |
143 | ASSERT_FLOAT_EQ(0, decomposition.rotation().x); |
144 | ASSERT_FLOAT_EQ(0, decomposition.rotation().y); |
145 | ASSERT_FLOAT_EQ(0, decomposition.rotation().z); |
146 | |
147 | ASSERT_FLOAT_EQ(scale2, decomposition2.scale().x); |
148 | ASSERT_FLOAT_EQ(scale2, decomposition2.scale().y); |
149 | ASSERT_FLOAT_EQ(1.f, decomposition2.scale().z); |
150 | ASSERT_FLOAT_EQ(0, decomposition2.rotation().x); |
151 | ASSERT_FLOAT_EQ(0, decomposition2.rotation().y); |
152 | ASSERT_FLOAT_EQ(0, decomposition2.rotation().z); |
153 | |
154 | ASSERT_FLOAT_EQ(scale3, decomposition3.scale().x); |
155 | ASSERT_FLOAT_EQ(scale3, decomposition3.scale().y); |
156 | ASSERT_FLOAT_EQ(1.f, decomposition3.scale().z); |
157 | ASSERT_FLOAT_EQ(0, decomposition3.rotation().x); |
158 | ASSERT_FLOAT_EQ(0, decomposition3.rotation().y); |
159 | ASSERT_FLOAT_EQ(0, decomposition3.rotation().z); |
160 | } |
161 | |
162 | } // namespace testing |
163 | } // namespace flutter |
164 | |