From ee87ce65172d6764ae4792d777178bfc4573e0b8 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Tue, 6 Sep 2022 16:58:53 -0700 Subject: [PATCH] Add utility to check if a Matrix is aligned (flutter/engine#35951) --- .../impeller/geometry/geometry_unittests.cc | 14 +++++++++++ engine/src/flutter/impeller/geometry/matrix.h | 25 +++++++++++++++++++ engine/src/flutter/impeller/geometry/scalar.h | 7 +++++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/engine/src/flutter/impeller/geometry/geometry_unittests.cc b/engine/src/flutter/impeller/geometry/geometry_unittests.cc index db027c3c341..324e607daf0 100644 --- a/engine/src/flutter/impeller/geometry/geometry_unittests.cc +++ b/engine/src/flutter/impeller/geometry/geometry_unittests.cc @@ -351,6 +351,20 @@ TEST(GeometryTest, MatrixGetDirectionScale) { } } +TEST(GeometryTest, MatrixIsAligned) { + { + auto m = Matrix::MakeTranslation({1, 2, 3}); + bool result = m.IsAligned(); + ASSERT_TRUE(result); + } + + { + auto m = Matrix::MakeRotationZ(Degrees{123}); + bool result = m.IsAligned(); + ASSERT_FALSE(result); + } +} + TEST(GeometryTest, QuaternionLerp) { auto q1 = Quaternion{{0.0, 0.0, 1.0}, 0.0}; auto q2 = Quaternion{{0.0, 0.0, 1.0}, kPiOver4}; diff --git a/engine/src/flutter/impeller/geometry/matrix.h b/engine/src/flutter/impeller/geometry/matrix.h index 9be6707f085..b299d1ad9fe 100644 --- a/engine/src/flutter/impeller/geometry/matrix.h +++ b/engine/src/flutter/impeller/geometry/matrix.h @@ -258,6 +258,31 @@ struct Matrix { m[9] == 0 && m[10] == 1 && m[11] == 0 && m[14] == 0 && m[15] == 1); } + constexpr bool IsAligned(Scalar tolerance = 0) const { + int v[] = {!ScalarNearlyZero(m[0], tolerance), // + !ScalarNearlyZero(m[1], tolerance), // + !ScalarNearlyZero(m[2], tolerance), // + !ScalarNearlyZero(m[4], tolerance), // + !ScalarNearlyZero(m[5], tolerance), // + !ScalarNearlyZero(m[6], tolerance), // + !ScalarNearlyZero(m[8], tolerance), // + !ScalarNearlyZero(m[9], tolerance), // + !ScalarNearlyZero(m[10], tolerance)}; + // Check if all three basis vectors are aligned to an axis. + if (v[0] + v[1] + v[2] != 1 || // + v[3] + v[4] + v[5] != 1 || // + v[6] + v[7] + v[8] != 1) { + return false; + } + // Ensure that none of the basis vectors overlap. + if (v[0] + v[3] + v[6] != 1 || // + v[1] + v[4] + v[7] != 1 || // + v[2] + v[5] + v[8] != 1) { + return false; + } + return true; + } + constexpr bool IsIdentity() const { return ( // clang-format off diff --git a/engine/src/flutter/impeller/geometry/scalar.h b/engine/src/flutter/impeller/geometry/scalar.h index 3ca2f1dab66..8a080e18b52 100644 --- a/engine/src/flutter/impeller/geometry/scalar.h +++ b/engine/src/flutter/impeller/geometry/scalar.h @@ -19,10 +19,15 @@ constexpr T Absolute(const T& val) { return val >= T{} ? val : -val; } +constexpr inline bool ScalarNearlyZero(Scalar x, + Scalar tolerance = kEhCloseEnough) { + return Absolute(x) <= tolerance; +} + constexpr inline bool ScalarNearlyEqual(Scalar x, Scalar y, Scalar tolerance = kEhCloseEnough) { - return Absolute(x - y) <= tolerance; + return ScalarNearlyZero(x - y, tolerance); } struct Degrees;