Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(329)

Unified Diff: ui/gfx/transform_unittest.cc

Issue 11774005: Migrate more functions from MathUtil to gfx::Transform (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/gfx/transform_unittest.cc
diff --git a/ui/gfx/transform_unittest.cc b/ui/gfx/transform_unittest.cc
index 1984feab23c8375acfb834524005febac2e3d70f..cee9b044a93ff04cd8107bad96218887e0a21345 100644
--- a/ui/gfx/transform_unittest.cc
+++ b/ui/gfx/transform_unittest.cc
@@ -15,6 +15,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/point.h"
#include "ui/gfx/point3_f.h"
+#include "ui/gfx/test/transform_test_common.h"
#include "ui/gfx/transform_util.h"
#include "ui/gfx/vector3d_f.h"
@@ -41,51 +42,6 @@ bool MatricesAreNearlyEqual(const Transform& lhs,
return true;
}
-#define EXPECT_ROW1_EQ(a, b, c, d, transform) \
- EXPECT_FLOAT_EQ((a), (transform).matrix().get(0, 0)); \
- EXPECT_FLOAT_EQ((b), (transform).matrix().get(0, 1)); \
- EXPECT_FLOAT_EQ((c), (transform).matrix().get(0, 2)); \
- EXPECT_FLOAT_EQ((d), (transform).matrix().get(0, 3));
-
-#define EXPECT_ROW2_EQ(a, b, c, d, transform) \
- EXPECT_FLOAT_EQ((a), (transform).matrix().get(1, 0)); \
- EXPECT_FLOAT_EQ((b), (transform).matrix().get(1, 1)); \
- EXPECT_FLOAT_EQ((c), (transform).matrix().get(1, 2)); \
- EXPECT_FLOAT_EQ((d), (transform).matrix().get(1, 3));
-
-#define EXPECT_ROW3_EQ(a, b, c, d, transform) \
- EXPECT_FLOAT_EQ((a), (transform).matrix().get(2, 0)); \
- EXPECT_FLOAT_EQ((b), (transform).matrix().get(2, 1)); \
- EXPECT_FLOAT_EQ((c), (transform).matrix().get(2, 2)); \
- EXPECT_FLOAT_EQ((d), (transform).matrix().get(2, 3));
-
-#define EXPECT_ROW4_EQ(a, b, c, d, transform) \
- EXPECT_FLOAT_EQ((a), (transform).matrix().get(3, 0)); \
- EXPECT_FLOAT_EQ((b), (transform).matrix().get(3, 1)); \
- EXPECT_FLOAT_EQ((c), (transform).matrix().get(3, 2)); \
- EXPECT_FLOAT_EQ((d), (transform).matrix().get(3, 3)); \
-
-// Checking float values for equality close to zero is not robust using
-// EXPECT_FLOAT_EQ (see gtest documentation). So, to verify rotation matrices,
-// we must use a looser absolute error threshold in some places.
-#define EXPECT_ROW1_NEAR(a, b, c, d, transform, errorThreshold) \
- EXPECT_NEAR((a), (transform).matrix().get(0, 0), (errorThreshold)); \
- EXPECT_NEAR((b), (transform).matrix().get(0, 1), (errorThreshold)); \
- EXPECT_NEAR((c), (transform).matrix().get(0, 2), (errorThreshold)); \
- EXPECT_NEAR((d), (transform).matrix().get(0, 3), (errorThreshold));
-
-#define EXPECT_ROW2_NEAR(a, b, c, d, transform, errorThreshold) \
- EXPECT_NEAR((a), (transform).matrix().get(1, 0), (errorThreshold)); \
- EXPECT_NEAR((b), (transform).matrix().get(1, 1), (errorThreshold)); \
- EXPECT_NEAR((c), (transform).matrix().get(1, 2), (errorThreshold)); \
- EXPECT_NEAR((d), (transform).matrix().get(1, 3), (errorThreshold));
-
-#define EXPECT_ROW3_NEAR(a, b, c, d, transform, errorThreshold) \
- EXPECT_NEAR((a), (transform).matrix().get(2, 0), (errorThreshold)); \
- EXPECT_NEAR((b), (transform).matrix().get(2, 1), (errorThreshold)); \
- EXPECT_NEAR((c), (transform).matrix().get(2, 2), (errorThreshold)); \
- EXPECT_NEAR((d), (transform).matrix().get(2, 3), (errorThreshold));
-
#ifdef SK_MSCALAR_IS_DOUBLE
#define ERROR_THRESHOLD 1e-14
#else
@@ -1240,6 +1196,930 @@ TEST(XFormTest, verifyMatrixInversion)
}
}
+TEST(XFormTest, verifyBackfaceVisibilityBasicCases)
+{
+ Transform transform;
+
+ transform.MakeIdentity();
+ EXPECT_FALSE(transform.IsBackFaceVisible());
+
+ transform.MakeIdentity();
+ transform.RotateAboutYAxis(80);
+ EXPECT_FALSE(transform.IsBackFaceVisible());
+
+ transform.MakeIdentity();
+ transform.RotateAboutYAxis(100);
+ EXPECT_TRUE(transform.IsBackFaceVisible());
+
+ // Edge case, 90 degree rotation should return false.
+ transform.MakeIdentity();
+ transform.RotateAboutYAxis(90);
+ EXPECT_FALSE(transform.IsBackFaceVisible());
+}
+
+TEST(XFormTest, verifyBackfaceVisibilityForPerspective)
+{
+ Transform layer_space_to_projection_plane;
+
+ // This tests if IsBackFaceVisible works properly under perspective
+ // transforms. Specifically, layers that may have their back face visible in
+ // orthographic projection, may not actually have back face visible under
+ // perspective projection.
+
+ // Case 1: Layer is rotated by slightly more than 90 degrees, at the center
+ // of the prespective projection. In this case, the layer's back-side
+ // is visible to the camera.
+ layer_space_to_projection_plane.MakeIdentity();
+ layer_space_to_projection_plane.ApplyPerspectiveDepth(1);
+ layer_space_to_projection_plane.Translate3d(0, 0, 0);
+ layer_space_to_projection_plane.RotateAboutYAxis(100);
+ EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible());
+
+ // Case 2: Layer is rotated by slightly more than 90 degrees, but shifted off
+ // to the side of the camera. Because of the wide field-of-view, the
+ // layer's front side is still visible.
+ //
+ // |<-- front side of layer is visible to camera
+ // \ | /
+ // \ | /
+ // \| /
+ // | /
+ // |\ /<-- camera field of view
+ // | \ /
+ // back side of layer -->| \ /
+ // \./ <-- camera origin
+ //
+ layer_space_to_projection_plane.MakeIdentity();
+ layer_space_to_projection_plane.ApplyPerspectiveDepth(1);
+ layer_space_to_projection_plane.Translate3d(-10, 0, 0);
+ layer_space_to_projection_plane.RotateAboutYAxis(100);
+ EXPECT_FALSE(layer_space_to_projection_plane.IsBackFaceVisible());
+
+ // Case 3: Additionally rotating the layer by 180 degrees should of course
+ // show the opposite result of case 2.
+ layer_space_to_projection_plane.RotateAboutYAxis(180);
+ EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible());
+}
+
+TEST(XFormTest, verifyDefaultConstructorCreatesIdentityMatrix)
+{
+ Transform A;
+ EXPECT_ROW1_EQ(1, 0, 0, 0, A);
+ EXPECT_ROW2_EQ(0, 1, 0, 0, A);
+ EXPECT_ROW3_EQ(0, 0, 1, 0, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+ EXPECT_TRUE(A.IsIdentity());
+}
+
+TEST(XFormTest, verifyCopyConstructor)
+{
+ Transform A;
+ InitializeTestMatrix(&A);
+
+ // Copy constructor should produce exact same elements as matrix A.
+ Transform B(A);
+ EXPECT_ROW1_EQ(10, 14, 18, 22, B);
+ EXPECT_ROW2_EQ(11, 15, 19, 23, B);
+ EXPECT_ROW3_EQ(12, 16, 20, 24, B);
+ EXPECT_ROW4_EQ(13, 17, 21, 25, B);
+}
+
+TEST(XFormTest, verifyAssignmentOperator)
+{
+ Transform A;
+ InitializeTestMatrix(&A);
+ Transform B;
+ InitializeTestMatrix2(&B);
+ Transform C;
+ InitializeTestMatrix2(&C);
+ C = B = A;
+
+ // Both B and C should now have been re-assigned to the value of A.
+ EXPECT_ROW1_EQ(10, 14, 18, 22, B);
+ EXPECT_ROW2_EQ(11, 15, 19, 23, B);
+ EXPECT_ROW3_EQ(12, 16, 20, 24, B);
+ EXPECT_ROW4_EQ(13, 17, 21, 25, B);
+
+ EXPECT_ROW1_EQ(10, 14, 18, 22, C);
+ EXPECT_ROW2_EQ(11, 15, 19, 23, C);
+ EXPECT_ROW3_EQ(12, 16, 20, 24, C);
+ EXPECT_ROW4_EQ(13, 17, 21, 25, C);
+}
+
+TEST(XFormTest, verifyEqualsBooleanOperator)
+{
+ Transform A;
+ InitializeTestMatrix(&A);
+
+ Transform B;
+ InitializeTestMatrix(&B);
+ EXPECT_TRUE(A == B);
+
+ // Modifying multiple elements should cause equals operator to return false.
+ Transform C;
+ InitializeTestMatrix2(&C);
+ EXPECT_FALSE(A == C);
+
+ // Modifying any one individual element should cause equals operator to
+ // return false.
+ Transform D;
+ D = A;
+ D.matrix().setDouble(0, 0, 0);
+ EXPECT_FALSE(A == D);
+
+ D = A;
+ D.matrix().setDouble(1, 0, 0);
+ EXPECT_FALSE(A == D);
+
+ D = A;
+ D.matrix().setDouble(2, 0, 0);
+ EXPECT_FALSE(A == D);
+
+ D = A;
+ D.matrix().setDouble(3, 0, 0);
+ EXPECT_FALSE(A == D);
+
+ D = A;
+ D.matrix().setDouble(0, 1, 0);
+ EXPECT_FALSE(A == D);
+
+ D = A;
+ D.matrix().setDouble(1, 1, 0);
+ EXPECT_FALSE(A == D);
+
+ D = A;
+ D.matrix().setDouble(2, 1, 0);
+ EXPECT_FALSE(A == D);
+
+ D = A;
+ D.matrix().setDouble(3, 1, 0);
+ EXPECT_FALSE(A == D);
+
+ D = A;
+ D.matrix().setDouble(0, 2, 0);
+ EXPECT_FALSE(A == D);
+
+ D = A;
+ D.matrix().setDouble(1, 2, 0);
+ EXPECT_FALSE(A == D);
+
+ D = A;
+ D.matrix().setDouble(2, 2, 0);
+ EXPECT_FALSE(A == D);
+
+ D = A;
+ D.matrix().setDouble(3, 2, 0);
+ EXPECT_FALSE(A == D);
+
+ D = A;
+ D.matrix().setDouble(0, 3, 0);
+ EXPECT_FALSE(A == D);
+
+ D = A;
+ D.matrix().setDouble(1, 3, 0);
+ EXPECT_FALSE(A == D);
+
+ D = A;
+ D.matrix().setDouble(2, 3, 0);
+ EXPECT_FALSE(A == D);
+
+ D = A;
+ D.matrix().setDouble(3, 3, 0);
+ EXPECT_FALSE(A == D);
+}
+
+TEST(XFormTest, verifyMultiplyOperator)
+{
danakj 2013/01/07 23:22:35 chromium style here. { on previous line for all th
+ Transform A;
+ InitializeTestMatrix(&A);
+
+ Transform B;
+ InitializeTestMatrix2(&B);
+
+ Transform C = A * B;
+ EXPECT_ROW1_EQ(2036, 2292, 2548, 2804, C);
danakj 2013/01/07 23:22:35 float literals should have .f or .0f suffix all th
+ EXPECT_ROW2_EQ(2162, 2434, 2706, 2978, C);
+ EXPECT_ROW3_EQ(2288, 2576, 2864, 3152, C);
+ EXPECT_ROW4_EQ(2414, 2718, 3022, 3326, C);
+
+ // Just an additional sanity check; matrix multiplication is not commutative.
+ EXPECT_FALSE(A * B == B * A);
+}
+
+TEST(XFormTest, verifyMultiplyAndAssignOperator)
+{
+ Transform A;
+ InitializeTestMatrix(&A);
+
+ Transform B;
+ InitializeTestMatrix2(&B);
+
+ A *= B;
+ EXPECT_ROW1_EQ(2036, 2292, 2548, 2804, A);
+ EXPECT_ROW2_EQ(2162, 2434, 2706, 2978, A);
+ EXPECT_ROW3_EQ(2288, 2576, 2864, 3152, A);
+ EXPECT_ROW4_EQ(2414, 2718, 3022, 3326, A);
+
+ // Just an additional sanity check; matrix multiplication is not commutative.
+ Transform C = A;
+ C *= B;
+ Transform D = B;
+ D *= A;
+ EXPECT_FALSE(C == D);
+}
+
+TEST(XFormTest, verifyMatrixMultiplication)
+{
+ Transform A;
+ InitializeTestMatrix(&A);
+
+ Transform B;
+ InitializeTestMatrix2(&B);
+
+ A.PreconcatTransform(B);
+ EXPECT_ROW1_EQ(2036, 2292, 2548, 2804, A);
+ EXPECT_ROW2_EQ(2162, 2434, 2706, 2978, A);
+ EXPECT_ROW3_EQ(2288, 2576, 2864, 3152, A);
+ EXPECT_ROW4_EQ(2414, 2718, 3022, 3326, A);
+}
+
+TEST(XFormTest, verifyMakeIdentiy)
+{
+ Transform A;
+ InitializeTestMatrix(&A);
+ A.MakeIdentity();
+ EXPECT_ROW1_EQ(1, 0, 0, 0, A);
+ EXPECT_ROW2_EQ(0, 1, 0, 0, A);
+ EXPECT_ROW3_EQ(0, 0, 1, 0, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+ EXPECT_TRUE(A.IsIdentity());
+}
+
+TEST(XFormTest, verifyTranslate)
+{
+ Transform A;
+ A.Translate(2, 3);
+ EXPECT_ROW1_EQ(1, 0, 0, 2, A);
+ EXPECT_ROW2_EQ(0, 1, 0, 3, A);
+ EXPECT_ROW3_EQ(0, 0, 1, 0, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+
+ // Verify that Translate() post-multiplies the existing matrix.
+ A.MakeIdentity();
+ A.Scale(5, 5);
+ A.Translate(2, 3);
+ EXPECT_ROW1_EQ(5, 0, 0, 10, A);
+ EXPECT_ROW2_EQ(0, 5, 0, 15, A);
+ EXPECT_ROW3_EQ(0, 0, 1, 0, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+}
+
+TEST(XFormTest, verifyTranslate3d)
+{
+ Transform A;
+ A.Translate3d(2, 3, 4);
+ EXPECT_ROW1_EQ(1, 0, 0, 2, A);
+ EXPECT_ROW2_EQ(0, 1, 0, 3, A);
+ EXPECT_ROW3_EQ(0, 0, 1, 4, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+
+ // Verify that Translate3d() post-multiplies the existing matrix.
+ A.MakeIdentity();
+ A.Scale3d(6, 7, 8);
+ A.Translate3d(2, 3, 4);
+ EXPECT_ROW1_EQ(6, 0, 0, 12, A);
+ EXPECT_ROW2_EQ(0, 7, 0, 21, A);
+ EXPECT_ROW3_EQ(0, 0, 8, 32, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+}
+
+TEST(XFormTest, verifyScale)
+{
+ Transform A;
+ A.Scale(6, 7);
+ EXPECT_ROW1_EQ(6, 0, 0, 0, A);
+ EXPECT_ROW2_EQ(0, 7, 0, 0, A);
+ EXPECT_ROW3_EQ(0, 0, 1, 0, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+
+ // Verify that Scale() post-multiplies the existing matrix.
+ A.MakeIdentity();
+ A.Translate3d(2, 3, 4);
+ A.Scale(6, 7);
+ EXPECT_ROW1_EQ(6, 0, 0, 2, A);
+ EXPECT_ROW2_EQ(0, 7, 0, 3, A);
+ EXPECT_ROW3_EQ(0, 0, 1, 4, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+}
+
+TEST(XFormTest, verifyScale3d)
+{
+ Transform A;
+ A.Scale3d(6, 7, 8);
+ EXPECT_ROW1_EQ(6, 0, 0, 0, A);
+ EXPECT_ROW2_EQ(0, 7, 0, 0, A);
+ EXPECT_ROW3_EQ(0, 0, 8, 0, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+
+ // Verify that scale3d() post-multiplies the existing matrix.
+ A.MakeIdentity();
+ A.Translate3d(2, 3, 4);
+ A.Scale3d(6, 7, 8);
+ EXPECT_ROW1_EQ(6, 0, 0, 2, A);
+ EXPECT_ROW2_EQ(0, 7, 0, 3, A);
+ EXPECT_ROW3_EQ(0, 0, 8, 4, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+}
+
+TEST(XFormTest, verifyRotate)
+{
+ Transform A;
+ A.Rotate(90);
+ EXPECT_ROW1_NEAR(0, -1, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW2_NEAR(1, 0, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW3_EQ(0, 0, 1, 0, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+
+ // Verify that Rotate() post-multiplies the existing matrix.
+ A.MakeIdentity();
+ A.Scale3d(6, 7, 8);
+ A.Rotate(90);
+ EXPECT_ROW1_NEAR(0, -6, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW2_NEAR(7, 0, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW3_EQ(0, 0, 8, 0, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+}
+
+TEST(XFormTest, verifyRotateAboutXAxis)
+{
+ Transform A;
+ double sin45 = 0.5 * sqrt(2.0);
+ double cos45 = sin45;
+
+ A.MakeIdentity();
+ A.RotateAboutXAxis(90);
+ EXPECT_ROW1_EQ(1, 0, 0, 0, A);
+ EXPECT_ROW2_NEAR(0, 0, -1, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW3_NEAR(0, 1, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+
+ A.MakeIdentity();
+ A.RotateAboutXAxis(45);
+ EXPECT_ROW1_EQ(1, 0, 0, 0, A);
+ EXPECT_ROW2_NEAR(0, cos45, -sin45, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW3_NEAR(0, sin45, cos45, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+
+ // Verify that RotateAboutXAxis(angle) post-multiplies the existing matrix.
+ A.MakeIdentity();
+ A.Scale3d(6, 7, 8);
+ A.RotateAboutXAxis(90);
+ EXPECT_ROW1_NEAR(6, 0, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW2_NEAR(0, 0, -7, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW3_NEAR(0, 8, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+}
+
+TEST(XFormTest, verifyRotateAboutYAxis)
+{
+ Transform A;
+ double sin45 = 0.5 * sqrt(2.0);
+ double cos45 = sin45;
+
+ // Note carefully, the expected pattern is inverted compared to rotating
+ // about x axis or z axis.
+ A.MakeIdentity();
+ A.RotateAboutYAxis(90);
+ EXPECT_ROW1_NEAR(0, 0, 1, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW2_EQ(0, 1, 0, 0, A);
+ EXPECT_ROW3_NEAR(-1, 0, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+
+ A.MakeIdentity();
+ A.RotateAboutYAxis(45);
+ EXPECT_ROW1_NEAR(cos45, 0, sin45, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW2_EQ(0, 1, 0, 0, A);
+ EXPECT_ROW3_NEAR(-sin45, 0, cos45, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+
+ // Verify that RotateAboutYAxis(angle) post-multiplies the existing matrix.
+ A.MakeIdentity();
+ A.Scale3d(6, 7, 8);
+ A.RotateAboutYAxis(90);
+ EXPECT_ROW1_NEAR(0, 0, 6, 0, A, ERROR_THRESHOLD);
danakj 2013/01/07 23:22:35 constants are named kErrorThreshold
shawnsingh 2013/01/07 23:59:53 This is a macro, not a constant. Do you want to c
danakj 2013/01/08 00:45:08 Oh, I see. I guess it's fine.
+ EXPECT_ROW2_NEAR(0, 7, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW3_NEAR(-8, 0, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+}
+
+TEST(XFormTest, verifyRotateAboutZAxis)
+{
+ Transform A;
+ double sin45 = 0.5 * sqrt(2.0);
+ double cos45 = sin45;
+
+ A.MakeIdentity();
+ A.RotateAboutZAxis(90);
+ EXPECT_ROW1_NEAR(0, -1, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW2_NEAR(1, 0, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW3_EQ(0, 0, 1, 0, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+
+ A.MakeIdentity();
+ A.RotateAboutZAxis(45);
+ EXPECT_ROW1_NEAR(cos45, -sin45, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW2_NEAR(sin45, cos45, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW3_EQ(0, 0, 1, 0, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+
+ // Verify that RotateAboutZAxis(angle) post-multiplies the existing matrix.
+ A.MakeIdentity();
+ A.Scale3d(6, 7, 8);
+ A.RotateAboutZAxis(90);
+ EXPECT_ROW1_NEAR(0, -6, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW2_NEAR(7, 0, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW3_EQ(0, 0, 8, 0, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+}
+
+TEST(XFormTest, verifyRotateAboutForAlignedAxes)
+{
+ Transform A;
+
+ // Check rotation about z-axis
+ A.MakeIdentity();
+ A.RotateAbout(Vector3dF(0, 0, 1), 90);
+ EXPECT_ROW1_NEAR(0, -1, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW2_NEAR(1, 0, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW3_EQ(0, 0, 1, 0, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+
+ // Check rotation about x-axis
+ A.MakeIdentity();
+ A.RotateAbout(Vector3dF(1, 0, 0), 90);
+ EXPECT_ROW1_EQ(1, 0, 0, 0, A);
+ EXPECT_ROW2_NEAR(0, 0, -1, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW3_NEAR(0, 1, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+
+ // Check rotation about y-axis. Note carefully, the expected pattern is
+ // inverted compared to rotating about x axis or z axis.
+ A.MakeIdentity();
+ A.RotateAbout(Vector3dF(0, 1, 0), 90);
+ EXPECT_ROW1_NEAR(0, 0, 1, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW2_EQ(0, 1, 0, 0, A);
+ EXPECT_ROW3_NEAR(-1, 0, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+
+ // Verify that rotate3d(axis, angle) post-multiplies the existing matrix.
+ A.MakeIdentity();
+ A.Scale3d(6, 7, 8);
+ A.RotateAboutZAxis(90);
+ EXPECT_ROW1_NEAR(0, -6, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW2_NEAR(7, 0, 0, 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW3_EQ(0, 0, 8, 0, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+}
+
+TEST(XFormTest, verifyRotateAboutForArbitraryAxis)
+{
+ // Check rotation about an arbitrary non-axis-aligned vector.
+ Transform A;
+ A.RotateAbout(Vector3dF(1, 1, 1), 90);
+ EXPECT_ROW1_NEAR(0.3333333333333334258519187,
+ -0.2440169358562924717404030,
+ 0.9106836025229592124219380,
+ 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW2_NEAR(0.9106836025229592124219380,
+ 0.3333333333333334258519187,
+ -0.2440169358562924717404030,
+ 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW3_NEAR(-0.2440169358562924717404030,
+ 0.9106836025229592124219380,
+ 0.3333333333333334258519187,
+ 0, A, ERROR_THRESHOLD);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+}
+
+TEST(XFormTest, verifyRotateAboutForDegenerateAxis)
+{
+ // Check rotation about a degenerate zero vector.
+ // It is expected to skip applying the rotation.
+ Transform A;
+
+ A.RotateAbout(Vector3dF(0, 0, 0), 45);
+ // Verify that A remains unchanged.
+ EXPECT_TRUE(A.IsIdentity());
+
+ InitializeTestMatrix(&A);
+ A.RotateAbout(Vector3dF(0, 0, 0), 35);
+
+ // Verify that A remains unchanged.
+ EXPECT_ROW1_EQ(10, 14, 18, 22, A);
+ EXPECT_ROW2_EQ(11, 15, 19, 23, A);
+ EXPECT_ROW3_EQ(12, 16, 20, 24, A);
+ EXPECT_ROW4_EQ(13, 17, 21, 25, A);
+}
+
+TEST(XFormTest, verifySkewX)
+{
+ Transform A;
+ A.SkewX(45);
+ EXPECT_ROW1_EQ(1, 1, 0, 0, A);
+ EXPECT_ROW2_EQ(0, 1, 0, 0, A);
+ EXPECT_ROW3_EQ(0, 0, 1, 0, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+
+ // Verify that skewX() post-multiplies the existing matrix. Row 1, column 2,
+ // would incorrectly have value "7" if the matrix is pre-multiplied instead
+ // of post-multiplied.
+ A.MakeIdentity();
+ A.Scale3d(6, 7, 8);
+ A.SkewX(45);
+ EXPECT_ROW1_EQ(6, 6, 0, 0, A);
+ EXPECT_ROW2_EQ(0, 7, 0, 0, A);
+ EXPECT_ROW3_EQ(0, 0, 8, 0, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+}
+
+TEST(XFormTest, verifySkewY)
+{
+ Transform A;
+ A.SkewY(45);
+ EXPECT_ROW1_EQ(1, 0, 0, 0, A);
+ EXPECT_ROW2_EQ(1, 1, 0, 0, A);
+ EXPECT_ROW3_EQ(0, 0, 1, 0, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+
+ // Verify that skewY() post-multiplies the existing matrix. Row 2, column 1,
+ // would incorrectly have value "6" if the matrix is pre-multiplied instead
+ // of post-multiplied.
+ A.MakeIdentity();
+ A.Scale3d(6, 7, 8);
+ A.SkewY(45);
+ EXPECT_ROW1_EQ(6, 0, 0, 0, A);
+ EXPECT_ROW2_EQ(7, 7, 0, 0, A);
+ EXPECT_ROW3_EQ(0, 0, 8, 0, A);
+ EXPECT_ROW4_EQ(0, 0, 0, 1, A);
+}
+
+TEST(XFormTest, verifyPerspectiveDepth)
+{
+ Transform A;
+ A.ApplyPerspectiveDepth(1);
+ EXPECT_ROW1_EQ(1, 0, 0, 0, A);
+ EXPECT_ROW2_EQ(0, 1, 0, 0, A);
+ EXPECT_ROW3_EQ(0, 0, 1, 0, A);
+ EXPECT_ROW4_EQ(0, 0, -1, 1, A);
+
+ // Verify that PerspectiveDepth() post-multiplies the existing matrix.
+ A.MakeIdentity();
+ A.Translate3d(2, 3, 4);
+ A.ApplyPerspectiveDepth(1);
+ EXPECT_ROW1_EQ(1, 0, -2, 2, A);
+ EXPECT_ROW2_EQ(0, 1, -3, 3, A);
+ EXPECT_ROW3_EQ(0, 0, -3, 4, A);
+ EXPECT_ROW4_EQ(0, 0, -1, 1, A);
+}
+
+TEST(XFormTest, verifyHasPerspective)
+{
+ Transform A;
+ A.ApplyPerspectiveDepth(1);
+ EXPECT_TRUE(A.HasPerspective());
+
+ A.MakeIdentity();
+ A.ApplyPerspectiveDepth(0);
+ EXPECT_FALSE(A.HasPerspective());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(3, 0, -1);
+ EXPECT_TRUE(A.HasPerspective());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(3, 1, -1);
+ EXPECT_TRUE(A.HasPerspective());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(3, 2, -0.3);
+ EXPECT_TRUE(A.HasPerspective());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(3, 3, 0.5);
+ EXPECT_TRUE(A.HasPerspective());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(3, 3, 0);
+ EXPECT_TRUE(A.HasPerspective());
+}
+
+TEST(XFormTest, verifyIsInvertible)
+{
+ Transform A;
+
+ // Translations, rotations, scales, skews and arbitrary combinations of them
+ // are invertible.
+ A.MakeIdentity();
+ EXPECT_TRUE(A.IsInvertible());
+
+ A.MakeIdentity();
+ A.Translate3d(2, 3, 4);
+ EXPECT_TRUE(A.IsInvertible());
+
+ A.MakeIdentity();
+ A.Scale3d(6, 7, 8);
+ EXPECT_TRUE(A.IsInvertible());
+
+ A.MakeIdentity();
+ A.RotateAboutXAxis(10);
+ A.RotateAboutYAxis(20);
+ A.RotateAboutZAxis(30);
+ EXPECT_TRUE(A.IsInvertible());
+
+ A.MakeIdentity();
+ A.SkewX(45);
+ EXPECT_TRUE(A.IsInvertible());
+
+ // A perspective matrix (projection plane at z=0) is invertible. The
+ // intuitive explanation is that perspective is eqivalent to a skew of the
+ // w-axis; skews are invertible.
+ A.MakeIdentity();
+ A.ApplyPerspectiveDepth(1);
+ EXPECT_TRUE(A.IsInvertible());
+
+ // A "pure" perspective matrix derived by similar triangles, with m44() set
+ // to zero (i.e. camera positioned at the origin), is not invertible.
+ A.MakeIdentity();
+ A.ApplyPerspectiveDepth(1);
+ A.matrix().setDouble(3, 3, 0);
+ EXPECT_FALSE(A.IsInvertible());
+
+ // Adding more to a non-invertible matrix will not make it invertible in the
+ // general case.
+ A.MakeIdentity();
+ A.ApplyPerspectiveDepth(1);
+ A.matrix().setDouble(3, 3, 0);
+ A.Scale3d(6, 7, 8);
+ A.RotateAboutXAxis(10);
+ A.RotateAboutYAxis(20);
+ A.RotateAboutZAxis(30);
+ A.Translate3d(6, 7, 8);
+ EXPECT_FALSE(A.IsInvertible());
+
+ // A degenerate matrix of all zeros is not invertible.
+ A.MakeIdentity();
+ A.matrix().setDouble(0, 0, 0);
+ A.matrix().setDouble(1, 1, 0);
+ A.matrix().setDouble(2, 2, 0);
+ A.matrix().setDouble(3, 3, 0);
+ EXPECT_FALSE(A.IsInvertible());
+}
+
+TEST(XFormTest, verifyIsIdentity)
+{
+ Transform A;
+
+ InitializeTestMatrix(&A);
+ EXPECT_FALSE(A.IsIdentity());
+
+ A.MakeIdentity();
+ EXPECT_TRUE(A.IsIdentity());
+
+ // Modifying any one individual element should cause the matrix to no longer
+ // be identity.
+ A.MakeIdentity();
+ A.matrix().setDouble(0, 0, 2);
+ EXPECT_FALSE(A.IsIdentity());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(1, 0, 2);
+ EXPECT_FALSE(A.IsIdentity());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(2, 0, 2);
+ EXPECT_FALSE(A.IsIdentity());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(3, 0, 2);
+ EXPECT_FALSE(A.IsIdentity());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(0, 1, 2);
+ EXPECT_FALSE(A.IsIdentity());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(1, 1, 2);
+ EXPECT_FALSE(A.IsIdentity());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(2, 1, 2);
+ EXPECT_FALSE(A.IsIdentity());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(3, 1, 2);
+ EXPECT_FALSE(A.IsIdentity());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(0, 2, 2);
+ EXPECT_FALSE(A.IsIdentity());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(1, 2, 2);
+ EXPECT_FALSE(A.IsIdentity());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(2, 2, 2);
+ EXPECT_FALSE(A.IsIdentity());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(3, 2, 2);
+ EXPECT_FALSE(A.IsIdentity());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(0, 3, 2);
+ EXPECT_FALSE(A.IsIdentity());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(1, 3, 2);
+ EXPECT_FALSE(A.IsIdentity());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(2, 3, 2);
+ EXPECT_FALSE(A.IsIdentity());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(3, 3, 2);
+ EXPECT_FALSE(A.IsIdentity());
+}
+
+TEST(XFormTest, verifyIsIdentityOrTranslation)
+{
+ Transform A;
+
+ InitializeTestMatrix(&A);
+ EXPECT_FALSE(A.IsIdentityOrTranslation());
+
+ A.MakeIdentity();
+ EXPECT_TRUE(A.IsIdentityOrTranslation());
+
+ // Modifying any non-translation components should cause
+ // IsIdentityOrTranslation() to return false. NOTE: (0, 3), (1, 3), and
+ // (2, 3) are the translation components, so modifying them should still
+ // return true.
+ A.MakeIdentity();
+ A.matrix().setDouble(0, 0, 2);
+ EXPECT_FALSE(A.IsIdentityOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(1, 0, 2);
+ EXPECT_FALSE(A.IsIdentityOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(2, 0, 2);
+ EXPECT_FALSE(A.IsIdentityOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(3, 0, 2);
+ EXPECT_FALSE(A.IsIdentityOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(0, 1, 2);
+ EXPECT_FALSE(A.IsIdentityOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(1, 1, 2);
+ EXPECT_FALSE(A.IsIdentityOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(2, 1, 2);
+ EXPECT_FALSE(A.IsIdentityOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(3, 1, 2);
+ EXPECT_FALSE(A.IsIdentityOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(0, 2, 2);
+ EXPECT_FALSE(A.IsIdentityOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(1, 2, 2);
+ EXPECT_FALSE(A.IsIdentityOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(2, 2, 2);
+ EXPECT_FALSE(A.IsIdentityOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(3, 2, 2);
+ EXPECT_FALSE(A.IsIdentityOrTranslation());
+
+ // Note carefully - expecting true here.
+ A.MakeIdentity();
+ A.matrix().setDouble(0, 3, 2);
+ EXPECT_TRUE(A.IsIdentityOrTranslation());
+
+ // Note carefully - expecting true here.
+ A.MakeIdentity();
+ A.matrix().setDouble(1, 3, 2);
+ EXPECT_TRUE(A.IsIdentityOrTranslation());
+
+ // Note carefully - expecting true here.
+ A.MakeIdentity();
+ A.matrix().setDouble(2, 3, 2);
+ EXPECT_TRUE(A.IsIdentityOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(3, 3, 2);
+ EXPECT_FALSE(A.IsIdentityOrTranslation());
+}
+
+TEST(XFormTest, verifyIsScaleOrTranslation)
+{
+ Transform A;
+
+ InitializeTestMatrix(&A);
+ EXPECT_FALSE(A.IsScaleOrTranslation());
+
+ A.MakeIdentity();
+ EXPECT_TRUE(A.IsScaleOrTranslation());
+
+ // Modifying any non-scale or non-translation components should cause
+ // IsScaleOrTranslation() to return false. (0, 0), (1, 1), (2, 2), (0, 3),
+ // (1, 3), and (2, 3) are the scale and translation components, so
+ // modifying them should still return true.
+
+ // Note carefully - expecting true here.
+ A.MakeIdentity();
+ A.matrix().setDouble(0, 0, 2);
+ EXPECT_TRUE(A.IsScaleOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(1, 0, 2);
+ EXPECT_FALSE(A.IsScaleOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(2, 0, 2);
+ EXPECT_FALSE(A.IsScaleOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(3, 0, 2);
+ EXPECT_FALSE(A.IsScaleOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(0, 1, 2);
+ EXPECT_FALSE(A.IsScaleOrTranslation());
+
+ // Note carefully - expecting true here.
+ A.MakeIdentity();
+ A.matrix().setDouble(1, 1, 2);
+ EXPECT_TRUE(A.IsScaleOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(2, 1, 2);
+ EXPECT_FALSE(A.IsScaleOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(3, 1, 2);
+ EXPECT_FALSE(A.IsScaleOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(0, 2, 2);
+ EXPECT_FALSE(A.IsScaleOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(1, 2, 2);
+ EXPECT_FALSE(A.IsScaleOrTranslation());
+
+ // Note carefully - expecting true here.
+ A.MakeIdentity();
+ A.matrix().setDouble(2, 2, 2);
+ EXPECT_TRUE(A.IsScaleOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(3, 2, 2);
+ EXPECT_FALSE(A.IsScaleOrTranslation());
+
+ // Note carefully - expecting true here.
+ A.MakeIdentity();
+ A.matrix().setDouble(0, 3, 2);
+ EXPECT_TRUE(A.IsScaleOrTranslation());
+
+ // Note carefully - expecting true here.
+ A.MakeIdentity();
+ A.matrix().setDouble(1, 3, 2);
+ EXPECT_TRUE(A.IsScaleOrTranslation());
+
+ // Note carefully - expecting true here.
+ A.MakeIdentity();
+ A.matrix().setDouble(2, 3, 2);
+ EXPECT_TRUE(A.IsScaleOrTranslation());
+
+ A.MakeIdentity();
+ A.matrix().setDouble(3, 3, 2);
+ EXPECT_FALSE(A.IsScaleOrTranslation());
+}
+
} // namespace
} // namespace gfx

Powered by Google App Engine
This is Rietveld 408576698