1 // Copyright (c) 2011 The Chromium 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.
5 // MSVC++ requires this to be set before any other includes to get M_PI.
6 #define _USE_MATH_DEFINES
8 #include "ui/gfx/transform.h"
14 #include "base/basictypes.h"
15 #include "base/logging.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "ui/gfx/box_f.h"
18 #include "ui/gfx/point.h"
19 #include "ui/gfx/point3_f.h"
20 #include "ui/gfx/quad_f.h"
21 #include "ui/gfx/transform_util.h"
22 #include "ui/gfx/vector3d_f.h"
28 #define EXPECT_ROW1_EQ(a, b, c, d, transform) \
29 EXPECT_FLOAT_EQ((a), (transform).matrix().get(0, 0)); \
30 EXPECT_FLOAT_EQ((b), (transform).matrix().get(0, 1)); \
31 EXPECT_FLOAT_EQ((c), (transform).matrix().get(0, 2)); \
32 EXPECT_FLOAT_EQ((d), (transform).matrix().get(0, 3));
34 #define EXPECT_ROW2_EQ(a, b, c, d, transform) \
35 EXPECT_FLOAT_EQ((a), (transform).matrix().get(1, 0)); \
36 EXPECT_FLOAT_EQ((b), (transform).matrix().get(1, 1)); \
37 EXPECT_FLOAT_EQ((c), (transform).matrix().get(1, 2)); \
38 EXPECT_FLOAT_EQ((d), (transform).matrix().get(1, 3));
40 #define EXPECT_ROW3_EQ(a, b, c, d, transform) \
41 EXPECT_FLOAT_EQ((a), (transform).matrix().get(2, 0)); \
42 EXPECT_FLOAT_EQ((b), (transform).matrix().get(2, 1)); \
43 EXPECT_FLOAT_EQ((c), (transform).matrix().get(2, 2)); \
44 EXPECT_FLOAT_EQ((d), (transform).matrix().get(2, 3));
46 #define EXPECT_ROW4_EQ(a, b, c, d, transform) \
47 EXPECT_FLOAT_EQ((a), (transform).matrix().get(3, 0)); \
48 EXPECT_FLOAT_EQ((b), (transform).matrix().get(3, 1)); \
49 EXPECT_FLOAT_EQ((c), (transform).matrix().get(3, 2)); \
50 EXPECT_FLOAT_EQ((d), (transform).matrix().get(3, 3)); \
52 // Checking float values for equality close to zero is not robust using
53 // EXPECT_FLOAT_EQ (see gtest documentation). So, to verify rotation matrices,
54 // we must use a looser absolute error threshold in some places.
55 #define EXPECT_ROW1_NEAR(a, b, c, d, transform, errorThreshold) \
56 EXPECT_NEAR((a), (transform).matrix().get(0, 0), (errorThreshold)); \
57 EXPECT_NEAR((b), (transform).matrix().get(0, 1), (errorThreshold)); \
58 EXPECT_NEAR((c), (transform).matrix().get(0, 2), (errorThreshold)); \
59 EXPECT_NEAR((d), (transform).matrix().get(0, 3), (errorThreshold));
61 #define EXPECT_ROW2_NEAR(a, b, c, d, transform, errorThreshold) \
62 EXPECT_NEAR((a), (transform).matrix().get(1, 0), (errorThreshold)); \
63 EXPECT_NEAR((b), (transform).matrix().get(1, 1), (errorThreshold)); \
64 EXPECT_NEAR((c), (transform).matrix().get(1, 2), (errorThreshold)); \
65 EXPECT_NEAR((d), (transform).matrix().get(1, 3), (errorThreshold));
67 #define EXPECT_ROW3_NEAR(a, b, c, d, transform, errorThreshold) \
68 EXPECT_NEAR((a), (transform).matrix().get(2, 0), (errorThreshold)); \
69 EXPECT_NEAR((b), (transform).matrix().get(2, 1), (errorThreshold)); \
70 EXPECT_NEAR((c), (transform).matrix().get(2, 2), (errorThreshold)); \
71 EXPECT_NEAR((d), (transform).matrix().get(2, 3), (errorThreshold));
73 bool PointsAreNearlyEqual(const Point3F& lhs,
75 float epsilon = 0.0001f;
76 return lhs.SquaredDistanceTo(rhs) < epsilon;
79 bool MatricesAreNearlyEqual(const Transform& lhs,
80 const Transform& rhs) {
81 float epsilon = 0.0001f;
82 for (int row = 0; row < 4; ++row) {
83 for (int col = 0; col < 4; ++col) {
84 if (std::abs(lhs.matrix().get(row, col) -
85 rhs.matrix().get(row, col)) > epsilon)
92 void InitializeTestMatrix(Transform* transform) {
93 SkMatrix44& matrix = transform->matrix();
94 matrix.set(0, 0, 10.f);
95 matrix.set(1, 0, 11.f);
96 matrix.set(2, 0, 12.f);
97 matrix.set(3, 0, 13.f);
98 matrix.set(0, 1, 14.f);
99 matrix.set(1, 1, 15.f);
100 matrix.set(2, 1, 16.f);
101 matrix.set(3, 1, 17.f);
102 matrix.set(0, 2, 18.f);
103 matrix.set(1, 2, 19.f);
104 matrix.set(2, 2, 20.f);
105 matrix.set(3, 2, 21.f);
106 matrix.set(0, 3, 22.f);
107 matrix.set(1, 3, 23.f);
108 matrix.set(2, 3, 24.f);
109 matrix.set(3, 3, 25.f);
112 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, (*transform));
113 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, (*transform));
114 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, (*transform));
115 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, (*transform));
118 void InitializeTestMatrix2(Transform* transform) {
119 SkMatrix44& matrix = transform->matrix();
120 matrix.set(0, 0, 30.f);
121 matrix.set(1, 0, 31.f);
122 matrix.set(2, 0, 32.f);
123 matrix.set(3, 0, 33.f);
124 matrix.set(0, 1, 34.f);
125 matrix.set(1, 1, 35.f);
126 matrix.set(2, 1, 36.f);
127 matrix.set(3, 1, 37.f);
128 matrix.set(0, 2, 38.f);
129 matrix.set(1, 2, 39.f);
130 matrix.set(2, 2, 40.f);
131 matrix.set(3, 2, 41.f);
132 matrix.set(0, 3, 42.f);
133 matrix.set(1, 3, 43.f);
134 matrix.set(2, 3, 44.f);
135 matrix.set(3, 3, 45.f);
138 EXPECT_ROW1_EQ(30.0f, 34.0f, 38.0f, 42.0f, (*transform));
139 EXPECT_ROW2_EQ(31.0f, 35.0f, 39.0f, 43.0f, (*transform));
140 EXPECT_ROW3_EQ(32.0f, 36.0f, 40.0f, 44.0f, (*transform));
141 EXPECT_ROW4_EQ(33.0f, 37.0f, 41.0f, 45.0f, (*transform));
144 const SkMScalar kApproxZero =
145 SkFloatToMScalar(std::numeric_limits<float>::epsilon());
146 const SkMScalar kApproxOne = 1 - kApproxZero;
148 void InitializeApproxIdentityMatrix(Transform* transform) {
149 SkMatrix44& matrix = transform->matrix();
150 matrix.set(0, 0, kApproxOne);
151 matrix.set(0, 1, kApproxZero);
152 matrix.set(0, 2, kApproxZero);
153 matrix.set(0, 3, kApproxZero);
155 matrix.set(1, 0, kApproxZero);
156 matrix.set(1, 1, kApproxOne);
157 matrix.set(1, 2, kApproxZero);
158 matrix.set(1, 3, kApproxZero);
160 matrix.set(2, 0, kApproxZero);
161 matrix.set(2, 1, kApproxZero);
162 matrix.set(2, 2, kApproxOne);
163 matrix.set(2, 3, kApproxZero);
165 matrix.set(3, 0, kApproxZero);
166 matrix.set(3, 1, kApproxZero);
167 matrix.set(3, 2, kApproxZero);
168 matrix.set(3, 3, kApproxOne);
171 #ifdef SK_MSCALAR_IS_DOUBLE
172 #define ERROR_THRESHOLD 1e-14
174 #define ERROR_THRESHOLD 1e-7
176 #define LOOSE_ERROR_THRESHOLD 1e-7
178 TEST(XFormTest, Equality) {
179 Transform lhs, rhs, interpolated;
180 rhs.matrix().set3x3(1, 2, 3,
184 for (int i = 0; i <= 100; ++i) {
185 for (int row = 0; row < 4; ++row) {
186 for (int col = 0; col < 4; ++col) {
187 float a = lhs.matrix().get(row, col);
188 float b = rhs.matrix().get(row, col);
189 float t = i / 100.0f;
190 interpolated.matrix().set(row, col, a + (b - a) * t);
194 EXPECT_TRUE(rhs == interpolated);
196 EXPECT_TRUE(rhs != interpolated);
201 for (int i = 1; i < 100; ++i) {
205 rhs.Translate(-i, -i);
206 EXPECT_TRUE(lhs != rhs);
207 rhs.Translate(2*i, 2*i);
208 EXPECT_TRUE(lhs == rhs);
212 TEST(XFormTest, ConcatTranslate) {
213 static const struct TestCase {
221 { 0, 0, 10.0f, 20.0f, 10, 20 },
222 { 0, 0, -10.0f, -20.0f, 0, 0 },
223 { 0, 0, -10.0f, -20.0f, -10, -20 },
225 std::numeric_limits<float>::quiet_NaN(),
226 std::numeric_limits<float>::quiet_NaN(),
231 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
232 const TestCase& value = test_cases[i];
233 Transform translation;
234 translation.Translate(value.tx, value.ty);
235 xform = translation * xform;
236 Point3F p1(value.x1, value.y1, 0);
237 Point3F p2(value.x2, value.y2, 0);
238 xform.TransformPoint(&p1);
239 if (value.tx == value.tx &&
240 value.ty == value.ty) {
241 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
246 TEST(XFormTest, ConcatScale) {
247 static const struct TestCase {
256 { 1, std::numeric_limits<float>::quiet_NaN(), 1 }
260 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
261 const TestCase& value = test_cases[i];
263 scale.Scale(value.scale, value.scale);
264 xform = scale * xform;
265 Point3F p1(value.before, value.before, 0);
266 Point3F p2(value.after, value.after, 0);
267 xform.TransformPoint(&p1);
268 if (value.scale == value.scale) {
269 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
274 TEST(XFormTest, ConcatRotate) {
275 static const struct TestCase {
282 { 1, 0, 90.0f, 0, 1 },
283 { 1, 0, -90.0f, 1, 0 },
284 { 1, 0, 90.0f, 0, 1 },
285 { 1, 0, 360.0f, 0, 1 },
286 { 1, 0, 0.0f, 0, 1 },
287 { 1, 0, std::numeric_limits<float>::quiet_NaN(), 1, 0 }
291 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
292 const TestCase& value = test_cases[i];
294 rotation.Rotate(value.degrees);
295 xform = rotation * xform;
296 Point3F p1(value.x1, value.y1, 0);
297 Point3F p2(value.x2, value.y2, 0);
298 xform.TransformPoint(&p1);
299 if (value.degrees == value.degrees) {
300 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
305 TEST(XFormTest, SetTranslate) {
306 static const struct TestCase {
311 { 0, 0, 10.0f, 20.0f, 10, 20 },
312 { 10, 20, 10.0f, 20.0f, 20, 40 },
313 { 10, 20, 0.0f, 0.0f, 10, 20 },
315 std::numeric_limits<float>::quiet_NaN(),
316 std::numeric_limits<float>::quiet_NaN(),
320 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
321 const TestCase& value = test_cases[i];
322 for (int k = 0; k < 3; ++k) {
327 p1.SetPoint(value.x1, 0, 0);
328 p2.SetPoint(value.x2, 0, 0);
329 xform.Translate(value.tx, 0.0);
332 p1.SetPoint(0, value.y1, 0);
333 p2.SetPoint(0, value.y2, 0);
334 xform.Translate(0.0, value.ty);
337 p1.SetPoint(value.x1, value.y1, 0);
338 p2.SetPoint(value.x2, value.y2, 0);
339 xform.Translate(value.tx, value.ty);
343 xform.TransformPoint(&p1);
344 if (value.tx == value.tx &&
345 value.ty == value.ty) {
346 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
347 xform.TransformPointReverse(&p1);
348 EXPECT_TRUE(PointsAreNearlyEqual(p1, p0));
354 TEST(XFormTest, SetScale) {
355 static const struct TestCase {
364 { 1, std::numeric_limits<float>::quiet_NaN(), 0 },
367 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
368 const TestCase& value = test_cases[i];
369 for (int k = 0; k < 3; ++k) {
374 p1.SetPoint(value.before, 0, 0);
375 p2.SetPoint(value.after, 0, 0);
376 xform.Scale(value.s, 1.0);
379 p1.SetPoint(0, value.before, 0);
380 p2.SetPoint(0, value.after, 0);
381 xform.Scale(1.0, value.s);
384 p1.SetPoint(value.before, value.before, 0);
385 p2.SetPoint(value.after, value.after, 0);
386 xform.Scale(value.s, value.s);
390 xform.TransformPoint(&p1);
391 if (value.s == value.s) {
392 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
393 if (value.s != 0.0f) {
394 xform.TransformPointReverse(&p1);
395 EXPECT_TRUE(PointsAreNearlyEqual(p1, p0));
402 TEST(XFormTest, SetRotate) {
403 static const struct SetRotateCase {
409 } set_rotate_cases[] = {
410 { 100, 0, 90.0f, 0, 100 },
411 { 0, 0, 90.0f, 0, 0 },
412 { 0, 100, 90.0f, -100, 0 },
413 { 0, 1, -90.0f, 1, 0 },
414 { 100, 0, 0.0f, 100, 0 },
415 { 0, 0, 0.0f, 0, 0 },
416 { 0, 0, std::numeric_limits<float>::quiet_NaN(), 0, 0 },
417 { 100, 0, 360.0f, 100, 0 }
420 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(set_rotate_cases); ++i) {
421 const SetRotateCase& value = set_rotate_cases[i];
423 Point3F p1(value.x, value.y, 0);
424 Point3F p2(value.xprime, value.yprime, 0);
427 xform.Rotate(value.degree);
428 // just want to make sure that we don't crash in the case of NaN.
429 if (value.degree == value.degree) {
430 xform.TransformPoint(&p1);
431 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
432 xform.TransformPointReverse(&p1);
433 EXPECT_TRUE(PointsAreNearlyEqual(p1, p0));
439 TEST(XFormTest, ConcatTranslate2D) {
440 static const struct TestCase {
448 { 0, 0, 10.0f, 20.0f, 10, 20},
449 { 0, 0, -10.0f, -20.0f, 0, 0},
450 { 0, 0, -10.0f, -20.0f, -10, -20},
452 std::numeric_limits<float>::quiet_NaN(),
453 std::numeric_limits<float>::quiet_NaN(),
458 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
459 const TestCase& value = test_cases[i];
460 Transform translation;
461 translation.Translate(value.tx, value.ty);
462 xform = translation * xform;
463 Point p1(value.x1, value.y1);
464 Point p2(value.x2, value.y2);
465 xform.TransformPoint(&p1);
466 if (value.tx == value.tx &&
467 value.ty == value.ty) {
468 EXPECT_EQ(p1.x(), p2.x());
469 EXPECT_EQ(p1.y(), p2.y());
474 TEST(XFormTest, ConcatScale2D) {
475 static const struct TestCase {
484 { 1, std::numeric_limits<float>::quiet_NaN(), 1}
488 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
489 const TestCase& value = test_cases[i];
491 scale.Scale(value.scale, value.scale);
492 xform = scale * xform;
493 Point p1(value.before, value.before);
494 Point p2(value.after, value.after);
495 xform.TransformPoint(&p1);
496 if (value.scale == value.scale) {
497 EXPECT_EQ(p1.x(), p2.x());
498 EXPECT_EQ(p1.y(), p2.y());
503 TEST(XFormTest, ConcatRotate2D) {
504 static const struct TestCase {
511 { 1, 0, 90.0f, 0, 1},
512 { 1, 0, -90.0f, 1, 0},
513 { 1, 0, 90.0f, 0, 1},
514 { 1, 0, 360.0f, 0, 1},
516 { 1, 0, std::numeric_limits<float>::quiet_NaN(), 1, 0}
520 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
521 const TestCase& value = test_cases[i];
523 rotation.Rotate(value.degrees);
524 xform = rotation * xform;
525 Point p1(value.x1, value.y1);
526 Point p2(value.x2, value.y2);
527 xform.TransformPoint(&p1);
528 if (value.degrees == value.degrees) {
529 EXPECT_EQ(p1.x(), p2.x());
530 EXPECT_EQ(p1.y(), p2.y());
535 TEST(XFormTest, SetTranslate2D) {
536 static const struct TestCase {
541 { 0, 0, 10.0f, 20.0f, 10, 20},
542 { 10, 20, 10.0f, 20.0f, 20, 40},
543 { 10, 20, 0.0f, 0.0f, 10, 20},
545 std::numeric_limits<float>::quiet_NaN(),
546 std::numeric_limits<float>::quiet_NaN(),
550 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
551 const TestCase& value = test_cases[i];
552 for (int j = -1; j < 2; ++j) {
553 for (int k = 0; k < 3; ++k) {
554 float epsilon = 0.0001f;
559 p1.SetPoint(value.x1, 0);
560 p2.SetPoint(value.x2, 0);
561 xform.Translate(value.tx + j * epsilon, 0.0);
564 p1.SetPoint(0, value.y1);
565 p2.SetPoint(0, value.y2);
566 xform.Translate(0.0, value.ty + j * epsilon);
569 p1.SetPoint(value.x1, value.y1);
570 p2.SetPoint(value.x2, value.y2);
571 xform.Translate(value.tx + j * epsilon,
572 value.ty + j * epsilon);
576 xform.TransformPoint(&p1);
577 if (value.tx == value.tx &&
578 value.ty == value.ty) {
579 EXPECT_EQ(p1.x(), p2.x());
580 EXPECT_EQ(p1.y(), p2.y());
581 xform.TransformPointReverse(&p1);
582 EXPECT_EQ(p1.x(), p0.x());
583 EXPECT_EQ(p1.y(), p0.y());
590 TEST(XFormTest, SetScale2D) {
591 static const struct TestCase {
600 { 1, std::numeric_limits<float>::quiet_NaN(), 0},
603 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
604 const TestCase& value = test_cases[i];
605 for (int j = -1; j < 2; ++j) {
606 for (int k = 0; k < 3; ++k) {
607 float epsilon = 0.0001f;
612 p1.SetPoint(value.before, 0);
613 p2.SetPoint(value.after, 0);
614 xform.Scale(value.s + j * epsilon, 1.0);
617 p1.SetPoint(0, value.before);
618 p2.SetPoint(0, value.after);
619 xform.Scale(1.0, value.s + j * epsilon);
622 p1.SetPoint(value.before,
624 p2.SetPoint(value.after,
626 xform.Scale(value.s + j * epsilon,
627 value.s + j * epsilon);
631 xform.TransformPoint(&p1);
632 if (value.s == value.s) {
633 EXPECT_EQ(p1.x(), p2.x());
634 EXPECT_EQ(p1.y(), p2.y());
635 if (value.s != 0.0f) {
636 xform.TransformPointReverse(&p1);
637 EXPECT_EQ(p1.x(), p0.x());
638 EXPECT_EQ(p1.y(), p0.y());
646 TEST(XFormTest, SetRotate2D) {
647 static const struct SetRotateCase {
653 } set_rotate_cases[] = {
654 { 100, 0, 90.0f, 0, 100},
655 { 0, 0, 90.0f, 0, 0},
656 { 0, 100, 90.0f, -100, 0},
657 { 0, 1, -90.0f, 1, 0},
658 { 100, 0, 0.0f, 100, 0},
660 { 0, 0, std::numeric_limits<float>::quiet_NaN(), 0, 0},
661 { 100, 0, 360.0f, 100, 0}
664 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(set_rotate_cases); ++i) {
665 const SetRotateCase& value = set_rotate_cases[i];
666 for (int j = 1; j >= -1; --j) {
667 float epsilon = 0.1f;
668 Point pt(value.x, value.y);
670 // should be invariant to small floating point errors.
671 xform.Rotate(value.degree + j * epsilon);
672 // just want to make sure that we don't crash in the case of NaN.
673 if (value.degree == value.degree) {
674 xform.TransformPoint(&pt);
675 EXPECT_EQ(value.xprime, pt.x());
676 EXPECT_EQ(value.yprime, pt.y());
677 xform.TransformPointReverse(&pt);
678 EXPECT_EQ(pt.x(), value.x);
679 EXPECT_EQ(pt.y(), value.y);
685 TEST(XFormTest, TransformPointWithExtremePerspective) {
686 Point3F point(1.f, 1.f, 1.f);
687 Transform perspective;
688 perspective.ApplyPerspectiveDepth(1.f);
689 Point3F transformed = point;
690 perspective.TransformPoint(&transformed);
691 EXPECT_EQ(point.ToString(), transformed.ToString());
694 perspective.MakeIdentity();
695 perspective.ApplyPerspectiveDepth(1.1f);
696 perspective.TransformPoint(&transformed);
697 EXPECT_FLOAT_EQ(11.f, transformed.x());
698 EXPECT_FLOAT_EQ(11.f, transformed.y());
699 EXPECT_FLOAT_EQ(11.f, transformed.z());
702 TEST(XFormTest, BlendTranslate) {
704 for (int i = -5; i < 15; ++i) {
706 to.Translate3d(1, 1, 1);
708 EXPECT_TRUE(to.Blend(from, t));
709 EXPECT_FLOAT_EQ(t, to.matrix().get(0, 3));
710 EXPECT_FLOAT_EQ(t, to.matrix().get(1, 3));
711 EXPECT_FLOAT_EQ(t, to.matrix().get(2, 3));
715 TEST(XFormTest, BlendRotate) {
723 for (size_t index = 0; index < ARRAYSIZE_UNSAFE(axes); ++index) {
724 for (int i = -5; i < 15; ++i) {
726 to.RotateAbout(axes[index], 90);
728 EXPECT_TRUE(to.Blend(from, t));
731 expected.RotateAbout(axes[index], 90 * t);
733 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
739 // http://crbug.com/406574
740 #define MAYBE_BlendRotateFollowsShortestPath DISABLED_BlendRotateFollowsShortestPath
742 #define MAYBE_BlendRotateFollowsShortestPath BlendRotateFollowsShortestPath
744 TEST(XFormTest, MAYBE_BlendRotateFollowsShortestPath) {
745 // Verify that we interpolate along the shortest path regardless of whether
746 // this path crosses the 180-degree point.
753 for (size_t index = 0; index < ARRAYSIZE_UNSAFE(axes); ++index) {
754 for (int i = -5; i < 15; ++i) {
756 from1.RotateAbout(axes[index], 130.0);
758 to1.RotateAbout(axes[index], 175.0);
761 from2.RotateAbout(axes[index], 140.0);
763 to2.RotateAbout(axes[index], 185.0);
766 EXPECT_TRUE(to1.Blend(from1, t));
767 EXPECT_TRUE(to2.Blend(from2, t));
770 expected1.RotateAbout(axes[index], 130.0 + 45.0 * t);
773 expected2.RotateAbout(axes[index], 140.0 + 45.0 * t);
775 EXPECT_TRUE(MatricesAreNearlyEqual(expected1, to1));
776 EXPECT_TRUE(MatricesAreNearlyEqual(expected2, to2));
781 TEST(XFormTest, CanBlend180DegreeRotation) {
789 for (size_t index = 0; index < ARRAYSIZE_UNSAFE(axes); ++index) {
790 for (int i = -5; i < 15; ++i) {
792 to.RotateAbout(axes[index], 180.0);
794 EXPECT_TRUE(to.Blend(from, t));
796 // A 180 degree rotation is exactly opposite on the sphere, therefore
797 // either great circle arc to it is equivalent (and numerical precision
798 // will determine which is closer). Test both directions.
800 expected1.RotateAbout(axes[index], 180.0 * t);
802 expected2.RotateAbout(axes[index], -180.0 * t);
804 EXPECT_TRUE(MatricesAreNearlyEqual(expected1, to) ||
805 MatricesAreNearlyEqual(expected2, to))
806 << "axis: " << index << ", i: " << i;
812 // http://crbug.com/406574
813 #define MAYBE_BlendScale DISABLED_BlendScale
815 #define MAYBE_BlendScale BlendScale
817 TEST(XFormTest, MAYBE_BlendScale) {
819 for (int i = -5; i < 15; ++i) {
823 EXPECT_TRUE(to.Blend(from, t));
824 EXPECT_FLOAT_EQ(t * 4 + 1, to.matrix().get(0, 0)) << "i: " << i;
825 EXPECT_FLOAT_EQ(t * 3 + 1, to.matrix().get(1, 1)) << "i: " << i;
826 EXPECT_FLOAT_EQ(t * 2 + 1, to.matrix().get(2, 2)) << "i: " << i;
830 TEST(XFormTest, BlendSkew) {
832 for (int i = 0; i < 2; ++i) {
838 expected.SkewX(t * 10);
839 expected.SkewY(t * 5);
840 EXPECT_TRUE(to.Blend(from, t));
841 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
845 TEST(XFormTest, ExtrapolateSkew) {
847 for (int i = -1; i < 2; ++i) {
852 expected.SkewX(t * 20);
853 EXPECT_TRUE(to.Blend(from, t));
854 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
859 // http://crbug.com/406574
860 #define MAYBE_BlendPerspective DISABLED_BlendPerspective
862 #define MAYBE_BlendPerspective BlendPerspective
864 TEST(XFormTest, MAYBE_BlendPerspective) {
866 from.ApplyPerspectiveDepth(200);
867 for (int i = -1; i < 3; ++i) {
869 to.ApplyPerspectiveDepth(800);
871 double depth = 1.0 / ((1.0 / 200) * (1.0 - t) + (1.0 / 800) * t);
873 expected.ApplyPerspectiveDepth(depth);
874 EXPECT_TRUE(to.Blend(from, t));
875 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
879 TEST(XFormTest, BlendIdentity) {
882 EXPECT_TRUE(to.Blend(from, 0.5));
886 TEST(XFormTest, CannotBlendSingularMatrix) {
889 to.matrix().set(1, 1, SkDoubleToMScalar(0));
890 EXPECT_FALSE(to.Blend(from, 0.5));
893 TEST(XFormTest, VerifyBlendForTranslation) {
895 from.Translate3d(100.0, 200.0, 100.0);
899 to.Translate3d(200.0, 100.0, 300.0);
904 to.Translate3d(200.0, 100.0, 300.0);
905 to.Blend(from, 0.25);
906 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 125.0f, to);
907 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 175.0f, to);
908 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 150.0f, to);
909 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
912 to.Translate3d(200.0, 100.0, 300.0);
914 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 150.0f, to);
915 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 150.0f, to);
916 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 200.0f, to);
917 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
920 to.Translate3d(200.0, 100.0, 300.0);
922 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 200.0f, to);
923 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 100.0f, to);
924 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 300.0f, to);
925 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
928 TEST(XFormTest, VerifyBlendForScale) {
930 from.Scale3d(100.0, 200.0, 100.0);
934 to.Scale3d(200.0, 100.0, 300.0);
939 to.Scale3d(200.0, 100.0, 300.0);
940 to.Blend(from, 0.25);
941 EXPECT_ROW1_EQ(125.0f, 0.0f, 0.0f, 0.0f, to);
942 EXPECT_ROW2_EQ(0.0f, 175.0f, 0.0f, 0.0f, to);
943 EXPECT_ROW3_EQ(0.0f, 0.0f, 150.0f, 0.0f, to);
944 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
947 to.Scale3d(200.0, 100.0, 300.0);
949 EXPECT_ROW1_EQ(150.0f, 0.0f, 0.0f, 0.0f, to);
950 EXPECT_ROW2_EQ(0.0f, 150.0f, 0.0f, 0.0f, to);
951 EXPECT_ROW3_EQ(0.0f, 0.0f, 200.0f, 0.0f, to);
952 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
955 to.Scale3d(200.0, 100.0, 300.0);
957 EXPECT_ROW1_EQ(200.0f, 0.0f, 0.0f, 0.0f, to);
958 EXPECT_ROW2_EQ(0.0f, 100.0f, 0.0f, 0.0f, to);
959 EXPECT_ROW3_EQ(0.0f, 0.0f, 300.0f, 0.0f, to);
960 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
963 TEST(XFormTest, VerifyBlendForSkewX) {
976 EXPECT_ROW1_EQ(1.0f, 0.5f, 0.0f, 0.0f, to);
977 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
978 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
979 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
983 to.Blend(from, 0.25);
984 EXPECT_ROW1_EQ(1.0f, 0.25f, 0.0f, 0.0f, to);
985 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
986 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
987 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
992 EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, to);
993 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
994 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
995 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
998 TEST(XFormTest, VerifyBlendForSkewY) {
999 // NOTE CAREFULLY: Decomposition of skew and rotation terms of the matrix
1000 // is inherently underconstrained, and so it does not always compute the
1001 // originally intended skew parameters. The current implementation uses QR
1002 // decomposition, which decomposes the shear into a rotation + non-uniform
1005 // It is unlikely that the decomposition implementation will need to change
1006 // very often, so to get any test coverage, the compromise is to verify the
1007 // exact matrix that the.Blend() operation produces.
1009 // This problem also potentially exists for skewX, but the current QR
1010 // decomposition implementation just happens to decompose those test
1011 // matrices intuitively.
1013 // Unfortunately, this case suffers from uncomfortably large precision
1022 to.Blend(from, 0.0);
1023 EXPECT_EQ(from, to);
1027 to.Blend(from, 0.25);
1028 EXPECT_ROW1_NEAR(1.0823489449280947471976333,
1029 0.0464370719145053845178239,
1033 LOOSE_ERROR_THRESHOLD);
1034 EXPECT_ROW2_NEAR(0.2152925909665224513123150,
1035 0.9541702441750861130032035,
1039 LOOSE_ERROR_THRESHOLD);
1040 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
1041 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1045 to.Blend(from, 0.5);
1046 EXPECT_ROW1_NEAR(1.1152212925809066312865525,
1047 0.0676495144007326631996335,
1051 LOOSE_ERROR_THRESHOLD);
1052 EXPECT_ROW2_NEAR(0.4619397844342648662419037,
1053 0.9519009045724774464858342,
1057 LOOSE_ERROR_THRESHOLD);
1058 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
1059 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1063 to.Blend(from, 1.0);
1064 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD);
1065 EXPECT_ROW2_NEAR(1.0, 1.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD);
1066 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
1067 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1071 // http://crbug.com/406574
1072 #define MAYBE_VerifyBlendForRotationAboutX DISABLED_VerifyBlendForRotationAboutX
1074 #define MAYBE_VerifyBlendForRotationAboutX VerifyBlendForRotationAboutX
1076 TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutX) {
1077 // Even though.Blending uses quaternions, axis-aligned rotations should.
1078 // Blend the same with quaternions or Euler angles. So we can test
1079 // rotation.Blending by comparing against manually specified matrices from
1083 from.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 0.0);
1087 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1088 to.Blend(from, 0.0);
1089 EXPECT_EQ(from, to);
1091 double expectedRotationAngle = 22.5 * M_PI / 180.0;
1093 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1094 to.Blend(from, 0.25);
1095 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1096 EXPECT_ROW2_NEAR(0.0,
1097 std::cos(expectedRotationAngle),
1098 -std::sin(expectedRotationAngle),
1102 EXPECT_ROW3_NEAR(0.0,
1103 std::sin(expectedRotationAngle),
1104 std::cos(expectedRotationAngle),
1108 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1110 expectedRotationAngle = 45.0 * M_PI / 180.0;
1112 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1113 to.Blend(from, 0.5);
1114 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1115 EXPECT_ROW2_NEAR(0.0,
1116 std::cos(expectedRotationAngle),
1117 -std::sin(expectedRotationAngle),
1121 EXPECT_ROW3_NEAR(0.0,
1122 std::sin(expectedRotationAngle),
1123 std::cos(expectedRotationAngle),
1127 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1130 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1131 to.Blend(from, 1.0);
1132 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1133 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, to, ERROR_THRESHOLD);
1134 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1135 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1139 // http://crbug.com/406574
1140 #define MAYBE_VerifyBlendForRotationAboutY DISABLED_VerifyBlendForRotationAboutY
1142 #define MAYBE_VerifyBlendForRotationAboutY VerifyBlendForRotationAboutY
1144 TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutY) {
1146 from.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 0.0);
1150 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1151 to.Blend(from, 0.0);
1152 EXPECT_EQ(from, to);
1154 double expectedRotationAngle = 22.5 * M_PI / 180.0;
1156 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1157 to.Blend(from, 0.25);
1158 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1160 std::sin(expectedRotationAngle),
1164 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1165 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle),
1167 std::cos(expectedRotationAngle),
1171 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1173 expectedRotationAngle = 45.0 * M_PI / 180.0;
1175 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1176 to.Blend(from, 0.5);
1177 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1179 std::sin(expectedRotationAngle),
1183 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1184 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle),
1186 std::cos(expectedRotationAngle),
1190 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1193 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1194 to.Blend(from, 1.0);
1195 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1196 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1197 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1198 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1202 // http://crbug.com/406574
1203 #define MAYBE_VerifyBlendForRotationAboutZ DISABLED_VerifyBlendForRotationAboutZ
1205 #define MAYBE_VerifyBlendForRotationAboutZ VerifyBlendForRotationAboutZ
1207 TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutZ) {
1209 from.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 0.0);
1213 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1214 to.Blend(from, 0.0);
1215 EXPECT_EQ(from, to);
1217 double expectedRotationAngle = 22.5 * M_PI / 180.0;
1219 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1220 to.Blend(from, 0.25);
1221 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1222 -std::sin(expectedRotationAngle),
1227 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle),
1228 std::cos(expectedRotationAngle),
1233 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1234 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1236 expectedRotationAngle = 45.0 * M_PI / 180.0;
1238 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1239 to.Blend(from, 0.5);
1240 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1241 -std::sin(expectedRotationAngle),
1246 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle),
1247 std::cos(expectedRotationAngle),
1252 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1253 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1256 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1257 to.Blend(from, 1.0);
1258 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1259 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1260 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1261 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1264 TEST(XFormTest, VerifyBlendForCompositeTransform) {
1265 // Verify that the.Blending was done with a decomposition in correct order
1266 // by blending a composite transform. Using matrix x vector notation
1267 // (Ax = b, where x is column vector), the ordering should be:
1268 // perspective * translation * rotation * skew * scale
1270 // It is not as important (or meaningful) to check intermediate
1271 // interpolations; order of operations will be tested well enough by the
1272 // end cases that are easier to specify.
1277 Transform expectedEndOfAnimation;
1278 expectedEndOfAnimation.ApplyPerspectiveDepth(1.0);
1279 expectedEndOfAnimation.Translate3d(10.0, 20.0, 30.0);
1280 expectedEndOfAnimation.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 25.0);
1281 expectedEndOfAnimation.SkewY(45.0);
1282 expectedEndOfAnimation.Scale3d(6.0, 7.0, 8.0);
1284 to = expectedEndOfAnimation;
1285 to.Blend(from, 0.0);
1286 EXPECT_EQ(from, to);
1288 to = expectedEndOfAnimation;
1289 // We short circuit if blend is >= 1, so to check the numerics, we will
1290 // check that we get close to what we expect when we're nearly done
1292 to.Blend(from, .99999f);
1294 // Recomposing the matrix results in a normalized matrix, so to verify we
1295 // need to normalize the expectedEndOfAnimation before comparing elements.
1296 // Normalizing means dividing everything by expectedEndOfAnimation.m44().
1297 Transform normalizedExpectedEndOfAnimation = expectedEndOfAnimation;
1298 Transform normalizationMatrix;
1299 normalizationMatrix.matrix().set(
1302 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1303 normalizationMatrix.matrix().set(
1306 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1307 normalizationMatrix.matrix().set(
1310 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1311 normalizationMatrix.matrix().set(
1314 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1315 normalizedExpectedEndOfAnimation.PreconcatTransform(normalizationMatrix);
1317 EXPECT_TRUE(MatricesAreNearlyEqual(normalizedExpectedEndOfAnimation, to));
1320 TEST(XFormTest, DecomposedTransformCtor) {
1321 DecomposedTransform decomp;
1322 for (int i = 0; i < 3; ++i) {
1323 EXPECT_EQ(0.0, decomp.translate[i]);
1324 EXPECT_EQ(1.0, decomp.scale[i]);
1325 EXPECT_EQ(0.0, decomp.skew[i]);
1326 EXPECT_EQ(0.0, decomp.quaternion[i]);
1327 EXPECT_EQ(0.0, decomp.perspective[i]);
1329 EXPECT_EQ(1.0, decomp.quaternion[3]);
1330 EXPECT_EQ(1.0, decomp.perspective[3]);
1332 Transform composed = ComposeTransform(decomp);
1333 EXPECT_TRUE(MatricesAreNearlyEqual(identity, composed));
1336 TEST(XFormTest, FactorTRS) {
1337 for (int degrees = 0; degrees < 180; ++degrees) {
1338 // build a transformation matrix.
1339 gfx::Transform transform;
1340 transform.Translate(degrees * 2, -degrees * 3);
1341 transform.Rotate(degrees);
1342 transform.Scale(degrees + 1, 2 * degrees + 1);
1344 // factor the matrix
1345 DecomposedTransform decomp;
1346 bool success = DecomposeTransform(&decomp, transform);
1347 EXPECT_TRUE(success);
1348 EXPECT_FLOAT_EQ(decomp.translate[0], degrees * 2);
1349 EXPECT_FLOAT_EQ(decomp.translate[1], -degrees * 3);
1351 std::acos(SkMScalarToDouble(decomp.quaternion[3])) * 360.0 / M_PI;
1352 while (rotation < 0.0)
1354 while (rotation > 360.0)
1357 const float epsilon = 0.00015f;
1358 EXPECT_NEAR(rotation, degrees, epsilon);
1359 EXPECT_NEAR(decomp.scale[0], degrees + 1, epsilon);
1360 EXPECT_NEAR(decomp.scale[1], 2 * degrees + 1, epsilon);
1364 TEST(XFormTest, IntegerTranslation) {
1365 gfx::Transform transform;
1366 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1368 transform.Translate3d(1, 2, 3);
1369 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1371 transform.MakeIdentity();
1372 transform.Translate3d(-1, -2, -3);
1373 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1375 transform.MakeIdentity();
1376 transform.Translate3d(4.5f, 0, 0);
1377 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1379 transform.MakeIdentity();
1380 transform.Translate3d(0, -6.7f, 0);
1381 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1383 transform.MakeIdentity();
1384 transform.Translate3d(0, 0, 8.9f);
1385 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1388 TEST(XFormTest, verifyMatrixInversion) {
1390 // Invert a translation
1391 gfx::Transform translation;
1392 translation.Translate3d(2.0, 3.0, 4.0);
1393 EXPECT_TRUE(translation.IsInvertible());
1395 gfx::Transform inverse_translation;
1396 bool is_invertible = translation.GetInverse(&inverse_translation);
1397 EXPECT_TRUE(is_invertible);
1398 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, -2.0f, inverse_translation);
1399 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, -3.0f, inverse_translation);
1400 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, -4.0f, inverse_translation);
1401 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_translation);
1405 // Invert a non-uniform scale
1406 gfx::Transform scale;
1407 scale.Scale3d(4.0, 10.0, 100.0);
1408 EXPECT_TRUE(scale.IsInvertible());
1410 gfx::Transform inverse_scale;
1411 bool is_invertible = scale.GetInverse(&inverse_scale);
1412 EXPECT_TRUE(is_invertible);
1413 EXPECT_ROW1_EQ(0.25f, 0.0f, 0.0f, 0.0f, inverse_scale);
1414 EXPECT_ROW2_EQ(0.0f, 0.1f, 0.0f, 0.0f, inverse_scale);
1415 EXPECT_ROW3_EQ(0.0f, 0.0f, 0.01f, 0.0f, inverse_scale);
1416 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_scale);
1420 // Try to invert a matrix that is not invertible.
1421 // The inverse() function should reset the output matrix to identity.
1422 gfx::Transform uninvertible;
1423 uninvertible.matrix().set(0, 0, 0.f);
1424 uninvertible.matrix().set(1, 1, 0.f);
1425 uninvertible.matrix().set(2, 2, 0.f);
1426 uninvertible.matrix().set(3, 3, 0.f);
1427 EXPECT_FALSE(uninvertible.IsInvertible());
1429 gfx::Transform inverse_of_uninvertible;
1431 // Add a scale just to more easily ensure that inverse_of_uninvertible is
1432 // reset to identity.
1433 inverse_of_uninvertible.Scale3d(4.0, 10.0, 100.0);
1435 bool is_invertible = uninvertible.GetInverse(&inverse_of_uninvertible);
1436 EXPECT_FALSE(is_invertible);
1437 EXPECT_TRUE(inverse_of_uninvertible.IsIdentity());
1438 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, inverse_of_uninvertible);
1439 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, inverse_of_uninvertible);
1440 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, inverse_of_uninvertible);
1441 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_of_uninvertible);
1445 TEST(XFormTest, verifyBackfaceVisibilityBasicCases) {
1446 Transform transform;
1448 transform.MakeIdentity();
1449 EXPECT_FALSE(transform.IsBackFaceVisible());
1451 transform.MakeIdentity();
1452 transform.RotateAboutYAxis(80.0);
1453 EXPECT_FALSE(transform.IsBackFaceVisible());
1455 transform.MakeIdentity();
1456 transform.RotateAboutYAxis(100.0);
1457 EXPECT_TRUE(transform.IsBackFaceVisible());
1459 // Edge case, 90 degree rotation should return false.
1460 transform.MakeIdentity();
1461 transform.RotateAboutYAxis(90.0);
1462 EXPECT_FALSE(transform.IsBackFaceVisible());
1465 TEST(XFormTest, verifyBackfaceVisibilityForPerspective) {
1466 Transform layer_space_to_projection_plane;
1468 // This tests if IsBackFaceVisible works properly under perspective
1469 // transforms. Specifically, layers that may have their back face visible in
1470 // orthographic projection, may not actually have back face visible under
1471 // perspective projection.
1473 // Case 1: Layer is rotated by slightly more than 90 degrees, at the center
1474 // of the prespective projection. In this case, the layer's back-side
1475 // is visible to the camera.
1476 layer_space_to_projection_plane.MakeIdentity();
1477 layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0);
1478 layer_space_to_projection_plane.Translate3d(0.0, 0.0, 0.0);
1479 layer_space_to_projection_plane.RotateAboutYAxis(100.0);
1480 EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible());
1482 // Case 2: Layer is rotated by slightly more than 90 degrees, but shifted off
1483 // to the side of the camera. Because of the wide field-of-view, the
1484 // layer's front side is still visible.
1486 // |<-- front side of layer is visible to camera
1491 // |\ /<-- camera field of view
1493 // back side of layer -->| \ /
1494 // \./ <-- camera origin
1496 layer_space_to_projection_plane.MakeIdentity();
1497 layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0);
1498 layer_space_to_projection_plane.Translate3d(-10.0, 0.0, 0.0);
1499 layer_space_to_projection_plane.RotateAboutYAxis(100.0);
1500 EXPECT_FALSE(layer_space_to_projection_plane.IsBackFaceVisible());
1502 // Case 3: Additionally rotating the layer by 180 degrees should of course
1503 // show the opposite result of case 2.
1504 layer_space_to_projection_plane.RotateAboutYAxis(180.0);
1505 EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible());
1508 TEST(XFormTest, verifyDefaultConstructorCreatesIdentityMatrix) {
1510 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1511 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1512 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1513 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1514 EXPECT_TRUE(A.IsIdentity());
1517 TEST(XFormTest, verifyCopyConstructor) {
1519 InitializeTestMatrix(&A);
1521 // Copy constructor should produce exact same elements as matrix A.
1523 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B);
1524 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B);
1525 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B);
1526 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B);
1529 TEST(XFormTest, verifyConstructorFor16Elements) {
1530 Transform transform(1.0, 2.0, 3.0, 4.0,
1532 9.0, 10.0, 11.0, 12.0,
1533 13.0, 14.0, 15.0, 16.0);
1535 EXPECT_ROW1_EQ(1.0f, 2.0f, 3.0f, 4.0f, transform);
1536 EXPECT_ROW2_EQ(5.0f, 6.0f, 7.0f, 8.0f, transform);
1537 EXPECT_ROW3_EQ(9.0f, 10.0f, 11.0f, 12.0f, transform);
1538 EXPECT_ROW4_EQ(13.0f, 14.0f, 15.0f, 16.0f, transform);
1541 TEST(XFormTest, verifyConstructorFor2dElements) {
1542 Transform transform(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
1544 EXPECT_ROW1_EQ(1.0f, 2.0f, 0.0f, 5.0f, transform);
1545 EXPECT_ROW2_EQ(3.0f, 4.0f, 0.0f, 6.0f, transform);
1546 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, transform);
1547 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, transform);
1551 TEST(XFormTest, verifyAssignmentOperator) {
1553 InitializeTestMatrix(&A);
1555 InitializeTestMatrix2(&B);
1557 InitializeTestMatrix2(&C);
1560 // Both B and C should now have been re-assigned to the value of A.
1561 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B);
1562 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B);
1563 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B);
1564 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B);
1566 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, C);
1567 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, C);
1568 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, C);
1569 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, C);
1572 TEST(XFormTest, verifyEqualsBooleanOperator) {
1574 InitializeTestMatrix(&A);
1577 InitializeTestMatrix(&B);
1578 EXPECT_TRUE(A == B);
1580 // Modifying multiple elements should cause equals operator to return false.
1582 InitializeTestMatrix2(&C);
1583 EXPECT_FALSE(A == C);
1585 // Modifying any one individual element should cause equals operator to
1589 D.matrix().set(0, 0, 0.f);
1590 EXPECT_FALSE(A == D);
1593 D.matrix().set(1, 0, 0.f);
1594 EXPECT_FALSE(A == D);
1597 D.matrix().set(2, 0, 0.f);
1598 EXPECT_FALSE(A == D);
1601 D.matrix().set(3, 0, 0.f);
1602 EXPECT_FALSE(A == D);
1605 D.matrix().set(0, 1, 0.f);
1606 EXPECT_FALSE(A == D);
1609 D.matrix().set(1, 1, 0.f);
1610 EXPECT_FALSE(A == D);
1613 D.matrix().set(2, 1, 0.f);
1614 EXPECT_FALSE(A == D);
1617 D.matrix().set(3, 1, 0.f);
1618 EXPECT_FALSE(A == D);
1621 D.matrix().set(0, 2, 0.f);
1622 EXPECT_FALSE(A == D);
1625 D.matrix().set(1, 2, 0.f);
1626 EXPECT_FALSE(A == D);
1629 D.matrix().set(2, 2, 0.f);
1630 EXPECT_FALSE(A == D);
1633 D.matrix().set(3, 2, 0.f);
1634 EXPECT_FALSE(A == D);
1637 D.matrix().set(0, 3, 0.f);
1638 EXPECT_FALSE(A == D);
1641 D.matrix().set(1, 3, 0.f);
1642 EXPECT_FALSE(A == D);
1645 D.matrix().set(2, 3, 0.f);
1646 EXPECT_FALSE(A == D);
1649 D.matrix().set(3, 3, 0.f);
1650 EXPECT_FALSE(A == D);
1653 TEST(XFormTest, verifyMultiplyOperator) {
1655 InitializeTestMatrix(&A);
1658 InitializeTestMatrix2(&B);
1660 Transform C = A * B;
1661 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, C);
1662 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, C);
1663 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, C);
1664 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, C);
1666 // Just an additional sanity check; matrix multiplication is not commutative.
1667 EXPECT_FALSE(A * B == B * A);
1670 TEST(XFormTest, verifyMultiplyAndAssignOperator) {
1672 InitializeTestMatrix(&A);
1675 InitializeTestMatrix2(&B);
1678 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
1679 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
1680 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
1681 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
1683 // Just an additional sanity check; matrix multiplication is not commutative.
1688 EXPECT_FALSE(C == D);
1691 TEST(XFormTest, verifyMatrixMultiplication) {
1693 InitializeTestMatrix(&A);
1696 InitializeTestMatrix2(&B);
1698 A.PreconcatTransform(B);
1699 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
1700 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
1701 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
1702 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
1705 TEST(XFormTest, verifyMakeIdentiy) {
1707 InitializeTestMatrix(&A);
1709 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1710 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1711 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1712 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1713 EXPECT_TRUE(A.IsIdentity());
1716 TEST(XFormTest, verifyTranslate) {
1718 A.Translate(2.0, 3.0);
1719 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
1720 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
1721 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1722 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1724 // Verify that Translate() post-multiplies the existing matrix.
1727 A.Translate(2.0, 3.0);
1728 EXPECT_ROW1_EQ(5.0f, 0.0f, 0.0f, 10.0f, A);
1729 EXPECT_ROW2_EQ(0.0f, 5.0f, 0.0f, 15.0f, A);
1730 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1731 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1734 TEST(XFormTest, verifyTranslate3d) {
1736 A.Translate3d(2.0, 3.0, 4.0);
1737 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
1738 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
1739 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
1740 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1742 // Verify that Translate3d() post-multiplies the existing matrix.
1744 A.Scale3d(6.0, 7.0, 8.0);
1745 A.Translate3d(2.0, 3.0, 4.0);
1746 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 12.0f, A);
1747 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 21.0f, A);
1748 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 32.0f, A);
1749 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1752 TEST(XFormTest, verifyScale) {
1755 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
1756 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
1757 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1758 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1760 // Verify that Scale() post-multiplies the existing matrix.
1762 A.Translate3d(2.0, 3.0, 4.0);
1764 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
1765 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
1766 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
1767 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1770 TEST(XFormTest, verifyScale3d) {
1772 A.Scale3d(6.0, 7.0, 8.0);
1773 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
1774 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
1775 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1776 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1778 // Verify that scale3d() post-multiplies the existing matrix.
1780 A.Translate3d(2.0, 3.0, 4.0);
1781 A.Scale3d(6.0, 7.0, 8.0);
1782 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
1783 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
1784 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 4.0f, A);
1785 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1788 TEST(XFormTest, verifyRotate) {
1791 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1792 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1793 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1794 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1796 // Verify that Rotate() post-multiplies the existing matrix.
1798 A.Scale3d(6.0, 7.0, 8.0);
1800 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1801 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1802 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1803 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1806 TEST(XFormTest, verifyRotateAboutXAxis) {
1808 double sin45 = 0.5 * sqrt(2.0);
1809 double cos45 = sin45;
1812 A.RotateAboutXAxis(90.0);
1813 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1814 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD);
1815 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1816 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1819 A.RotateAboutXAxis(45.0);
1820 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1821 EXPECT_ROW2_NEAR(0.0, cos45, -sin45, 0.0, A, ERROR_THRESHOLD);
1822 EXPECT_ROW3_NEAR(0.0, sin45, cos45, 0.0, A, ERROR_THRESHOLD);
1823 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1825 // Verify that RotateAboutXAxis(angle) post-multiplies the existing matrix.
1827 A.Scale3d(6.0, 7.0, 8.0);
1828 A.RotateAboutXAxis(90.0);
1829 EXPECT_ROW1_NEAR(6.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1830 EXPECT_ROW2_NEAR(0.0, 0.0, -7.0, 0.0, A, ERROR_THRESHOLD);
1831 EXPECT_ROW3_NEAR(0.0, 8.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1832 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1835 TEST(XFormTest, verifyRotateAboutYAxis) {
1837 double sin45 = 0.5 * sqrt(2.0);
1838 double cos45 = sin45;
1840 // Note carefully, the expected pattern is inverted compared to rotating
1841 // about x axis or z axis.
1843 A.RotateAboutYAxis(90.0);
1844 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD);
1845 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1846 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1847 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1850 A.RotateAboutYAxis(45.0);
1851 EXPECT_ROW1_NEAR(cos45, 0.0, sin45, 0.0, A, ERROR_THRESHOLD);
1852 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1853 EXPECT_ROW3_NEAR(-sin45, 0.0, cos45, 0.0, A, ERROR_THRESHOLD);
1854 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1856 // Verify that RotateAboutYAxis(angle) post-multiplies the existing matrix.
1858 A.Scale3d(6.0, 7.0, 8.0);
1859 A.RotateAboutYAxis(90.0);
1860 EXPECT_ROW1_NEAR(0.0, 0.0, 6.0, 0.0, A, ERROR_THRESHOLD);
1861 EXPECT_ROW2_NEAR(0.0, 7.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1862 EXPECT_ROW3_NEAR(-8.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1863 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1866 TEST(XFormTest, verifyRotateAboutZAxis) {
1868 double sin45 = 0.5 * sqrt(2.0);
1869 double cos45 = sin45;
1872 A.RotateAboutZAxis(90.0);
1873 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1874 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1875 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1876 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1879 A.RotateAboutZAxis(45.0);
1880 EXPECT_ROW1_NEAR(cos45, -sin45, 0.0, 0.0, A, ERROR_THRESHOLD);
1881 EXPECT_ROW2_NEAR(sin45, cos45, 0.0, 0.0, A, ERROR_THRESHOLD);
1882 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1883 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1885 // Verify that RotateAboutZAxis(angle) post-multiplies the existing matrix.
1887 A.Scale3d(6.0, 7.0, 8.0);
1888 A.RotateAboutZAxis(90.0);
1889 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1890 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1891 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1892 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1895 TEST(XFormTest, verifyRotateAboutForAlignedAxes) {
1898 // Check rotation about z-axis
1900 A.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1901 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1902 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1903 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1904 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1906 // Check rotation about x-axis
1908 A.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1909 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1910 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD);
1911 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1912 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1914 // Check rotation about y-axis. Note carefully, the expected pattern is
1915 // inverted compared to rotating about x axis or z axis.
1917 A.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1918 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD);
1919 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1920 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1921 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1923 // Verify that rotate3d(axis, angle) post-multiplies the existing matrix.
1925 A.Scale3d(6.0, 7.0, 8.0);
1926 A.RotateAboutZAxis(90.0);
1927 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1928 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1929 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1930 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1933 TEST(XFormTest, verifyRotateAboutForArbitraryAxis) {
1934 // Check rotation about an arbitrary non-axis-aligned vector.
1936 A.RotateAbout(Vector3dF(1.0, 1.0, 1.0), 90.0);
1937 EXPECT_ROW1_NEAR(0.3333333333333334258519187,
1938 -0.2440169358562924717404030,
1939 0.9106836025229592124219380,
1940 0.0, A, ERROR_THRESHOLD);
1941 EXPECT_ROW2_NEAR(0.9106836025229592124219380,
1942 0.3333333333333334258519187,
1943 -0.2440169358562924717404030,
1944 0.0, A, ERROR_THRESHOLD);
1945 EXPECT_ROW3_NEAR(-0.2440169358562924717404030,
1946 0.9106836025229592124219380,
1947 0.3333333333333334258519187,
1948 0.0, A, ERROR_THRESHOLD);
1949 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1952 TEST(XFormTest, verifyRotateAboutForDegenerateAxis) {
1953 // Check rotation about a degenerate zero vector.
1954 // It is expected to skip applying the rotation.
1957 A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 45.0);
1958 // Verify that A remains unchanged.
1959 EXPECT_TRUE(A.IsIdentity());
1961 InitializeTestMatrix(&A);
1962 A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 35.0);
1964 // Verify that A remains unchanged.
1965 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, A);
1966 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, A);
1967 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, A);
1968 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, A);
1971 TEST(XFormTest, verifySkewX) {
1974 EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
1975 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1976 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1977 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1979 // Verify that skewX() post-multiplies the existing matrix. Row 1, column 2,
1980 // would incorrectly have value "7" if the matrix is pre-multiplied instead
1981 // of post-multiplied.
1983 A.Scale3d(6.0, 7.0, 8.0);
1985 EXPECT_ROW1_EQ(6.0f, 6.0f, 0.0f, 0.0f, A);
1986 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
1987 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1988 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1991 TEST(XFormTest, verifySkewY) {
1994 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1995 EXPECT_ROW2_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
1996 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1997 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1999 // Verify that skewY() post-multiplies the existing matrix. Row 2, column 1 ,
2000 // would incorrectly have value "6" if the matrix is pre-multiplied instead
2001 // of post-multiplied.
2003 A.Scale3d(6.0, 7.0, 8.0);
2005 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
2006 EXPECT_ROW2_EQ(7.0f, 7.0f, 0.0f, 0.0f, A);
2007 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
2008 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
2011 TEST(XFormTest, verifyPerspectiveDepth) {
2013 A.ApplyPerspectiveDepth(1.0);
2014 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
2015 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
2016 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
2017 EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
2019 // Verify that PerspectiveDepth() post-multiplies the existing matrix.
2021 A.Translate3d(2.0, 3.0, 4.0);
2022 A.ApplyPerspectiveDepth(1.0);
2023 EXPECT_ROW1_EQ(1.0f, 0.0f, -2.0f, 2.0f, A);
2024 EXPECT_ROW2_EQ(0.0f, 1.0f, -3.0f, 3.0f, A);
2025 EXPECT_ROW3_EQ(0.0f, 0.0f, -3.0f, 4.0f, A);
2026 EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
2029 TEST(XFormTest, verifyHasPerspective) {
2031 A.ApplyPerspectiveDepth(1.0);
2032 EXPECT_TRUE(A.HasPerspective());
2035 A.ApplyPerspectiveDepth(0.0);
2036 EXPECT_FALSE(A.HasPerspective());
2039 A.matrix().set(3, 0, -1.f);
2040 EXPECT_TRUE(A.HasPerspective());
2043 A.matrix().set(3, 1, -1.f);
2044 EXPECT_TRUE(A.HasPerspective());
2047 A.matrix().set(3, 2, -0.3f);
2048 EXPECT_TRUE(A.HasPerspective());
2051 A.matrix().set(3, 3, 0.5f);
2052 EXPECT_TRUE(A.HasPerspective());
2055 A.matrix().set(3, 3, 0.f);
2056 EXPECT_TRUE(A.HasPerspective());
2059 TEST(XFormTest, verifyIsInvertible) {
2062 // Translations, rotations, scales, skews and arbitrary combinations of them
2065 EXPECT_TRUE(A.IsInvertible());
2068 A.Translate3d(2.0, 3.0, 4.0);
2069 EXPECT_TRUE(A.IsInvertible());
2072 A.Scale3d(6.0, 7.0, 8.0);
2073 EXPECT_TRUE(A.IsInvertible());
2076 A.RotateAboutXAxis(10.0);
2077 A.RotateAboutYAxis(20.0);
2078 A.RotateAboutZAxis(30.0);
2079 EXPECT_TRUE(A.IsInvertible());
2083 EXPECT_TRUE(A.IsInvertible());
2085 // A perspective matrix (projection plane at z=0) is invertible. The
2086 // intuitive explanation is that perspective is eqivalent to a skew of the
2087 // w-axis; skews are invertible.
2089 A.ApplyPerspectiveDepth(1.0);
2090 EXPECT_TRUE(A.IsInvertible());
2092 // A "pure" perspective matrix derived by similar triangles, with m44() set
2093 // to zero (i.e. camera positioned at the origin), is not invertible.
2095 A.ApplyPerspectiveDepth(1.0);
2096 A.matrix().set(3, 3, 0.f);
2097 EXPECT_FALSE(A.IsInvertible());
2099 // Adding more to a non-invertible matrix will not make it invertible in the
2102 A.ApplyPerspectiveDepth(1.0);
2103 A.matrix().set(3, 3, 0.f);
2104 A.Scale3d(6.0, 7.0, 8.0);
2105 A.RotateAboutXAxis(10.0);
2106 A.RotateAboutYAxis(20.0);
2107 A.RotateAboutZAxis(30.0);
2108 A.Translate3d(6.0, 7.0, 8.0);
2109 EXPECT_FALSE(A.IsInvertible());
2111 // A degenerate matrix of all zeros is not invertible.
2113 A.matrix().set(0, 0, 0.f);
2114 A.matrix().set(1, 1, 0.f);
2115 A.matrix().set(2, 2, 0.f);
2116 A.matrix().set(3, 3, 0.f);
2117 EXPECT_FALSE(A.IsInvertible());
2120 TEST(XFormTest, verifyIsIdentity) {
2123 InitializeTestMatrix(&A);
2124 EXPECT_FALSE(A.IsIdentity());
2127 EXPECT_TRUE(A.IsIdentity());
2129 // Modifying any one individual element should cause the matrix to no longer
2132 A.matrix().set(0, 0, 2.f);
2133 EXPECT_FALSE(A.IsIdentity());
2136 A.matrix().set(1, 0, 2.f);
2137 EXPECT_FALSE(A.IsIdentity());
2140 A.matrix().set(2, 0, 2.f);
2141 EXPECT_FALSE(A.IsIdentity());
2144 A.matrix().set(3, 0, 2.f);
2145 EXPECT_FALSE(A.IsIdentity());
2148 A.matrix().set(0, 1, 2.f);
2149 EXPECT_FALSE(A.IsIdentity());
2152 A.matrix().set(1, 1, 2.f);
2153 EXPECT_FALSE(A.IsIdentity());
2156 A.matrix().set(2, 1, 2.f);
2157 EXPECT_FALSE(A.IsIdentity());
2160 A.matrix().set(3, 1, 2.f);
2161 EXPECT_FALSE(A.IsIdentity());
2164 A.matrix().set(0, 2, 2.f);
2165 EXPECT_FALSE(A.IsIdentity());
2168 A.matrix().set(1, 2, 2.f);
2169 EXPECT_FALSE(A.IsIdentity());
2172 A.matrix().set(2, 2, 2.f);
2173 EXPECT_FALSE(A.IsIdentity());
2176 A.matrix().set(3, 2, 2.f);
2177 EXPECT_FALSE(A.IsIdentity());
2180 A.matrix().set(0, 3, 2.f);
2181 EXPECT_FALSE(A.IsIdentity());
2184 A.matrix().set(1, 3, 2.f);
2185 EXPECT_FALSE(A.IsIdentity());
2188 A.matrix().set(2, 3, 2.f);
2189 EXPECT_FALSE(A.IsIdentity());
2192 A.matrix().set(3, 3, 2.f);
2193 EXPECT_FALSE(A.IsIdentity());
2196 TEST(XFormTest, verifyIsIdentityOrTranslation) {
2199 InitializeTestMatrix(&A);
2200 EXPECT_FALSE(A.IsIdentityOrTranslation());
2203 EXPECT_TRUE(A.IsIdentityOrTranslation());
2205 // Modifying any non-translation components should cause
2206 // IsIdentityOrTranslation() to return false. NOTE: (0, 3), (1, 3), and
2207 // (2, 3) are the translation components, so modifying them should still
2210 A.matrix().set(0, 0, 2.f);
2211 EXPECT_FALSE(A.IsIdentityOrTranslation());
2214 A.matrix().set(1, 0, 2.f);
2215 EXPECT_FALSE(A.IsIdentityOrTranslation());
2218 A.matrix().set(2, 0, 2.f);
2219 EXPECT_FALSE(A.IsIdentityOrTranslation());
2222 A.matrix().set(3, 0, 2.f);
2223 EXPECT_FALSE(A.IsIdentityOrTranslation());
2226 A.matrix().set(0, 1, 2.f);
2227 EXPECT_FALSE(A.IsIdentityOrTranslation());
2230 A.matrix().set(1, 1, 2.f);
2231 EXPECT_FALSE(A.IsIdentityOrTranslation());
2234 A.matrix().set(2, 1, 2.f);
2235 EXPECT_FALSE(A.IsIdentityOrTranslation());
2238 A.matrix().set(3, 1, 2.f);
2239 EXPECT_FALSE(A.IsIdentityOrTranslation());
2242 A.matrix().set(0, 2, 2.f);
2243 EXPECT_FALSE(A.IsIdentityOrTranslation());
2246 A.matrix().set(1, 2, 2.f);
2247 EXPECT_FALSE(A.IsIdentityOrTranslation());
2250 A.matrix().set(2, 2, 2.f);
2251 EXPECT_FALSE(A.IsIdentityOrTranslation());
2254 A.matrix().set(3, 2, 2.f);
2255 EXPECT_FALSE(A.IsIdentityOrTranslation());
2257 // Note carefully - expecting true here.
2259 A.matrix().set(0, 3, 2.f);
2260 EXPECT_TRUE(A.IsIdentityOrTranslation());
2262 // Note carefully - expecting true here.
2264 A.matrix().set(1, 3, 2.f);
2265 EXPECT_TRUE(A.IsIdentityOrTranslation());
2267 // Note carefully - expecting true here.
2269 A.matrix().set(2, 3, 2.f);
2270 EXPECT_TRUE(A.IsIdentityOrTranslation());
2273 A.matrix().set(3, 3, 2.f);
2274 EXPECT_FALSE(A.IsIdentityOrTranslation());
2277 TEST(XFormTest, verifyIsApproximatelyIdentityOrTranslation) {
2279 SkMatrix44& matrix = A.matrix();
2281 // Exact pure translation.
2284 // Set translate values to values other than 0 or 1.
2285 matrix.set(0, 3, 3.4f);
2286 matrix.set(1, 3, 4.4f);
2287 matrix.set(2, 3, 5.6f);
2289 EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(0));
2290 EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2292 // Approximately pure translation.
2293 InitializeApproxIdentityMatrix(&A);
2295 // Some values must be exact.
2296 matrix.set(3, 0, 0);
2297 matrix.set(3, 1, 0);
2298 matrix.set(3, 2, 0);
2299 matrix.set(3, 3, 1);
2301 // Set translate values to values other than 0 or 1.
2302 matrix.set(0, 3, 3.4f);
2303 matrix.set(1, 3, 4.4f);
2304 matrix.set(2, 3, 5.6f);
2306 EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
2307 EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2309 // Not approximately pure translation.
2310 InitializeApproxIdentityMatrix(&A);
2312 // Some values must be exact.
2313 matrix.set(3, 0, 0);
2314 matrix.set(3, 1, 0);
2315 matrix.set(3, 2, 0);
2316 matrix.set(3, 3, 1);
2318 // Set some values (not translate values) to values other than 0 or 1.
2319 matrix.set(0, 1, 3.4f);
2320 matrix.set(3, 2, 4.4f);
2321 matrix.set(2, 0, 5.6f);
2323 EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
2324 EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2327 TEST(XFormTest, verifyIsScaleOrTranslation) {
2330 InitializeTestMatrix(&A);
2331 EXPECT_FALSE(A.IsScaleOrTranslation());
2334 EXPECT_TRUE(A.IsScaleOrTranslation());
2336 // Modifying any non-scale or non-translation components should cause
2337 // IsScaleOrTranslation() to return false. (0, 0), (1, 1), (2, 2), (0, 3),
2338 // (1, 3), and (2, 3) are the scale and translation components, so
2339 // modifying them should still return true.
2341 // Note carefully - expecting true here.
2343 A.matrix().set(0, 0, 2.f);
2344 EXPECT_TRUE(A.IsScaleOrTranslation());
2347 A.matrix().set(1, 0, 2.f);
2348 EXPECT_FALSE(A.IsScaleOrTranslation());
2351 A.matrix().set(2, 0, 2.f);
2352 EXPECT_FALSE(A.IsScaleOrTranslation());
2355 A.matrix().set(3, 0, 2.f);
2356 EXPECT_FALSE(A.IsScaleOrTranslation());
2359 A.matrix().set(0, 1, 2.f);
2360 EXPECT_FALSE(A.IsScaleOrTranslation());
2362 // Note carefully - expecting true here.
2364 A.matrix().set(1, 1, 2.f);
2365 EXPECT_TRUE(A.IsScaleOrTranslation());
2368 A.matrix().set(2, 1, 2.f);
2369 EXPECT_FALSE(A.IsScaleOrTranslation());
2372 A.matrix().set(3, 1, 2.f);
2373 EXPECT_FALSE(A.IsScaleOrTranslation());
2376 A.matrix().set(0, 2, 2.f);
2377 EXPECT_FALSE(A.IsScaleOrTranslation());
2380 A.matrix().set(1, 2, 2.f);
2381 EXPECT_FALSE(A.IsScaleOrTranslation());
2383 // Note carefully - expecting true here.
2385 A.matrix().set(2, 2, 2.f);
2386 EXPECT_TRUE(A.IsScaleOrTranslation());
2389 A.matrix().set(3, 2, 2.f);
2390 EXPECT_FALSE(A.IsScaleOrTranslation());
2392 // Note carefully - expecting true here.
2394 A.matrix().set(0, 3, 2.f);
2395 EXPECT_TRUE(A.IsScaleOrTranslation());
2397 // Note carefully - expecting true here.
2399 A.matrix().set(1, 3, 2.f);
2400 EXPECT_TRUE(A.IsScaleOrTranslation());
2402 // Note carefully - expecting true here.
2404 A.matrix().set(2, 3, 2.f);
2405 EXPECT_TRUE(A.IsScaleOrTranslation());
2408 A.matrix().set(3, 3, 2.f);
2409 EXPECT_FALSE(A.IsScaleOrTranslation());
2412 TEST(XFormTest, verifyFlattenTo2d) {
2414 InitializeTestMatrix(&A);
2417 EXPECT_ROW1_EQ(10.0f, 14.0f, 0.0f, 22.0f, A);
2418 EXPECT_ROW2_EQ(11.0f, 15.0f, 0.0f, 23.0f, A);
2419 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
2420 EXPECT_ROW4_EQ(13.0f, 17.0f, 0.0f, 25.0f, A);
2423 // Another implementation of Preserves2dAxisAlignment that isn't as fast,
2424 // good for testing the faster implementation.
2425 static bool EmpiricallyPreserves2dAxisAlignment(const Transform& transform) {
2426 Point3F p1(5.0f, 5.0f, 0.0f);
2427 Point3F p2(10.0f, 5.0f, 0.0f);
2428 Point3F p3(10.0f, 20.0f, 0.0f);
2429 Point3F p4(5.0f, 20.0f, 0.0f);
2431 QuadF test_quad(PointF(p1.x(), p1.y()),
2432 PointF(p2.x(), p2.y()),
2433 PointF(p3.x(), p3.y()),
2434 PointF(p4.x(), p4.y()));
2435 EXPECT_TRUE(test_quad.IsRectilinear());
2437 transform.TransformPoint(&p1);
2438 transform.TransformPoint(&p2);
2439 transform.TransformPoint(&p3);
2440 transform.TransformPoint(&p4);
2442 QuadF transformedQuad(PointF(p1.x(), p1.y()),
2443 PointF(p2.x(), p2.y()),
2444 PointF(p3.x(), p3.y()),
2445 PointF(p4.x(), p4.y()));
2446 return transformedQuad.IsRectilinear();
2449 TEST(XFormTest, Preserves2dAxisAlignment) {
2450 static const struct TestCase {
2451 SkMScalar a; // row 1, column 1
2452 SkMScalar b; // row 1, column 2
2453 SkMScalar c; // row 2, column 1
2454 SkMScalar d; // row 2, column 2
2458 0.f, 4.f, true }, // basic case
2460 3.f, 0.f, true }, // rotate by 90
2462 0.f, 4.f, true }, // degenerate x
2464 0.f, 0.f, true }, // degenerate y
2466 3.f, 0.f, true }, // degenerate x + rotate by 90
2468 0.f, 0.f, true }, // degenerate y + rotate by 90
2489 Transform transform;
2490 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
2491 const TestCase& value = test_cases[i];
2492 transform.MakeIdentity();
2493 transform.matrix().set(0, 0, value.a);
2494 transform.matrix().set(0, 1, value.b);
2495 transform.matrix().set(1, 0, value.c);
2496 transform.matrix().set(1, 1, value.d);
2498 if (value.expected) {
2499 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2500 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2502 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2503 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2507 // Try the same test cases again, but this time make sure that other matrix
2508 // elements (except perspective) have entries, to test that they are ignored.
2509 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
2510 const TestCase& value = test_cases[i];
2511 transform.MakeIdentity();
2512 transform.matrix().set(0, 0, value.a);
2513 transform.matrix().set(0, 1, value.b);
2514 transform.matrix().set(1, 0, value.c);
2515 transform.matrix().set(1, 1, value.d);
2517 transform.matrix().set(0, 2, 1.f);
2518 transform.matrix().set(0, 3, 2.f);
2519 transform.matrix().set(1, 2, 3.f);
2520 transform.matrix().set(1, 3, 4.f);
2521 transform.matrix().set(2, 0, 5.f);
2522 transform.matrix().set(2, 1, 6.f);
2523 transform.matrix().set(2, 2, 7.f);
2524 transform.matrix().set(2, 3, 8.f);
2526 if (value.expected) {
2527 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2528 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2530 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2531 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2535 // Try the same test cases again, but this time add perspective which is
2536 // always assumed to not-preserve axis alignment.
2537 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
2538 const TestCase& value = test_cases[i];
2539 transform.MakeIdentity();
2540 transform.matrix().set(0, 0, value.a);
2541 transform.matrix().set(0, 1, value.b);
2542 transform.matrix().set(1, 0, value.c);
2543 transform.matrix().set(1, 1, value.d);
2545 transform.matrix().set(0, 2, 1.f);
2546 transform.matrix().set(0, 3, 2.f);
2547 transform.matrix().set(1, 2, 3.f);
2548 transform.matrix().set(1, 3, 4.f);
2549 transform.matrix().set(2, 0, 5.f);
2550 transform.matrix().set(2, 1, 6.f);
2551 transform.matrix().set(2, 2, 7.f);
2552 transform.matrix().set(2, 3, 8.f);
2553 transform.matrix().set(3, 0, 9.f);
2554 transform.matrix().set(3, 1, 10.f);
2555 transform.matrix().set(3, 2, 11.f);
2556 transform.matrix().set(3, 3, 12.f);
2558 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2559 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2562 // Try a few more practical situations to check precision
2563 transform.MakeIdentity();
2564 transform.RotateAboutZAxis(90.0);
2565 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2566 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2568 transform.MakeIdentity();
2569 transform.RotateAboutZAxis(180.0);
2570 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2571 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2573 transform.MakeIdentity();
2574 transform.RotateAboutZAxis(270.0);
2575 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2576 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2578 transform.MakeIdentity();
2579 transform.RotateAboutYAxis(90.0);
2580 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2581 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2583 transform.MakeIdentity();
2584 transform.RotateAboutXAxis(90.0);
2585 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2586 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2588 transform.MakeIdentity();
2589 transform.RotateAboutZAxis(90.0);
2590 transform.RotateAboutYAxis(90.0);
2591 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2592 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2594 transform.MakeIdentity();
2595 transform.RotateAboutZAxis(90.0);
2596 transform.RotateAboutXAxis(90.0);
2597 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2598 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2600 transform.MakeIdentity();
2601 transform.RotateAboutYAxis(90.0);
2602 transform.RotateAboutZAxis(90.0);
2603 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2604 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2606 transform.MakeIdentity();
2607 transform.RotateAboutZAxis(45.0);
2608 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2609 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2611 // 3-d case; In 2d after an orthographic projection, this case does
2612 // preserve 2d axis alignment. But in 3d, it does not preserve axis
2614 transform.MakeIdentity();
2615 transform.RotateAboutYAxis(45.0);
2616 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2617 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2619 transform.MakeIdentity();
2620 transform.RotateAboutXAxis(45.0);
2621 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2622 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2624 // Perspective cases.
2625 transform.MakeIdentity();
2626 transform.ApplyPerspectiveDepth(10.0);
2627 transform.RotateAboutYAxis(45.0);
2628 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2629 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2631 transform.MakeIdentity();
2632 transform.ApplyPerspectiveDepth(10.0);
2633 transform.RotateAboutZAxis(90.0);
2634 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2635 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2638 TEST(XFormTest, To2dTranslation) {
2639 Vector2dF translation(3.f, 7.f);
2640 Transform transform;
2641 transform.Translate(translation.x(), translation.y() + 1);
2642 EXPECT_NE(translation.ToString(), transform.To2dTranslation().ToString());
2643 transform.MakeIdentity();
2644 transform.Translate(translation.x(), translation.y());
2645 EXPECT_EQ(translation.ToString(), transform.To2dTranslation().ToString());
2648 TEST(XFormTest, TransformRect) {
2649 Transform translation;
2650 translation.Translate(3.f, 7.f);
2651 RectF rect(1.f, 2.f, 3.f, 4.f);
2652 RectF expected(4.f, 9.f, 3.f, 4.f);
2653 translation.TransformRect(&rect);
2654 EXPECT_EQ(expected.ToString(), rect.ToString());
2657 TEST(XFormTest, TransformRectReverse) {
2658 Transform translation;
2659 translation.Translate(3.f, 7.f);
2660 RectF rect(1.f, 2.f, 3.f, 4.f);
2661 RectF expected(-2.f, -5.f, 3.f, 4.f);
2662 EXPECT_TRUE(translation.TransformRectReverse(&rect));
2663 EXPECT_EQ(expected.ToString(), rect.ToString());
2666 singular.Scale3d(0.f, 0.f, 0.f);
2667 EXPECT_FALSE(singular.TransformRectReverse(&rect));
2670 TEST(XFormTest, TransformBox) {
2671 Transform translation;
2672 translation.Translate3d(3.f, 7.f, 6.f);
2673 BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f);
2674 BoxF expected(4.f, 9.f, 9.f, 4.f, 5.f, 6.f);
2675 translation.TransformBox(&box);
2676 EXPECT_EQ(expected.ToString(), box.ToString());
2679 TEST(XFormTest, TransformBoxReverse) {
2680 Transform translation;
2681 translation.Translate3d(3.f, 7.f, 6.f);
2682 BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f);
2683 BoxF expected(-2.f, -5.f, -3.f, 4.f, 5.f, 6.f);
2684 EXPECT_TRUE(translation.TransformBoxReverse(&box));
2685 EXPECT_EQ(expected.ToString(), box.ToString());
2688 singular.Scale3d(0.f, 0.f, 0.f);
2689 EXPECT_FALSE(singular.TransformBoxReverse(&box));