| 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
7 #include "flutter/impeller/geometry/matrix.h"
8
9 #include "flutter/impeller/geometry/geometry_asserts.h"
10 #include "impeller/geometry/constants.h"
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, IsAligned2D) {
84 EXPECT_TRUE(Matrix().IsAligned2D());
85 EXPECT_TRUE(Matrix::MakeScale({1.0f, 1.0f, 2.0f}).IsAligned2D());
86
87 auto test = [](int index, bool expect) {
88 Matrix matrix;
89 EXPECT_TRUE(matrix.IsAligned2D());
90 matrix.m[index] = 0.5f;
91 EXPECT_EQ(matrix.IsAligned2D(), expect) << "index: " << index;
92 };
93
94 // clang-format off
95 test( 0, true); test( 1, false); test( 2, true); test( 3, false);
96 test( 4, false); test( 5, true); test( 6, true); test( 7, false);
97 test( 8, true); test( 9, true); test(10, true); test(11, true);
98 test(12, true); test(13, true); test(14, true); test(15, false);
99 // clang-format on
100
101 // True for quadrant rotations from -250 to +250 full circles
102 for (int i = -1000; i < 1000; i++) {
103 Degrees d = Degrees(i * 90);
104 Matrix matrix = Matrix::MakeRotationZ(Degrees(d));
105 EXPECT_TRUE(matrix.IsAligned2D()) << "degrees: " << d.degrees;
106 }
107
108 // False for half degree rotations from -999.5 to +1000.5 degrees
109 for (int i = -1000; i < 1000; i++) {
110 Degrees d = Degrees(i + 0.5f);
111 Matrix matrix = Matrix::MakeRotationZ(Degrees(d));
112 EXPECT_FALSE(matrix.IsAligned2D()) << "degrees: " << d.degrees;
113 }
114 }
115
116 TEST(MatrixTest, IsAligned) {
117 EXPECT_TRUE(Matrix().IsAligned());
118 EXPECT_TRUE(Matrix::MakeScale({1.0f, 1.0f, 2.0f}).IsAligned());
119
120 // Begin Legacy tests transferred over from geometry_unittests.cc
121 {
122 auto m = Matrix::MakeTranslation({1, 2, 3});
123 bool result = m.IsAligned();
124 ASSERT_TRUE(result);
125 }
126
127 {
128 auto m = Matrix::MakeRotationZ(Degrees{123});
129 bool result = m.IsAligned();
130 ASSERT_FALSE(result);
131 }
132 // End Legacy tests transferred over from geometry_unittests.cc
133
134 auto test = [](int index, bool expect) {
135 Matrix matrix;
136 EXPECT_TRUE(matrix.IsAligned());
137 matrix.m[index] = 0.5f;
138 EXPECT_EQ(matrix.IsAligned(), expect) << "index: " << index;
139 };
140
141 // clang-format off
142 test( 0, true); test( 1, false); test( 2, false); test( 3, false);
143 test( 4, false); test( 5, true); test( 6, false); test( 7, false);
144 test( 8, false); test( 9, false); test(10, true); test(11, false);
145 test(12, true); test(13, true); test(14, true); test(15, false);
146 // clang-format on
147
148 // True for quadrant rotations from -250 to +250 full circles
149 for (int i = -1000; i < 1000; i++) {
150 Degrees d = Degrees(i * 90);
151 Matrix matrix = Matrix::MakeRotationZ(Degrees(d));
152 EXPECT_TRUE(matrix.IsAligned()) << "degrees: " << d.degrees;
153 }
154
155 // False for half degree rotations from -999.5 to +1000.5 degrees
156 for (int i = -1000; i < 1000; i++) {
157 Degrees d = Degrees(i + 0.5f);
158 Matrix matrix = Matrix::MakeRotationZ(Degrees(d));
159 EXPECT_FALSE(matrix.IsAligned()) << "degrees: " << d.degrees;
160 }
161 }
162
163 TEST(MatrixTest, TransformHomogenous) {
164 Matrix matrix = Matrix::MakeColumn(
165 // clang-format off
166 2.0f, 3.0f, 5.0f, 7.0f,
167 11.0f, 13.0f, 17.0f, 19.0f,
168 23.0f, 29.0f, 31.0f, 37.0f,
169 41.0f, 43.0f, 47.0f, 53.0f
170 // clang-format on
171 );
172 EXPECT_EQ(matrix.TransformHomogenous({1.0f, -1.0f}),
173 Vector3(32.0f, 33.0f, 41.0f));
174 }
175
176 TEST(MatrixTest, GetMaxBasisXYNegativeScale) {
177 Matrix m = Matrix::MakeScale({-2, 1, 1});
178
179 EXPECT_EQ(m.GetMaxBasisLengthXY(), 2);
180
181 m = Matrix::MakeScale({1, -3, 1});
182
183 EXPECT_EQ(m.GetMaxBasisLengthXY(), 3);
184 }
185
186 // Verifies a translate scale matrix doesn't need to compute sqrt(pow(scale, 2))
187 TEST(MatrixTest, GetMaxBasisXYWithLargeAndSmallScalingFactor) {
188 Matrix m = Matrix::MakeScale({2.625e+20, 2.625e+20, 1});
189 EXPECT_NEAR(m.GetMaxBasisLengthXY(), 2.625e+20, 1e+20);
190
191 m = Matrix::MakeScale({2.625e-20, 2.625e-20, 1});
192 EXPECT_NEAR(m.GetMaxBasisLengthXY(), 2.625e-20, 1e-20);
193 }
194
195 TEST(MatrixTest, GetMaxBasisXYWithLargeAndSmallScalingFactorNonScaleTranslate) {
196 Matrix m = Matrix::MakeScale({2.625e+20, 2.625e+20, 1});
197 m.e[0][1] = 2;
198
199 EXPECT_TRUE(std::isinf(m.GetMaxBasisLengthXY()));
200 }
201
202 TEST(MatrixTest, TranslateWithPerspective) {
203 Matrix m = Matrix::MakeRow(1.0, 0.0, 0.0, 10.0, //
204 0.0, 1.0, 0.0, 20.0, //
205 0.0, 0.0, 1.0, 0.0, //
206 0.0, 2.0, 0.0, 30.0);
207 Matrix result = m.Translate({100, 200});
208 EXPECT_TRUE(MatrixNear(result, Matrix::MakeRow(1.0, 0.0, 0.0, 110.0, //
209 0.0, 1.0, 0.0, 220.0, //
210 0.0, 0.0, 1.0, 0.0, //
211 0.0, 2.0, 0.0, 430.0)));
212 }
213
214 } // namespace testing
215 } // namespace impeller
impeller::Matrix::HasPerspective
constexpr bool HasPerspective() const
Definition: matrix.h:335
impeller::Matrix::m
Scalar m[16]
Definition: matrix.h:39
impeller::Matrix::TransformHomogenous
constexpr Vector3 TransformHomogenous(const Point &v) const
Definition: matrix.h:491
impeller::Matrix::Equals
bool Equals(const Matrix &matrix, Scalar epsilon=1e-5f) const
Definition: matrix.h:410
impeller::Degrees::degrees
Scalar degrees
Definition: scalar.h:52
geometry_asserts.h
MatrixNear
inline ::testing::AssertionResult MatrixNear(impeller::Matrix a, impeller::Matrix b)
Definition: geometry_asserts.h:56
impeller::Matrix::MakeRow
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
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
impeller::Matrix::e
Scalar e[4][4]
Definition: matrix.h:40
matrix.h
impeller::Matrix::Translate
constexpr Matrix Translate(const Vector3 &t) const
Definition: matrix.h:240
impeller::Matrix::MakeColumn
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
impeller::Matrix::MakeRotationZ
static Matrix MakeRotationZ(Radians r)
Definition: matrix.h:213
impeller::Matrix::GetMaxBasisLengthXY
constexpr Scalar GetMaxBasisLengthXY() const
Definition: matrix.h:298
constants.h
impeller::Degrees
Definition: scalar.h:51
impeller
Definition: allocation.cc:12
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
impeller::testing::TEST
TEST(AllocationSizeTest, CanCreateTypedAllocations)
Definition: allocation_size_unittests.cc:10
impeller::Matrix::IsAligned2D
constexpr bool IsAligned2D(Scalar tolerance=0) const
Definition: matrix.h:341
impeller::Matrix::HasPerspective2D
constexpr bool HasPerspective2D() const
Definition: matrix.h:331
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::Vector3
Definition: vector.h:20
impeller::Matrix::IsAligned
constexpr bool IsAligned(Scalar tolerance=0) const
Definition: matrix.h:356