Flutter Impeller
matrix_unittests.cc
Go to the documentation of this file.
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 "gtest/gtest.h"
6 
8 
11 
12 namespace impeller {
13 namespace testing {
14 
15 TEST(MatrixTest, Multiply) {
16  Matrix x(0.0, 0.0, 0.0, 1.0, //
17  1.0, 0.0, 0.0, 1.0, //
18  0.0, 1.0, 0.0, 1.0, //
19  1.0, 1.0, 0.0, 1.0);
20  Matrix translate = Matrix::MakeTranslation({10, 20, 0});
21  Matrix result = translate * x;
22  EXPECT_TRUE(MatrixNear(result, Matrix(10.0, 20.0, 0.0, 1.0, //
23  11.0, 20.0, 0.0, 1.0, //
24  10.0, 21.0, 0.0, 1.0, //
25  11.0, 21.0, 0.0, 1.0)));
26 }
27 
28 TEST(MatrixTest, Equals) {
29  Matrix x;
30  Matrix y = x;
31  EXPECT_TRUE(x.Equals(y));
32 }
33 
34 TEST(MatrixTest, NotEquals) {
35  Matrix x;
36  Matrix y = x.Translate({1, 0, 0});
37  EXPECT_FALSE(x.Equals(y));
38 }
39 
40 TEST(MatrixTest, HasPerspective2D) {
41  EXPECT_FALSE(Matrix().HasPerspective2D());
42 
43  auto test = [](int index, bool expect) {
44  Matrix matrix;
45  EXPECT_FALSE(matrix.HasPerspective2D());
46  matrix.m[index] = 0.5f;
47  EXPECT_EQ(matrix.HasPerspective2D(), expect) << "index: " << index;
48  };
49 
50  // clang-format off
51  test( 0, false); test( 1, false); test( 2, false); test( 3, true);
52  test( 4, false); test( 5, false); test( 6, false); test( 7, true);
53  test( 8, false); test( 9, false); test(10, false); test(11, false);
54  test(12, false); test(13, false); test(14, false); test(15, true);
55  // clang-format on
56 }
57 
58 TEST(MatrixTest, HasPerspective) {
59  EXPECT_FALSE(Matrix().HasPerspective());
60 
61  auto test = [](int index, bool expect) {
62  Matrix matrix;
63  EXPECT_FALSE(matrix.HasPerspective());
64  matrix.m[index] = 0.5f;
65  EXPECT_EQ(matrix.HasPerspective(), expect) << "index: " << index;
66  };
67 
68  // clang-format off
69  test( 0, false); test( 1, false); test( 2, false); test( 3, true);
70  test( 4, false); test( 5, false); test( 6, false); test( 7, true);
71  test( 8, false); test( 9, false); test(10, false); test(11, true);
72  test(12, false); test(13, false); test(14, false); test(15, true);
73  // clang-format on
74 }
75 
76 TEST(MatrixTest, HasTranslation) {
77  EXPECT_TRUE(Matrix::MakeTranslation({100, 100, 0}).HasTranslation());
78  EXPECT_TRUE(Matrix::MakeTranslation({0, 100, 0}).HasTranslation());
79  EXPECT_TRUE(Matrix::MakeTranslation({100, 0, 0}).HasTranslation());
80  EXPECT_FALSE(Matrix().HasTranslation());
81 }
82 
83 TEST(MatrixTest, IsTranslationOnly) {
84  EXPECT_TRUE(Matrix::MakeTranslation({100, 100, 0}).IsTranslationOnly());
85  EXPECT_TRUE(Matrix::MakeTranslation({100, 100, 0}).IsTranslationScaleOnly());
86  EXPECT_TRUE(Matrix::MakeTranslation({0, 100, 0}).IsTranslationOnly());
87  EXPECT_TRUE(Matrix::MakeTranslation({0, 100, 0}).IsTranslationScaleOnly());
88  EXPECT_TRUE(Matrix::MakeTranslation({100, 0, 0}).IsTranslationOnly());
89  EXPECT_TRUE(Matrix::MakeTranslation({100, 0, 0}).IsTranslationScaleOnly());
90  EXPECT_TRUE(Matrix().IsTranslationOnly());
91  EXPECT_TRUE(Matrix().IsTranslationScaleOnly());
92 }
93 
94 TEST(MatrixTest, IsTranslationScaleOnly) {
95  EXPECT_FALSE(Matrix::MakeScale({100, 100, 1}).IsTranslationOnly());
96  EXPECT_TRUE(Matrix::MakeScale({100, 100, 1}).IsTranslationScaleOnly());
97  EXPECT_FALSE(Matrix::MakeScale({1, 100, 1}).IsTranslationOnly());
98  EXPECT_TRUE(Matrix::MakeScale({1, 100, 1}).IsTranslationScaleOnly());
99  EXPECT_FALSE(Matrix::MakeScale({100, 1, 1}).IsTranslationOnly());
100  EXPECT_TRUE(Matrix::MakeScale({100, 1, 1}).IsTranslationScaleOnly());
101  EXPECT_TRUE(Matrix().IsTranslationOnly());
102  EXPECT_TRUE(Matrix().IsTranslationScaleOnly());
103 }
104 
105 TEST(MatrixTest, IsInvertibleGetDeterminant) {
106  EXPECT_TRUE(Matrix().IsInvertible());
107  EXPECT_NE(Matrix().GetDeterminant(), 0.0f);
108 
109  EXPECT_TRUE(Matrix::MakeTranslation({100, 100, 0}).IsInvertible());
110  EXPECT_NE(Matrix::MakeTranslation({100, 100, 0}).GetDeterminant(), 0.0f);
111 
112  EXPECT_TRUE(Matrix::MakeScale({100, 100, 1}).IsInvertible());
113  EXPECT_NE(Matrix::MakeScale({100, 100, 1}).GetDeterminant(), 0.0f);
114 
115  EXPECT_TRUE(Matrix::MakeRotationX(Degrees(30)).IsInvertible());
116  EXPECT_NE(Matrix::MakeRotationX(Degrees(30)).GetDeterminant(), 0.0f);
117 
118  EXPECT_TRUE(Matrix::MakeRotationY(Degrees(30)).IsInvertible());
119  EXPECT_NE(Matrix::MakeRotationY(Degrees(30)).GetDeterminant(), 0.0f);
120 
121  EXPECT_TRUE(Matrix::MakeRotationZ(Degrees(30)).IsInvertible());
122  EXPECT_NE(Matrix::MakeRotationZ(Degrees(30)).GetDeterminant(), 0.0f);
123 
124  EXPECT_FALSE(Matrix::MakeScale({0, 1, 1}).IsInvertible());
125  EXPECT_EQ(Matrix::MakeScale({0, 1, 1}).GetDeterminant(), 0.0f);
126  EXPECT_FALSE(Matrix::MakeScale({1, 0, 1}).IsInvertible());
127  EXPECT_EQ(Matrix::MakeScale({1, 0, 1}).GetDeterminant(), 0.0f);
128  EXPECT_FALSE(Matrix::MakeScale({1, 1, 0}).IsInvertible());
129  EXPECT_EQ(Matrix::MakeScale({1, 1, 0}).GetDeterminant(), 0.0f);
130 }
131 
132 TEST(MatrixTest, IsFinite) {
133  EXPECT_TRUE(Matrix().IsFinite());
134 
135  EXPECT_TRUE(Matrix::MakeTranslation({100, 100, 0}).IsFinite());
136  EXPECT_TRUE(Matrix::MakeScale({100, 100, 1}).IsFinite());
137 
138  EXPECT_TRUE(Matrix::MakeRotationX(Degrees(30)).IsFinite());
139  EXPECT_TRUE(Matrix::MakeRotationY(Degrees(30)).IsFinite());
140  EXPECT_TRUE(Matrix::MakeRotationZ(Degrees(30)).IsFinite());
141 
142  EXPECT_TRUE(Matrix::MakeScale({0, 1, 1}).IsFinite());
143  EXPECT_TRUE(Matrix::MakeScale({1, 0, 1}).IsFinite());
144  EXPECT_TRUE(Matrix::MakeScale({1, 1, 0}).IsFinite());
145 
146  for (int i = 0; i < 16; i++) {
147  {
148  Matrix matrix;
149  ASSERT_TRUE(matrix.IsFinite());
150  matrix.m[i] = std::numeric_limits<Scalar>::infinity();
151  ASSERT_FALSE(matrix.IsFinite());
152  }
153 
154  {
155  Matrix matrix;
156  ASSERT_TRUE(matrix.IsFinite());
157  matrix.m[i] = -std::numeric_limits<Scalar>::infinity();
158  ASSERT_FALSE(matrix.IsFinite());
159  }
160 
161  {
162  Matrix matrix;
163  ASSERT_TRUE(matrix.IsFinite());
164  matrix.m[i] = -std::numeric_limits<Scalar>::quiet_NaN();
165  ASSERT_FALSE(matrix.IsFinite());
166  }
167  }
168 }
169 
170 TEST(MatrixTest, IsAligned2D) {
171  EXPECT_TRUE(Matrix().IsAligned2D());
172  EXPECT_TRUE(Matrix::MakeScale({1.0f, 1.0f, 2.0f}).IsAligned2D());
173 
174  auto test = [](int index, bool expect) {
175  Matrix matrix;
176  EXPECT_TRUE(matrix.IsAligned2D());
177  matrix.m[index] = 0.5f;
178  EXPECT_EQ(matrix.IsAligned2D(), expect) << "index: " << index;
179  };
180 
181  // clang-format off
182  test( 0, true); test( 1, false); test( 2, true); test( 3, false);
183  test( 4, false); test( 5, true); test( 6, true); test( 7, false);
184  test( 8, true); test( 9, true); test(10, true); test(11, true);
185  test(12, true); test(13, true); test(14, true); test(15, false);
186  // clang-format on
187 
188  // True for quadrant rotations from -250 to +250 full circles
189  for (int i = -1000; i < 1000; i++) {
190  Degrees d = Degrees(i * 90);
191  Matrix matrix = Matrix::MakeRotationZ(Degrees(d));
192  EXPECT_TRUE(matrix.IsAligned2D()) << "degrees: " << d.degrees;
193  }
194 
195  // False for half degree rotations from -999.5 to +1000.5 degrees
196  for (int i = -1000; i < 1000; i++) {
197  Degrees d = Degrees(i + 0.5f);
198  Matrix matrix = Matrix::MakeRotationZ(Degrees(d));
199  EXPECT_FALSE(matrix.IsAligned2D()) << "degrees: " << d.degrees;
200  }
201 }
202 
203 TEST(MatrixTest, IsAligned) {
204  EXPECT_TRUE(Matrix().IsAligned());
205  EXPECT_TRUE(Matrix::MakeScale({1.0f, 1.0f, 2.0f}).IsAligned());
206 
207  // Begin Legacy tests transferred over from geometry_unittests.cc
208  {
209  auto m = Matrix::MakeTranslation({1, 2, 3});
210  bool result = m.IsAligned();
211  ASSERT_TRUE(result);
212  }
213 
214  {
215  auto m = Matrix::MakeRotationZ(Degrees{123});
216  bool result = m.IsAligned();
217  ASSERT_FALSE(result);
218  }
219  // End Legacy tests transferred over from geometry_unittests.cc
220 
221  auto test = [](int index, bool expect) {
222  Matrix matrix;
223  EXPECT_TRUE(matrix.IsAligned());
224  matrix.m[index] = 0.5f;
225  EXPECT_EQ(matrix.IsAligned(), expect) << "index: " << index;
226  };
227 
228  // clang-format off
229  test( 0, true); test( 1, false); test( 2, false); test( 3, false);
230  test( 4, false); test( 5, true); test( 6, false); test( 7, false);
231  test( 8, false); test( 9, false); test(10, true); test(11, false);
232  test(12, true); test(13, true); test(14, true); test(15, false);
233  // clang-format on
234 
235  // True for quadrant rotations from -250 to +250 full circles
236  for (int i = -1000; i < 1000; i++) {
237  Degrees d = Degrees(i * 90);
238  Matrix matrix = Matrix::MakeRotationZ(Degrees(d));
239  EXPECT_TRUE(matrix.IsAligned()) << "degrees: " << d.degrees;
240  }
241 
242  // False for half degree rotations from -999.5 to +1000.5 degrees
243  for (int i = -1000; i < 1000; i++) {
244  Degrees d = Degrees(i + 0.5f);
245  Matrix matrix = Matrix::MakeRotationZ(Degrees(d));
246  EXPECT_FALSE(matrix.IsAligned()) << "degrees: " << d.degrees;
247  }
248 }
249 
250 TEST(MatrixTest, TransformHomogenous) {
251  Matrix matrix = Matrix::MakeColumn(
252  // clang-format off
253  2.0f, 3.0f, 5.0f, 7.0f,
254  11.0f, 13.0f, 17.0f, 19.0f,
255  23.0f, 29.0f, 31.0f, 37.0f,
256  41.0f, 43.0f, 47.0f, 53.0f
257  // clang-format on
258  );
259  EXPECT_EQ(matrix.TransformHomogenous({1.0f, -1.0f}),
260  Vector3(32.0f, 33.0f, 41.0f));
261 }
262 
263 TEST(MatrixTest, GetMaxBasisXYNegativeScale) {
264  Matrix m = Matrix::MakeScale({-2, 1, 1});
265 
266  EXPECT_EQ(m.GetMaxBasisLengthXY(), 2);
267 
268  m = Matrix::MakeScale({1, -3, 1});
269 
270  EXPECT_EQ(m.GetMaxBasisLengthXY(), 3);
271 }
272 
273 // Verifies a translate scale matrix doesn't need to compute sqrt(pow(scale, 2))
274 TEST(MatrixTest, GetMaxBasisXYWithLargeAndSmallScalingFactor) {
275  Matrix m = Matrix::MakeScale({2.625e+20, 2.625e+20, 1});
276  EXPECT_NEAR(m.GetMaxBasisLengthXY(), 2.625e+20, 1e+20);
277 
278  m = Matrix::MakeScale({2.625e-20, 2.625e-20, 1});
279  EXPECT_NEAR(m.GetMaxBasisLengthXY(), 2.625e-20, 1e-20);
280 }
281 
282 TEST(MatrixTest, GetMaxBasisXYWithLargeAndSmallScalingFactorNonScaleTranslate) {
283  Matrix m = Matrix::MakeScale({2.625e+20, 2.625e+20, 1});
284  m.e[0][1] = 2;
285 
286  EXPECT_TRUE(std::isinf(m.GetMaxBasisLengthXY()));
287 }
288 
289 TEST(MatrixTest, TranslateWithPerspective) {
290  Matrix m = Matrix::MakeRow(1.0, 0.0, 0.0, 10.0, //
291  0.0, 1.0, 0.0, 20.0, //
292  0.0, 0.0, 1.0, 0.0, //
293  0.0, 2.0, 0.0, 30.0);
294  Matrix result = m.Translate({100, 200});
295  EXPECT_TRUE(MatrixNear(result, Matrix::MakeRow(1.0, 0.0, 0.0, 110.0, //
296  0.0, 1.0, 0.0, 220.0, //
297  0.0, 0.0, 1.0, 0.0, //
298  0.0, 2.0, 0.0, 430.0)));
299 }
300 
301 TEST(MatrixTest, MakeScaleTranslate) {
302  EXPECT_TRUE(MatrixNear(
303  Matrix::MakeTranslateScale({1, 1, 1.0 / 1024}, {10, 10, 1.0 / 1024}),
304  Matrix::MakeTranslation({10, 10, 1.0 / 1024}) *
305  Matrix::MakeScale({1, 1, 1.0 / 1024})));
306 
307  EXPECT_TRUE(MatrixNear(
308  Matrix::MakeTranslateScale({2, 2, 2}, {10, 10, 0}),
309  Matrix::MakeTranslation({10, 10, 0}) * Matrix::MakeScale({2, 2, 2})));
310 
311  EXPECT_TRUE(MatrixNear(
312  Matrix::MakeTranslateScale({0, 0, 0}, {0, 0, 0}),
313  Matrix::MakeTranslation({0, 0, 0}) * Matrix::MakeScale({0, 0, 0})));
314 }
315 
316 TEST(MatrixTest, To3x3) {
317  Matrix x(1.0, 0.0, 4.0, 0.0, //
318  0.0, 1.0, 4.0, 0.0, //
319  6.0, 5.0, 111.0, 7.0, //
320  0.0, 0.0, 9.0, 1.0);
321 
322  EXPECT_TRUE(MatrixNear(x.To3x3(), Matrix()));
323 }
324 
325 } // namespace testing
326 } // namespace impeller
int32_t x
inline ::testing::AssertionResult MatrixNear(impeller::Matrix a, impeller::Matrix b)
TEST(AllocationSizeTest, CanCreateTypedAllocations)
Scalar degrees
Definition: scalar.h:77
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
Scalar m[16]
Definition: matrix.h:39
constexpr Matrix Translate(const Vector3 &t) const
Definition: matrix.h:263
constexpr bool IsAligned(Scalar tolerance=0) const
Definition: matrix.h:386
static constexpr Matrix MakeColumn(Scalar m0, Scalar m1, Scalar m2, Scalar m3, Scalar m4, Scalar m5, Scalar m6, Scalar m7, Scalar m8, Scalar m9, Scalar m10, Scalar m11, Scalar m12, Scalar m13, Scalar m14, Scalar m15)
Definition: matrix.h:69
static Matrix MakeRotationY(Radians r)
Definition: matrix.h:208
constexpr bool HasPerspective2D() const
Definition: matrix.h:361
bool IsFinite() const
Definition: matrix.h:351
static constexpr Matrix MakeRow(Scalar m0, Scalar m1, Scalar m2, Scalar m3, Scalar m4, Scalar m5, Scalar m6, Scalar m7, Scalar m8, Scalar m9, Scalar m10, Scalar m11, Scalar m12, Scalar m13, Scalar m14, Scalar m15)
Definition: matrix.h:83
constexpr Vector3 TransformHomogenous(const Point &v) const
Definition: matrix.h:534
static constexpr Matrix MakeTranslateScale(const Vector3 &s, const Vector3 &t)
Definition: matrix.h:113
Scalar e[4][4]
Definition: matrix.h:40
static Matrix MakeRotationZ(Radians r)
Definition: matrix.h:223
constexpr bool HasPerspective() const
Definition: matrix.h:365
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
constexpr bool IsAligned2D(Scalar tolerance=0) const
Definition: matrix.h:371
Scalar GetMaxBasisLengthXY() const
Definition: matrix.h:323
static Matrix MakeRotationX(Radians r)
Definition: matrix.h:193