Chromium Code Reviews| 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 |