Flutter Engine
 
Loading...
Searching...
No Matches
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
12namespace impeller {
13namespace testing {
14
15TEST(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
28TEST(MatrixTest, Equals) {
29 Matrix x;
30 Matrix y = x;
31 EXPECT_TRUE(x.Equals(y));
32}
33
34TEST(MatrixTest, NotEquals) {
35 Matrix x;
36 Matrix y = x.Translate({1, 0, 0});
37 EXPECT_FALSE(x.Equals(y));
38}
39
40TEST(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
58TEST(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
76TEST(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
83TEST(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
94TEST(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
105TEST(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
132TEST(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
170TEST(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);
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);
199 EXPECT_FALSE(matrix.IsAligned2D()) << "degrees: " << d.degrees;
200 }
201}
202
203TEST(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);
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);
246 EXPECT_FALSE(matrix.IsAligned()) << "degrees: " << d.degrees;
247 }
248}
249
250TEST(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
263TEST(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))
274TEST(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
282TEST(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
289TEST(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
301TEST(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
316TEST(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
325TEST(MatrixTest, MinMaxScales2D) {
326 // The GetScales2D() method is allowed to return the scales in any
327 // order so we need to take special care in verifying the return
328 // value to test them in either order.
329 auto check_pair = [](const Matrix& matrix, Scalar scale1, Scalar scale2) {
330 auto pair = matrix.GetScales2D();
331 EXPECT_TRUE(pair.has_value())
332 << "Scales: " << scale1 << ", " << scale2 << ", " << matrix;
333 if (ScalarNearlyEqual(pair->first, scale1)) {
334 EXPECT_FLOAT_EQ(pair->first, scale1) << matrix;
335 EXPECT_FLOAT_EQ(pair->second, scale2) << matrix;
336 } else {
337 EXPECT_FLOAT_EQ(pair->first, scale2) << matrix;
338 EXPECT_FLOAT_EQ(pair->second, scale1) << matrix;
339 }
340 };
341
342 for (int i = 1; i < 10; i++) {
343 Scalar xScale = static_cast<Scalar>(i);
344 for (int j = 1; j < 10; j++) {
345 Scalar yScale = static_cast<Scalar>(j);
346 Scalar minScale = std::min(xScale, yScale);
347 Scalar maxScale = std::max(xScale, yScale);
348
349 {
350 // Simple scale
351 Matrix matrix = Matrix::MakeScale({xScale, yScale, 1.0f});
352 EXPECT_TRUE(matrix.GetMinScale2D().has_value());
353 EXPECT_TRUE(matrix.GetMaxScale2D().has_value());
354 EXPECT_FLOAT_EQ(matrix.GetMinScale2D().value_or(-1.0f), minScale);
355 EXPECT_FLOAT_EQ(matrix.GetMaxScale2D().value_or(-1.0f), maxScale);
356 check_pair(matrix, xScale, yScale);
357 }
358
359 {
360 // Simple scale with Z scale
361 Matrix matrix = Matrix::MakeScale({xScale, yScale, 5.0f});
362 EXPECT_TRUE(matrix.GetMinScale2D().has_value());
363 EXPECT_TRUE(matrix.GetMaxScale2D().has_value());
364 EXPECT_FLOAT_EQ(matrix.GetMinScale2D().value_or(-1.0f), minScale);
365 EXPECT_FLOAT_EQ(matrix.GetMaxScale2D().value_or(-1.0f), maxScale);
366 check_pair(matrix, xScale, yScale);
367 }
368
369 {
370 // Simple scale + translate
371 Matrix matrix = Matrix::MakeTranslateScale({xScale, yScale, 1.0f},
372 {10.0f, 15.0f, 2.0f});
373 EXPECT_TRUE(matrix.GetMinScale2D().has_value());
374 EXPECT_TRUE(matrix.GetMaxScale2D().has_value());
375 EXPECT_FLOAT_EQ(matrix.GetMinScale2D().value_or(-1.0f), minScale);
376 EXPECT_FLOAT_EQ(matrix.GetMaxScale2D().value_or(-1.0f), maxScale);
377 check_pair(matrix, xScale, yScale);
378 }
379
380 for (int d = 45; d < 360; d += 45) {
381 {
382 // Rotation * Scale
383 Matrix matrix = Matrix::MakeScale({xScale, yScale, 1.0f}) *
385 EXPECT_TRUE(matrix.GetMinScale2D().has_value());
386 EXPECT_TRUE(matrix.GetMaxScale2D().has_value());
387 EXPECT_FLOAT_EQ(matrix.GetMinScale2D().value_or(-1.0f), minScale);
388 EXPECT_FLOAT_EQ(matrix.GetMaxScale2D().value_or(-1.0f), maxScale);
389 check_pair(matrix, xScale, yScale);
390 }
391
392 {
393 // Scale * Rotation
395 Matrix::MakeScale({xScale, yScale, 1.0f});
396 EXPECT_TRUE(matrix.GetMinScale2D().has_value());
397 EXPECT_TRUE(matrix.GetMaxScale2D().has_value());
398 EXPECT_FLOAT_EQ(matrix.GetMinScale2D().value_or(-1.0f), minScale);
399 EXPECT_FLOAT_EQ(matrix.GetMaxScale2D().value_or(-1.0f), maxScale);
400 check_pair(matrix, xScale, yScale);
401 }
402 }
403
404 {
405 // Scale + PerspectiveX (returns invalid values)
406 Matrix matrix = Matrix::MakeScale({xScale, yScale, 1.0f});
407 matrix.m[3] = 0.1;
408 EXPECT_FALSE(matrix.GetMinScale2D().has_value());
409 EXPECT_FALSE(matrix.GetMaxScale2D().has_value());
410 EXPECT_FALSE(matrix.GetScales2D().has_value());
411 }
412
413 {
414 // Scale + PerspectiveY (returns invalid values)
415 Matrix matrix = Matrix::MakeScale({xScale, yScale, 1.0f});
416 matrix.m[7] = 0.1;
417 EXPECT_FALSE(matrix.GetMinScale2D().has_value());
418 EXPECT_FALSE(matrix.GetMaxScale2D().has_value());
419 EXPECT_FALSE(matrix.GetScales2D().has_value());
420 }
421
422 {
423 // Scale + PerspectiveZ (Z ignored; returns actual scales)
424 Matrix matrix = Matrix::MakeScale({xScale, yScale, 1.0f});
425 matrix.m[11] = 0.1;
426 EXPECT_TRUE(matrix.GetMinScale2D().has_value());
427 EXPECT_TRUE(matrix.GetMaxScale2D().has_value());
428 EXPECT_FLOAT_EQ(matrix.GetMinScale2D().value_or(-1.0f), minScale);
429 EXPECT_FLOAT_EQ(matrix.GetMaxScale2D().value_or(-1.0f), maxScale);
430 check_pair(matrix, xScale, yScale);
431 }
432
433 {
434 // Scale + PerspectiveW (returns invalid values)
435 Matrix matrix = Matrix::MakeScale({xScale, yScale, 1.0f});
436 matrix.m[15] = 0.1;
437 EXPECT_FALSE(matrix.GetMinScale2D().has_value());
438 EXPECT_FALSE(matrix.GetMaxScale2D().has_value());
439 EXPECT_FALSE(matrix.GetScales2D().has_value());
440 }
441 }
442 }
443}
444
445} // namespace testing
446} // namespace impeller
int32_t x
auto & d
Definition main.cc:28
inline ::testing::AssertionResult MatrixNear(impeller::Matrix a, impeller::Matrix b)
double y
TEST(FrameTimingsRecorderTest, RecordVsync)
bool Equals(const T *a, const U *b)
bool NotEquals(const T *a, const U *b)
float Scalar
Definition scalar.h:19
constexpr bool ScalarNearlyEqual(Scalar x, Scalar y, Scalar tolerance=kEhCloseEnough)
Definition scalar.h:36
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:439
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:414
bool IsFinite() const
Definition matrix.h:404
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:601
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
std::optional< std::pair< Scalar, Scalar > > GetScales2D() const
Compute the two non-negative scales applied by this matrix to 2D coordinates and return them as an op...
Definition matrix.cc:363
std::optional< Scalar > GetMaxScale2D() const
Return the smaller of the two non-negative scales that will be applied to 2D coordinates by this matr...
Definition matrix.h:380
std::optional< Scalar > GetMinScale2D() const
Return the smaller of the two non-negative scales that will be applied to 2D coordinates by this matr...
Definition matrix.h:356
constexpr bool HasPerspective() const
Definition matrix.h:418
static constexpr Matrix MakeScale(const Vector3 &s)
Definition matrix.h:104
constexpr bool IsAligned2D(Scalar tolerance=0) const
Definition matrix.h:424
Scalar GetMaxBasisLengthXY() const
Return the maximum scale applied specifically to either the X axis or Y axis unit vectors (the bases)...
Definition matrix.h:328
static Matrix MakeRotationX(Radians r)
Definition matrix.h:193