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/geometry/box_f.h"
18 #include "ui/gfx/geometry/point.h"
19 #include "ui/gfx/geometry/point3_f.h"
20 #include "ui/gfx/geometry/quad_f.h"
21 #include "ui/gfx/geometry/vector3d_f.h"
22 #include "ui/gfx/transform_util.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(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(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(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(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(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(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},
454 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
455 const TestCase
& value
= test_cases
[i
];
456 Transform translation
;
457 translation
.Translate(value
.tx
, value
.ty
);
458 xform
= translation
* xform
;
459 Point
p1(value
.x1
, value
.y1
);
460 Point
p2(value
.x2
, value
.y2
);
461 xform
.TransformPoint(&p1
);
462 if (value
.tx
== value
.tx
&&
463 value
.ty
== value
.ty
) {
464 EXPECT_EQ(p1
.x(), p2
.x());
465 EXPECT_EQ(p1
.y(), p2
.y());
470 TEST(XFormTest
, ConcatScale2D
) {
471 static const struct TestCase
{
483 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
484 const TestCase
& value
= test_cases
[i
];
486 scale
.Scale(value
.scale
, value
.scale
);
487 xform
= scale
* xform
;
488 Point
p1(value
.before
, value
.before
);
489 Point
p2(value
.after
, value
.after
);
490 xform
.TransformPoint(&p1
);
491 if (value
.scale
== value
.scale
) {
492 EXPECT_EQ(p1
.x(), p2
.x());
493 EXPECT_EQ(p1
.y(), p2
.y());
498 TEST(XFormTest
, ConcatRotate2D
) {
499 static const struct TestCase
{
506 { 1, 0, 90.0f
, 0, 1},
507 { 1, 0, -90.0f
, 1, 0},
508 { 1, 0, 90.0f
, 0, 1},
509 { 1, 0, 360.0f
, 0, 1},
514 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
515 const TestCase
& value
= test_cases
[i
];
517 rotation
.Rotate(value
.degrees
);
518 xform
= rotation
* xform
;
519 Point
p1(value
.x1
, value
.y1
);
520 Point
p2(value
.x2
, value
.y2
);
521 xform
.TransformPoint(&p1
);
522 if (value
.degrees
== value
.degrees
) {
523 EXPECT_EQ(p1
.x(), p2
.x());
524 EXPECT_EQ(p1
.y(), p2
.y());
529 TEST(XFormTest
, SetTranslate2D
) {
530 static const struct TestCase
{
535 { 0, 0, 10.0f
, 20.0f
, 10, 20},
536 { 10, 20, 10.0f
, 20.0f
, 20, 40},
537 { 10, 20, 0.0f
, 0.0f
, 10, 20},
540 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
541 const TestCase
& value
= test_cases
[i
];
542 for (int j
= -1; j
< 2; ++j
) {
543 for (int k
= 0; k
< 3; ++k
) {
544 float epsilon
= 0.0001f
;
549 p1
.SetPoint(value
.x1
, 0);
550 p2
.SetPoint(value
.x2
, 0);
551 xform
.Translate(value
.tx
+ j
* epsilon
, 0.0);
554 p1
.SetPoint(0, value
.y1
);
555 p2
.SetPoint(0, value
.y2
);
556 xform
.Translate(0.0, value
.ty
+ j
* epsilon
);
559 p1
.SetPoint(value
.x1
, value
.y1
);
560 p2
.SetPoint(value
.x2
, value
.y2
);
561 xform
.Translate(value
.tx
+ j
* epsilon
,
562 value
.ty
+ j
* epsilon
);
566 xform
.TransformPoint(&p1
);
567 if (value
.tx
== value
.tx
&&
568 value
.ty
== value
.ty
) {
569 EXPECT_EQ(p1
.x(), p2
.x());
570 EXPECT_EQ(p1
.y(), p2
.y());
571 xform
.TransformPointReverse(&p1
);
572 EXPECT_EQ(p1
.x(), p0
.x());
573 EXPECT_EQ(p1
.y(), p0
.y());
580 TEST(XFormTest
, SetScale2D
) {
581 static const struct TestCase
{
592 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
593 const TestCase
& value
= test_cases
[i
];
594 for (int j
= -1; j
< 2; ++j
) {
595 for (int k
= 0; k
< 3; ++k
) {
596 float epsilon
= 0.0001f
;
601 p1
.SetPoint(value
.before
, 0);
602 p2
.SetPoint(value
.after
, 0);
603 xform
.Scale(value
.s
+ j
* epsilon
, 1.0);
606 p1
.SetPoint(0, value
.before
);
607 p2
.SetPoint(0, value
.after
);
608 xform
.Scale(1.0, value
.s
+ j
* epsilon
);
611 p1
.SetPoint(value
.before
,
613 p2
.SetPoint(value
.after
,
615 xform
.Scale(value
.s
+ j
* epsilon
,
616 value
.s
+ j
* epsilon
);
620 xform
.TransformPoint(&p1
);
621 if (value
.s
== value
.s
) {
622 EXPECT_EQ(p1
.x(), p2
.x());
623 EXPECT_EQ(p1
.y(), p2
.y());
624 if (value
.s
!= 0.0f
) {
625 xform
.TransformPointReverse(&p1
);
626 EXPECT_EQ(p1
.x(), p0
.x());
627 EXPECT_EQ(p1
.y(), p0
.y());
635 TEST(XFormTest
, SetRotate2D
) {
636 static const struct SetRotateCase
{
642 } set_rotate_cases
[] = {
643 { 100, 0, 90.0f
, 0, 100},
644 { 0, 0, 90.0f
, 0, 0},
645 { 0, 100, 90.0f
, -100, 0},
646 { 0, 1, -90.0f
, 1, 0},
647 { 100, 0, 0.0f
, 100, 0},
649 { 0, 0, std::numeric_limits
<float>::quiet_NaN(), 0, 0},
650 { 100, 0, 360.0f
, 100, 0}
653 for (size_t i
= 0; i
< arraysize(set_rotate_cases
); ++i
) {
654 const SetRotateCase
& value
= set_rotate_cases
[i
];
655 for (int j
= 1; j
>= -1; --j
) {
656 float epsilon
= 0.1f
;
657 Point
pt(value
.x
, value
.y
);
659 // should be invariant to small floating point errors.
660 xform
.Rotate(value
.degree
+ j
* epsilon
);
661 // just want to make sure that we don't crash in the case of NaN.
662 if (value
.degree
== value
.degree
) {
663 xform
.TransformPoint(&pt
);
664 EXPECT_EQ(value
.xprime
, pt
.x());
665 EXPECT_EQ(value
.yprime
, pt
.y());
666 xform
.TransformPointReverse(&pt
);
667 EXPECT_EQ(pt
.x(), value
.x
);
668 EXPECT_EQ(pt
.y(), value
.y
);
674 TEST(XFormTest
, TransformPointWithExtremePerspective
) {
675 Point3F
point(1.f
, 1.f
, 1.f
);
676 Transform perspective
;
677 perspective
.ApplyPerspectiveDepth(1.f
);
678 Point3F transformed
= point
;
679 perspective
.TransformPoint(&transformed
);
680 EXPECT_EQ(point
.ToString(), transformed
.ToString());
683 perspective
.MakeIdentity();
684 perspective
.ApplyPerspectiveDepth(1.1f
);
685 perspective
.TransformPoint(&transformed
);
686 EXPECT_FLOAT_EQ(11.f
, transformed
.x());
687 EXPECT_FLOAT_EQ(11.f
, transformed
.y());
688 EXPECT_FLOAT_EQ(11.f
, transformed
.z());
691 TEST(XFormTest
, BlendTranslate
) {
693 for (int i
= -5; i
< 15; ++i
) {
695 to
.Translate3d(1, 1, 1);
697 EXPECT_TRUE(to
.Blend(from
, t
));
698 EXPECT_FLOAT_EQ(t
, to
.matrix().get(0, 3));
699 EXPECT_FLOAT_EQ(t
, to
.matrix().get(1, 3));
700 EXPECT_FLOAT_EQ(t
, to
.matrix().get(2, 3));
704 TEST(XFormTest
, BlendRotate
) {
712 for (size_t index
= 0; index
< arraysize(axes
); ++index
) {
713 for (int i
= -5; i
< 15; ++i
) {
715 to
.RotateAbout(axes
[index
], 90);
717 EXPECT_TRUE(to
.Blend(from
, t
));
720 expected
.RotateAbout(axes
[index
], 90 * t
);
722 EXPECT_TRUE(MatricesAreNearlyEqual(expected
, to
));
727 TEST(XFormTest
, CanBlend180DegreeRotation
) {
735 for (size_t index
= 0; index
< arraysize(axes
); ++index
) {
736 for (int i
= -5; i
< 15; ++i
) {
738 to
.RotateAbout(axes
[index
], 180.0);
740 EXPECT_TRUE(to
.Blend(from
, t
));
742 // A 180 degree rotation is exactly opposite on the sphere, therefore
743 // either great circle arc to it is equivalent (and numerical precision
744 // will determine which is closer). Test both directions.
746 expected1
.RotateAbout(axes
[index
], 180.0 * t
);
748 expected2
.RotateAbout(axes
[index
], -180.0 * t
);
750 EXPECT_TRUE(MatricesAreNearlyEqual(expected1
, to
) ||
751 MatricesAreNearlyEqual(expected2
, to
))
752 << "axis: " << index
<< ", i: " << i
;
758 // http://crbug.com/406574
759 #define MAYBE_BlendScale DISABLED_BlendScale
761 #define MAYBE_BlendScale BlendScale
763 TEST(XFormTest
, MAYBE_BlendScale
) {
765 for (int i
= -5; i
< 15; ++i
) {
769 EXPECT_TRUE(to
.Blend(from
, t
));
770 EXPECT_FLOAT_EQ(t
* 4 + 1, to
.matrix().get(0, 0)) << "i: " << i
;
771 EXPECT_FLOAT_EQ(t
* 3 + 1, to
.matrix().get(1, 1)) << "i: " << i
;
772 EXPECT_FLOAT_EQ(t
* 2 + 1, to
.matrix().get(2, 2)) << "i: " << i
;
776 TEST(XFormTest
, BlendSkew
) {
778 for (int i
= 0; i
< 2; ++i
) {
784 expected
.SkewX(t
* 10);
785 expected
.SkewY(t
* 5);
786 EXPECT_TRUE(to
.Blend(from
, t
));
787 EXPECT_TRUE(MatricesAreNearlyEqual(expected
, to
));
791 TEST(XFormTest
, ExtrapolateSkew
) {
793 for (int i
= -1; i
< 2; ++i
) {
798 expected
.SkewX(t
* 20);
799 EXPECT_TRUE(to
.Blend(from
, t
));
800 EXPECT_TRUE(MatricesAreNearlyEqual(expected
, to
));
805 // http://crbug.com/406574
806 #define MAYBE_BlendPerspective DISABLED_BlendPerspective
808 #define MAYBE_BlendPerspective BlendPerspective
810 TEST(XFormTest
, MAYBE_BlendPerspective
) {
812 from
.ApplyPerspectiveDepth(200);
813 for (int i
= -1; i
< 3; ++i
) {
815 to
.ApplyPerspectiveDepth(800);
817 double depth
= 1.0 / ((1.0 / 200) * (1.0 - t
) + (1.0 / 800) * t
);
819 expected
.ApplyPerspectiveDepth(depth
);
820 EXPECT_TRUE(to
.Blend(from
, t
));
821 EXPECT_TRUE(MatricesAreNearlyEqual(expected
, to
));
825 TEST(XFormTest
, BlendIdentity
) {
828 EXPECT_TRUE(to
.Blend(from
, 0.5));
832 TEST(XFormTest
, CannotBlendSingularMatrix
) {
835 to
.matrix().set(1, 1, SkDoubleToMScalar(0));
836 EXPECT_FALSE(to
.Blend(from
, 0.5));
839 TEST(XFormTest
, VerifyBlendForTranslation
) {
841 from
.Translate3d(100.0, 200.0, 100.0);
845 to
.Translate3d(200.0, 100.0, 300.0);
850 to
.Translate3d(200.0, 100.0, 300.0);
851 to
.Blend(from
, 0.25);
852 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 125.0f
, to
);
853 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 175.0f
, to
);
854 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 150.0f
, to
);
855 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
858 to
.Translate3d(200.0, 100.0, 300.0);
860 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 150.0f
, to
);
861 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 150.0f
, to
);
862 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 200.0f
, to
);
863 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
866 to
.Translate3d(200.0, 100.0, 300.0);
868 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 200.0f
, to
);
869 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 100.0f
, to
);
870 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 300.0f
, to
);
871 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
874 TEST(XFormTest
, VerifyBlendForScale
) {
876 from
.Scale3d(100.0, 200.0, 100.0);
880 to
.Scale3d(200.0, 100.0, 300.0);
885 to
.Scale3d(200.0, 100.0, 300.0);
886 to
.Blend(from
, 0.25);
887 EXPECT_ROW1_EQ(125.0f
, 0.0f
, 0.0f
, 0.0f
, to
);
888 EXPECT_ROW2_EQ(0.0f
, 175.0f
, 0.0f
, 0.0f
, to
);
889 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 150.0f
, 0.0f
, to
);
890 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
893 to
.Scale3d(200.0, 100.0, 300.0);
895 EXPECT_ROW1_EQ(150.0f
, 0.0f
, 0.0f
, 0.0f
, to
);
896 EXPECT_ROW2_EQ(0.0f
, 150.0f
, 0.0f
, 0.0f
, to
);
897 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 200.0f
, 0.0f
, to
);
898 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
901 to
.Scale3d(200.0, 100.0, 300.0);
903 EXPECT_ROW1_EQ(200.0f
, 0.0f
, 0.0f
, 0.0f
, to
);
904 EXPECT_ROW2_EQ(0.0f
, 100.0f
, 0.0f
, 0.0f
, to
);
905 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 300.0f
, 0.0f
, to
);
906 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
909 TEST(XFormTest
, VerifyBlendForSkewX
) {
922 EXPECT_ROW1_EQ(1.0f
, 0.5f
, 0.0f
, 0.0f
, to
);
923 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, to
);
924 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
925 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
929 to
.Blend(from
, 0.25);
930 EXPECT_ROW1_EQ(1.0f
, 0.25f
, 0.0f
, 0.0f
, to
);
931 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, to
);
932 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
933 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
938 EXPECT_ROW1_EQ(1.0f
, 1.0f
, 0.0f
, 0.0f
, to
);
939 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, to
);
940 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
941 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
944 TEST(XFormTest
, VerifyBlendForSkewY
) {
945 // NOTE CAREFULLY: Decomposition of skew and rotation terms of the matrix
946 // is inherently underconstrained, and so it does not always compute the
947 // originally intended skew parameters. The current implementation uses QR
948 // decomposition, which decomposes the shear into a rotation + non-uniform
951 // It is unlikely that the decomposition implementation will need to change
952 // very often, so to get any test coverage, the compromise is to verify the
953 // exact matrix that the.Blend() operation produces.
955 // This problem also potentially exists for skewX, but the current QR
956 // decomposition implementation just happens to decompose those test
957 // matrices intuitively.
959 // Unfortunately, this case suffers from uncomfortably large precision
973 to
.Blend(from
, 0.25);
974 EXPECT_ROW1_NEAR(1.0823489449280947471976333,
975 0.0464370719145053845178239,
979 LOOSE_ERROR_THRESHOLD
);
980 EXPECT_ROW2_NEAR(0.2152925909665224513123150,
981 0.9541702441750861130032035,
985 LOOSE_ERROR_THRESHOLD
);
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_NEAR(1.1152212925809066312865525,
993 0.0676495144007326631996335,
997 LOOSE_ERROR_THRESHOLD
);
998 EXPECT_ROW2_NEAR(0.4619397844342648662419037,
999 0.9519009045724774464858342,
1003 LOOSE_ERROR_THRESHOLD
);
1004 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
1005 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1009 to
.Blend(from
, 1.0);
1010 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to
, LOOSE_ERROR_THRESHOLD
);
1011 EXPECT_ROW2_NEAR(1.0, 1.0, 0.0, 0.0, to
, LOOSE_ERROR_THRESHOLD
);
1012 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
1013 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1017 // http://crbug.com/406574
1018 #define MAYBE_VerifyBlendForRotationAboutX DISABLED_VerifyBlendForRotationAboutX
1020 #define MAYBE_VerifyBlendForRotationAboutX VerifyBlendForRotationAboutX
1022 TEST(XFormTest
, MAYBE_VerifyBlendForRotationAboutX
) {
1023 // Even though.Blending uses quaternions, axis-aligned rotations should.
1024 // Blend the same with quaternions or Euler angles. So we can test
1025 // rotation.Blending by comparing against manually specified matrices from
1029 from
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 0.0);
1033 to
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1034 to
.Blend(from
, 0.0);
1035 EXPECT_EQ(from
, to
);
1037 double expectedRotationAngle
= 22.5 * M_PI
/ 180.0;
1039 to
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1040 to
.Blend(from
, 0.25);
1041 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1042 EXPECT_ROW2_NEAR(0.0,
1043 std::cos(expectedRotationAngle
),
1044 -std::sin(expectedRotationAngle
),
1048 EXPECT_ROW3_NEAR(0.0,
1049 std::sin(expectedRotationAngle
),
1050 std::cos(expectedRotationAngle
),
1054 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1056 expectedRotationAngle
= 45.0 * M_PI
/ 180.0;
1058 to
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1059 to
.Blend(from
, 0.5);
1060 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1061 EXPECT_ROW2_NEAR(0.0,
1062 std::cos(expectedRotationAngle
),
1063 -std::sin(expectedRotationAngle
),
1067 EXPECT_ROW3_NEAR(0.0,
1068 std::sin(expectedRotationAngle
),
1069 std::cos(expectedRotationAngle
),
1073 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1076 to
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1077 to
.Blend(from
, 1.0);
1078 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1079 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, to
, ERROR_THRESHOLD
);
1080 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1081 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1085 // http://crbug.com/406574
1086 #define MAYBE_VerifyBlendForRotationAboutY DISABLED_VerifyBlendForRotationAboutY
1088 #define MAYBE_VerifyBlendForRotationAboutY VerifyBlendForRotationAboutY
1090 TEST(XFormTest
, MAYBE_VerifyBlendForRotationAboutY
) {
1092 from
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 0.0);
1096 to
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1097 to
.Blend(from
, 0.0);
1098 EXPECT_EQ(from
, to
);
1100 double expectedRotationAngle
= 22.5 * M_PI
/ 180.0;
1102 to
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1103 to
.Blend(from
, 0.25);
1104 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle
),
1106 std::sin(expectedRotationAngle
),
1110 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1111 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle
),
1113 std::cos(expectedRotationAngle
),
1117 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1119 expectedRotationAngle
= 45.0 * M_PI
/ 180.0;
1121 to
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1122 to
.Blend(from
, 0.5);
1123 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle
),
1125 std::sin(expectedRotationAngle
),
1129 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1130 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle
),
1132 std::cos(expectedRotationAngle
),
1136 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1139 to
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1140 to
.Blend(from
, 1.0);
1141 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, to
, ERROR_THRESHOLD
);
1142 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1143 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1144 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1148 // http://crbug.com/406574
1149 #define MAYBE_VerifyBlendForRotationAboutZ DISABLED_VerifyBlendForRotationAboutZ
1151 #define MAYBE_VerifyBlendForRotationAboutZ VerifyBlendForRotationAboutZ
1153 TEST(XFormTest
, MAYBE_VerifyBlendForRotationAboutZ
) {
1155 from
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 0.0);
1159 to
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1160 to
.Blend(from
, 0.0);
1161 EXPECT_EQ(from
, to
);
1163 double expectedRotationAngle
= 22.5 * M_PI
/ 180.0;
1165 to
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1166 to
.Blend(from
, 0.25);
1167 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle
),
1168 -std::sin(expectedRotationAngle
),
1173 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle
),
1174 std::cos(expectedRotationAngle
),
1179 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to
, ERROR_THRESHOLD
);
1180 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1182 expectedRotationAngle
= 45.0 * M_PI
/ 180.0;
1184 to
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1185 to
.Blend(from
, 0.5);
1186 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle
),
1187 -std::sin(expectedRotationAngle
),
1192 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle
),
1193 std::cos(expectedRotationAngle
),
1198 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to
, ERROR_THRESHOLD
);
1199 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1202 to
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1203 to
.Blend(from
, 1.0);
1204 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1205 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1206 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to
, ERROR_THRESHOLD
);
1207 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1210 TEST(XFormTest
, VerifyBlendForCompositeTransform
) {
1211 // Verify that the.Blending was done with a decomposition in correct order
1212 // by blending a composite transform. Using matrix x vector notation
1213 // (Ax = b, where x is column vector), the ordering should be:
1214 // perspective * translation * rotation * skew * scale
1216 // It is not as important (or meaningful) to check intermediate
1217 // interpolations; order of operations will be tested well enough by the
1218 // end cases that are easier to specify.
1223 Transform expectedEndOfAnimation
;
1224 expectedEndOfAnimation
.ApplyPerspectiveDepth(1.0);
1225 expectedEndOfAnimation
.Translate3d(10.0, 20.0, 30.0);
1226 expectedEndOfAnimation
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 25.0);
1227 expectedEndOfAnimation
.SkewY(45.0);
1228 expectedEndOfAnimation
.Scale3d(6.0, 7.0, 8.0);
1230 to
= expectedEndOfAnimation
;
1231 to
.Blend(from
, 0.0);
1232 EXPECT_EQ(from
, to
);
1234 to
= expectedEndOfAnimation
;
1235 // We short circuit if blend is >= 1, so to check the numerics, we will
1236 // check that we get close to what we expect when we're nearly done
1238 to
.Blend(from
, .99999f
);
1240 // Recomposing the matrix results in a normalized matrix, so to verify we
1241 // need to normalize the expectedEndOfAnimation before comparing elements.
1242 // Normalizing means dividing everything by expectedEndOfAnimation.m44().
1243 Transform normalizedExpectedEndOfAnimation
= expectedEndOfAnimation
;
1244 Transform normalizationMatrix
;
1245 normalizationMatrix
.matrix().set(
1248 SkDoubleToMScalar(1 / expectedEndOfAnimation
.matrix().get(3.0, 3.0)));
1249 normalizationMatrix
.matrix().set(
1252 SkDoubleToMScalar(1 / expectedEndOfAnimation
.matrix().get(3.0, 3.0)));
1253 normalizationMatrix
.matrix().set(
1256 SkDoubleToMScalar(1 / expectedEndOfAnimation
.matrix().get(3.0, 3.0)));
1257 normalizationMatrix
.matrix().set(
1260 SkDoubleToMScalar(1 / expectedEndOfAnimation
.matrix().get(3.0, 3.0)));
1261 normalizedExpectedEndOfAnimation
.PreconcatTransform(normalizationMatrix
);
1263 EXPECT_TRUE(MatricesAreNearlyEqual(normalizedExpectedEndOfAnimation
, to
));
1266 TEST(XFormTest
, DecomposedTransformCtor
) {
1267 DecomposedTransform decomp
;
1268 for (int i
= 0; i
< 3; ++i
) {
1269 EXPECT_EQ(0.0, decomp
.translate
[i
]);
1270 EXPECT_EQ(1.0, decomp
.scale
[i
]);
1271 EXPECT_EQ(0.0, decomp
.skew
[i
]);
1272 EXPECT_EQ(0.0, decomp
.quaternion
[i
]);
1273 EXPECT_EQ(0.0, decomp
.perspective
[i
]);
1275 EXPECT_EQ(1.0, decomp
.quaternion
[3]);
1276 EXPECT_EQ(1.0, decomp
.perspective
[3]);
1278 Transform composed
= ComposeTransform(decomp
);
1279 EXPECT_TRUE(MatricesAreNearlyEqual(identity
, composed
));
1282 TEST(XFormTest
, FactorTRS
) {
1283 for (int degrees
= 0; degrees
< 180; ++degrees
) {
1284 // build a transformation matrix.
1285 gfx::Transform transform
;
1286 transform
.Translate(degrees
* 2, -degrees
* 3);
1287 transform
.Rotate(degrees
);
1288 transform
.Scale(degrees
+ 1, 2 * degrees
+ 1);
1290 // factor the matrix
1291 DecomposedTransform decomp
;
1292 bool success
= DecomposeTransform(&decomp
, transform
);
1293 EXPECT_TRUE(success
);
1294 EXPECT_FLOAT_EQ(decomp
.translate
[0], degrees
* 2);
1295 EXPECT_FLOAT_EQ(decomp
.translate
[1], -degrees
* 3);
1297 std::acos(SkMScalarToDouble(decomp
.quaternion
[3])) * 360.0 / M_PI
;
1298 while (rotation
< 0.0)
1300 while (rotation
> 360.0)
1303 const float epsilon
= 0.00015f
;
1304 EXPECT_NEAR(rotation
, degrees
, epsilon
);
1305 EXPECT_NEAR(decomp
.scale
[0], degrees
+ 1, epsilon
);
1306 EXPECT_NEAR(decomp
.scale
[1], 2 * degrees
+ 1, epsilon
);
1310 TEST(XFormTest
, DecomposeTransform
) {
1311 for (float scale
= 0.001f
; scale
< 2.0f
; scale
+= 0.001f
) {
1312 gfx::Transform transform
;
1313 transform
.Scale(scale
, scale
);
1314 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
1316 DecomposedTransform decomp
;
1317 bool success
= DecomposeTransform(&decomp
, transform
);
1318 EXPECT_TRUE(success
);
1320 gfx::Transform compose_transform
= ComposeTransform(decomp
);
1321 EXPECT_TRUE(compose_transform
.Preserves2dAxisAlignment());
1325 TEST(XFormTest
, IntegerTranslation
) {
1326 gfx::Transform transform
;
1327 EXPECT_TRUE(transform
.IsIdentityOrIntegerTranslation());
1329 transform
.Translate3d(1, 2, 3);
1330 EXPECT_TRUE(transform
.IsIdentityOrIntegerTranslation());
1332 transform
.MakeIdentity();
1333 transform
.Translate3d(-1, -2, -3);
1334 EXPECT_TRUE(transform
.IsIdentityOrIntegerTranslation());
1336 transform
.MakeIdentity();
1337 transform
.Translate3d(4.5f
, 0, 0);
1338 EXPECT_FALSE(transform
.IsIdentityOrIntegerTranslation());
1340 transform
.MakeIdentity();
1341 transform
.Translate3d(0, -6.7f
, 0);
1342 EXPECT_FALSE(transform
.IsIdentityOrIntegerTranslation());
1344 transform
.MakeIdentity();
1345 transform
.Translate3d(0, 0, 8.9f
);
1346 EXPECT_FALSE(transform
.IsIdentityOrIntegerTranslation());
1349 TEST(XFormTest
, verifyMatrixInversion
) {
1351 // Invert a translation
1352 gfx::Transform translation
;
1353 translation
.Translate3d(2.0, 3.0, 4.0);
1354 EXPECT_TRUE(translation
.IsInvertible());
1356 gfx::Transform inverse_translation
;
1357 bool is_invertible
= translation
.GetInverse(&inverse_translation
);
1358 EXPECT_TRUE(is_invertible
);
1359 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, -2.0f
, inverse_translation
);
1360 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, -3.0f
, inverse_translation
);
1361 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, -4.0f
, inverse_translation
);
1362 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, inverse_translation
);
1366 // Invert a non-uniform scale
1367 gfx::Transform scale
;
1368 scale
.Scale3d(4.0, 10.0, 100.0);
1369 EXPECT_TRUE(scale
.IsInvertible());
1371 gfx::Transform inverse_scale
;
1372 bool is_invertible
= scale
.GetInverse(&inverse_scale
);
1373 EXPECT_TRUE(is_invertible
);
1374 EXPECT_ROW1_EQ(0.25f
, 0.0f
, 0.0f
, 0.0f
, inverse_scale
);
1375 EXPECT_ROW2_EQ(0.0f
, 0.1f
, 0.0f
, 0.0f
, inverse_scale
);
1376 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 0.01f
, 0.0f
, inverse_scale
);
1377 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, inverse_scale
);
1381 // Try to invert a matrix that is not invertible.
1382 // The inverse() function should reset the output matrix to identity.
1383 gfx::Transform uninvertible
;
1384 uninvertible
.matrix().set(0, 0, 0.f
);
1385 uninvertible
.matrix().set(1, 1, 0.f
);
1386 uninvertible
.matrix().set(2, 2, 0.f
);
1387 uninvertible
.matrix().set(3, 3, 0.f
);
1388 EXPECT_FALSE(uninvertible
.IsInvertible());
1390 gfx::Transform inverse_of_uninvertible
;
1392 // Add a scale just to more easily ensure that inverse_of_uninvertible is
1393 // reset to identity.
1394 inverse_of_uninvertible
.Scale3d(4.0, 10.0, 100.0);
1396 bool is_invertible
= uninvertible
.GetInverse(&inverse_of_uninvertible
);
1397 EXPECT_FALSE(is_invertible
);
1398 EXPECT_TRUE(inverse_of_uninvertible
.IsIdentity());
1399 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, inverse_of_uninvertible
);
1400 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, inverse_of_uninvertible
);
1401 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, inverse_of_uninvertible
);
1402 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, inverse_of_uninvertible
);
1406 TEST(XFormTest
, verifyBackfaceVisibilityBasicCases
) {
1407 Transform transform
;
1409 transform
.MakeIdentity();
1410 EXPECT_FALSE(transform
.IsBackFaceVisible());
1412 transform
.MakeIdentity();
1413 transform
.RotateAboutYAxis(80.0);
1414 EXPECT_FALSE(transform
.IsBackFaceVisible());
1416 transform
.MakeIdentity();
1417 transform
.RotateAboutYAxis(100.0);
1418 EXPECT_TRUE(transform
.IsBackFaceVisible());
1420 // Edge case, 90 degree rotation should return false.
1421 transform
.MakeIdentity();
1422 transform
.RotateAboutYAxis(90.0);
1423 EXPECT_FALSE(transform
.IsBackFaceVisible());
1426 TEST(XFormTest
, verifyBackfaceVisibilityForPerspective
) {
1427 Transform layer_space_to_projection_plane
;
1429 // This tests if IsBackFaceVisible works properly under perspective
1430 // transforms. Specifically, layers that may have their back face visible in
1431 // orthographic projection, may not actually have back face visible under
1432 // perspective projection.
1434 // Case 1: Layer is rotated by slightly more than 90 degrees, at the center
1435 // of the prespective projection. In this case, the layer's back-side
1436 // is visible to the camera.
1437 layer_space_to_projection_plane
.MakeIdentity();
1438 layer_space_to_projection_plane
.ApplyPerspectiveDepth(1.0);
1439 layer_space_to_projection_plane
.Translate3d(0.0, 0.0, 0.0);
1440 layer_space_to_projection_plane
.RotateAboutYAxis(100.0);
1441 EXPECT_TRUE(layer_space_to_projection_plane
.IsBackFaceVisible());
1443 // Case 2: Layer is rotated by slightly more than 90 degrees, but shifted off
1444 // to the side of the camera. Because of the wide field-of-view, the
1445 // layer's front side is still visible.
1447 // |<-- front side of layer is visible to camera
1452 // |\ /<-- camera field of view
1454 // back side of layer -->| \ /
1455 // \./ <-- camera origin
1457 layer_space_to_projection_plane
.MakeIdentity();
1458 layer_space_to_projection_plane
.ApplyPerspectiveDepth(1.0);
1459 layer_space_to_projection_plane
.Translate3d(-10.0, 0.0, 0.0);
1460 layer_space_to_projection_plane
.RotateAboutYAxis(100.0);
1461 EXPECT_FALSE(layer_space_to_projection_plane
.IsBackFaceVisible());
1463 // Case 3: Additionally rotating the layer by 180 degrees should of course
1464 // show the opposite result of case 2.
1465 layer_space_to_projection_plane
.RotateAboutYAxis(180.0);
1466 EXPECT_TRUE(layer_space_to_projection_plane
.IsBackFaceVisible());
1469 TEST(XFormTest
, verifyDefaultConstructorCreatesIdentityMatrix
) {
1471 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1472 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1473 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1474 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1475 EXPECT_TRUE(A
.IsIdentity());
1478 TEST(XFormTest
, verifyCopyConstructor
) {
1480 InitializeTestMatrix(&A
);
1482 // Copy constructor should produce exact same elements as matrix A.
1484 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, B
);
1485 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, B
);
1486 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, B
);
1487 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, B
);
1490 TEST(XFormTest
, verifyConstructorFor16Elements
) {
1491 Transform
transform(1.0, 2.0, 3.0, 4.0,
1493 9.0, 10.0, 11.0, 12.0,
1494 13.0, 14.0, 15.0, 16.0);
1496 EXPECT_ROW1_EQ(1.0f
, 2.0f
, 3.0f
, 4.0f
, transform
);
1497 EXPECT_ROW2_EQ(5.0f
, 6.0f
, 7.0f
, 8.0f
, transform
);
1498 EXPECT_ROW3_EQ(9.0f
, 10.0f
, 11.0f
, 12.0f
, transform
);
1499 EXPECT_ROW4_EQ(13.0f
, 14.0f
, 15.0f
, 16.0f
, transform
);
1502 TEST(XFormTest
, verifyConstructorFor2dElements
) {
1503 Transform
transform(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
1505 EXPECT_ROW1_EQ(1.0f
, 2.0f
, 0.0f
, 5.0f
, transform
);
1506 EXPECT_ROW2_EQ(3.0f
, 4.0f
, 0.0f
, 6.0f
, transform
);
1507 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, transform
);
1508 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, transform
);
1512 TEST(XFormTest
, verifyAssignmentOperator
) {
1514 InitializeTestMatrix(&A
);
1516 InitializeTestMatrix2(&B
);
1518 InitializeTestMatrix2(&C
);
1521 // Both B and C should now have been re-assigned to the value of A.
1522 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, B
);
1523 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, B
);
1524 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, B
);
1525 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, B
);
1527 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, C
);
1528 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, C
);
1529 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, C
);
1530 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, C
);
1533 TEST(XFormTest
, verifyEqualsBooleanOperator
) {
1535 InitializeTestMatrix(&A
);
1538 InitializeTestMatrix(&B
);
1539 EXPECT_TRUE(A
== B
);
1541 // Modifying multiple elements should cause equals operator to return false.
1543 InitializeTestMatrix2(&C
);
1544 EXPECT_FALSE(A
== C
);
1546 // Modifying any one individual element should cause equals operator to
1550 D
.matrix().set(0, 0, 0.f
);
1551 EXPECT_FALSE(A
== D
);
1554 D
.matrix().set(1, 0, 0.f
);
1555 EXPECT_FALSE(A
== D
);
1558 D
.matrix().set(2, 0, 0.f
);
1559 EXPECT_FALSE(A
== D
);
1562 D
.matrix().set(3, 0, 0.f
);
1563 EXPECT_FALSE(A
== D
);
1566 D
.matrix().set(0, 1, 0.f
);
1567 EXPECT_FALSE(A
== D
);
1570 D
.matrix().set(1, 1, 0.f
);
1571 EXPECT_FALSE(A
== D
);
1574 D
.matrix().set(2, 1, 0.f
);
1575 EXPECT_FALSE(A
== D
);
1578 D
.matrix().set(3, 1, 0.f
);
1579 EXPECT_FALSE(A
== D
);
1582 D
.matrix().set(0, 2, 0.f
);
1583 EXPECT_FALSE(A
== D
);
1586 D
.matrix().set(1, 2, 0.f
);
1587 EXPECT_FALSE(A
== D
);
1590 D
.matrix().set(2, 2, 0.f
);
1591 EXPECT_FALSE(A
== D
);
1594 D
.matrix().set(3, 2, 0.f
);
1595 EXPECT_FALSE(A
== D
);
1598 D
.matrix().set(0, 3, 0.f
);
1599 EXPECT_FALSE(A
== D
);
1602 D
.matrix().set(1, 3, 0.f
);
1603 EXPECT_FALSE(A
== D
);
1606 D
.matrix().set(2, 3, 0.f
);
1607 EXPECT_FALSE(A
== D
);
1610 D
.matrix().set(3, 3, 0.f
);
1611 EXPECT_FALSE(A
== D
);
1614 TEST(XFormTest
, verifyMultiplyOperator
) {
1616 InitializeTestMatrix(&A
);
1619 InitializeTestMatrix2(&B
);
1621 Transform C
= A
* B
;
1622 EXPECT_ROW1_EQ(2036.0f
, 2292.0f
, 2548.0f
, 2804.0f
, C
);
1623 EXPECT_ROW2_EQ(2162.0f
, 2434.0f
, 2706.0f
, 2978.0f
, C
);
1624 EXPECT_ROW3_EQ(2288.0f
, 2576.0f
, 2864.0f
, 3152.0f
, C
);
1625 EXPECT_ROW4_EQ(2414.0f
, 2718.0f
, 3022.0f
, 3326.0f
, C
);
1627 // Just an additional sanity check; matrix multiplication is not commutative.
1628 EXPECT_FALSE(A
* B
== B
* A
);
1631 TEST(XFormTest
, verifyMultiplyAndAssignOperator
) {
1633 InitializeTestMatrix(&A
);
1636 InitializeTestMatrix2(&B
);
1639 EXPECT_ROW1_EQ(2036.0f
, 2292.0f
, 2548.0f
, 2804.0f
, A
);
1640 EXPECT_ROW2_EQ(2162.0f
, 2434.0f
, 2706.0f
, 2978.0f
, A
);
1641 EXPECT_ROW3_EQ(2288.0f
, 2576.0f
, 2864.0f
, 3152.0f
, A
);
1642 EXPECT_ROW4_EQ(2414.0f
, 2718.0f
, 3022.0f
, 3326.0f
, A
);
1644 // Just an additional sanity check; matrix multiplication is not commutative.
1649 EXPECT_FALSE(C
== D
);
1652 TEST(XFormTest
, verifyMatrixMultiplication
) {
1654 InitializeTestMatrix(&A
);
1657 InitializeTestMatrix2(&B
);
1659 A
.PreconcatTransform(B
);
1660 EXPECT_ROW1_EQ(2036.0f
, 2292.0f
, 2548.0f
, 2804.0f
, A
);
1661 EXPECT_ROW2_EQ(2162.0f
, 2434.0f
, 2706.0f
, 2978.0f
, A
);
1662 EXPECT_ROW3_EQ(2288.0f
, 2576.0f
, 2864.0f
, 3152.0f
, A
);
1663 EXPECT_ROW4_EQ(2414.0f
, 2718.0f
, 3022.0f
, 3326.0f
, A
);
1666 TEST(XFormTest
, verifyMakeIdentiy
) {
1668 InitializeTestMatrix(&A
);
1670 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1671 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1672 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1673 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1674 EXPECT_TRUE(A
.IsIdentity());
1677 TEST(XFormTest
, verifyTranslate
) {
1679 A
.Translate(2.0, 3.0);
1680 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 2.0f
, A
);
1681 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 3.0f
, A
);
1682 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1683 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1685 // Verify that Translate() post-multiplies the existing matrix.
1688 A
.Translate(2.0, 3.0);
1689 EXPECT_ROW1_EQ(5.0f
, 0.0f
, 0.0f
, 10.0f
, A
);
1690 EXPECT_ROW2_EQ(0.0f
, 5.0f
, 0.0f
, 15.0f
, A
);
1691 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1692 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1695 TEST(XFormTest
, verifyTranslate3d
) {
1697 A
.Translate3d(2.0, 3.0, 4.0);
1698 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 2.0f
, A
);
1699 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 3.0f
, A
);
1700 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 4.0f
, A
);
1701 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1703 // Verify that Translate3d() post-multiplies the existing matrix.
1705 A
.Scale3d(6.0, 7.0, 8.0);
1706 A
.Translate3d(2.0, 3.0, 4.0);
1707 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 12.0f
, A
);
1708 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 21.0f
, A
);
1709 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 32.0f
, A
);
1710 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1713 TEST(XFormTest
, verifyScale
) {
1716 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1717 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 0.0f
, A
);
1718 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1719 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1721 // Verify that Scale() post-multiplies the existing matrix.
1723 A
.Translate3d(2.0, 3.0, 4.0);
1725 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 2.0f
, A
);
1726 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 3.0f
, A
);
1727 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 4.0f
, A
);
1728 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1731 TEST(XFormTest
, verifyScale3d
) {
1733 A
.Scale3d(6.0, 7.0, 8.0);
1734 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1735 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 0.0f
, A
);
1736 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1737 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1739 // Verify that scale3d() post-multiplies the existing matrix.
1741 A
.Translate3d(2.0, 3.0, 4.0);
1742 A
.Scale3d(6.0, 7.0, 8.0);
1743 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 2.0f
, A
);
1744 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 3.0f
, A
);
1745 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 4.0f
, A
);
1746 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1749 TEST(XFormTest
, verifyRotate
) {
1752 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1753 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1754 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1755 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1757 // Verify that Rotate() post-multiplies the existing matrix.
1759 A
.Scale3d(6.0, 7.0, 8.0);
1761 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1762 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1763 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1764 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1767 TEST(XFormTest
, verifyRotateAboutXAxis
) {
1769 double sin45
= 0.5 * sqrt(2.0);
1770 double cos45
= sin45
;
1773 A
.RotateAboutXAxis(90.0);
1774 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1775 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A
, ERROR_THRESHOLD
);
1776 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1777 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1780 A
.RotateAboutXAxis(45.0);
1781 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1782 EXPECT_ROW2_NEAR(0.0, cos45
, -sin45
, 0.0, A
, ERROR_THRESHOLD
);
1783 EXPECT_ROW3_NEAR(0.0, sin45
, cos45
, 0.0, A
, ERROR_THRESHOLD
);
1784 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1786 // Verify that RotateAboutXAxis(angle) post-multiplies the existing matrix.
1788 A
.Scale3d(6.0, 7.0, 8.0);
1789 A
.RotateAboutXAxis(90.0);
1790 EXPECT_ROW1_NEAR(6.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1791 EXPECT_ROW2_NEAR(0.0, 0.0, -7.0, 0.0, A
, ERROR_THRESHOLD
);
1792 EXPECT_ROW3_NEAR(0.0, 8.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1793 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1796 TEST(XFormTest
, verifyRotateAboutYAxis
) {
1798 double sin45
= 0.5 * sqrt(2.0);
1799 double cos45
= sin45
;
1801 // Note carefully, the expected pattern is inverted compared to rotating
1802 // about x axis or z axis.
1804 A
.RotateAboutYAxis(90.0);
1805 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A
, ERROR_THRESHOLD
);
1806 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1807 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1808 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1811 A
.RotateAboutYAxis(45.0);
1812 EXPECT_ROW1_NEAR(cos45
, 0.0, sin45
, 0.0, A
, ERROR_THRESHOLD
);
1813 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1814 EXPECT_ROW3_NEAR(-sin45
, 0.0, cos45
, 0.0, A
, ERROR_THRESHOLD
);
1815 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1817 // Verify that RotateAboutYAxis(angle) post-multiplies the existing matrix.
1819 A
.Scale3d(6.0, 7.0, 8.0);
1820 A
.RotateAboutYAxis(90.0);
1821 EXPECT_ROW1_NEAR(0.0, 0.0, 6.0, 0.0, A
, ERROR_THRESHOLD
);
1822 EXPECT_ROW2_NEAR(0.0, 7.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1823 EXPECT_ROW3_NEAR(-8.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1824 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1827 TEST(XFormTest
, verifyRotateAboutZAxis
) {
1829 double sin45
= 0.5 * sqrt(2.0);
1830 double cos45
= sin45
;
1833 A
.RotateAboutZAxis(90.0);
1834 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1835 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1836 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1837 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1840 A
.RotateAboutZAxis(45.0);
1841 EXPECT_ROW1_NEAR(cos45
, -sin45
, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1842 EXPECT_ROW2_NEAR(sin45
, cos45
, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1843 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1844 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1846 // Verify that RotateAboutZAxis(angle) post-multiplies the existing matrix.
1848 A
.Scale3d(6.0, 7.0, 8.0);
1849 A
.RotateAboutZAxis(90.0);
1850 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1851 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1852 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1853 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1856 TEST(XFormTest
, verifyRotateAboutForAlignedAxes
) {
1859 // Check rotation about z-axis
1861 A
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1862 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1863 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1864 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1865 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1867 // Check rotation about x-axis
1869 A
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1870 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1871 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A
, ERROR_THRESHOLD
);
1872 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1873 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1875 // Check rotation about y-axis. Note carefully, the expected pattern is
1876 // inverted compared to rotating about x axis or z axis.
1878 A
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1879 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A
, ERROR_THRESHOLD
);
1880 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1881 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1882 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1884 // Verify that rotate3d(axis, angle) post-multiplies the existing matrix.
1886 A
.Scale3d(6.0, 7.0, 8.0);
1887 A
.RotateAboutZAxis(90.0);
1888 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1889 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1890 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1891 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1894 TEST(XFormTest
, verifyRotateAboutForArbitraryAxis
) {
1895 // Check rotation about an arbitrary non-axis-aligned vector.
1897 A
.RotateAbout(Vector3dF(1.0, 1.0, 1.0), 90.0);
1898 EXPECT_ROW1_NEAR(0.3333333333333334258519187,
1899 -0.2440169358562924717404030,
1900 0.9106836025229592124219380,
1901 0.0, A
, ERROR_THRESHOLD
);
1902 EXPECT_ROW2_NEAR(0.9106836025229592124219380,
1903 0.3333333333333334258519187,
1904 -0.2440169358562924717404030,
1905 0.0, A
, ERROR_THRESHOLD
);
1906 EXPECT_ROW3_NEAR(-0.2440169358562924717404030,
1907 0.9106836025229592124219380,
1908 0.3333333333333334258519187,
1909 0.0, A
, ERROR_THRESHOLD
);
1910 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1913 TEST(XFormTest
, verifyRotateAboutForDegenerateAxis
) {
1914 // Check rotation about a degenerate zero vector.
1915 // It is expected to skip applying the rotation.
1918 A
.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 45.0);
1919 // Verify that A remains unchanged.
1920 EXPECT_TRUE(A
.IsIdentity());
1922 InitializeTestMatrix(&A
);
1923 A
.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 35.0);
1925 // Verify that A remains unchanged.
1926 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, A
);
1927 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, A
);
1928 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, A
);
1929 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, A
);
1932 TEST(XFormTest
, verifySkewX
) {
1935 EXPECT_ROW1_EQ(1.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1936 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1937 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1938 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1940 // Verify that skewX() post-multiplies the existing matrix. Row 1, column 2,
1941 // would incorrectly have value "7" if the matrix is pre-multiplied instead
1942 // of post-multiplied.
1944 A
.Scale3d(6.0, 7.0, 8.0);
1946 EXPECT_ROW1_EQ(6.0f
, 6.0f
, 0.0f
, 0.0f
, A
);
1947 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 0.0f
, A
);
1948 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1949 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1952 TEST(XFormTest
, verifySkewY
) {
1955 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1956 EXPECT_ROW2_EQ(1.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1957 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1958 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1960 // Verify that skewY() post-multiplies the existing matrix. Row 2, column 1 ,
1961 // would incorrectly have value "6" if the matrix is pre-multiplied instead
1962 // of post-multiplied.
1964 A
.Scale3d(6.0, 7.0, 8.0);
1966 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1967 EXPECT_ROW2_EQ(7.0f
, 7.0f
, 0.0f
, 0.0f
, A
);
1968 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1969 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1972 TEST(XFormTest
, verifyPerspectiveDepth
) {
1974 A
.ApplyPerspectiveDepth(1.0);
1975 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1976 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1977 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1978 EXPECT_ROW4_EQ(0.0f
, 0.0f
, -1.0f
, 1.0f
, A
);
1980 // Verify that PerspectiveDepth() post-multiplies the existing matrix.
1982 A
.Translate3d(2.0, 3.0, 4.0);
1983 A
.ApplyPerspectiveDepth(1.0);
1984 EXPECT_ROW1_EQ(1.0f
, 0.0f
, -2.0f
, 2.0f
, A
);
1985 EXPECT_ROW2_EQ(0.0f
, 1.0f
, -3.0f
, 3.0f
, A
);
1986 EXPECT_ROW3_EQ(0.0f
, 0.0f
, -3.0f
, 4.0f
, A
);
1987 EXPECT_ROW4_EQ(0.0f
, 0.0f
, -1.0f
, 1.0f
, A
);
1990 TEST(XFormTest
, verifyHasPerspective
) {
1992 A
.ApplyPerspectiveDepth(1.0);
1993 EXPECT_TRUE(A
.HasPerspective());
1996 A
.ApplyPerspectiveDepth(0.0);
1997 EXPECT_FALSE(A
.HasPerspective());
2000 A
.matrix().set(3, 0, -1.f
);
2001 EXPECT_TRUE(A
.HasPerspective());
2004 A
.matrix().set(3, 1, -1.f
);
2005 EXPECT_TRUE(A
.HasPerspective());
2008 A
.matrix().set(3, 2, -0.3f
);
2009 EXPECT_TRUE(A
.HasPerspective());
2012 A
.matrix().set(3, 3, 0.5f
);
2013 EXPECT_TRUE(A
.HasPerspective());
2016 A
.matrix().set(3, 3, 0.f
);
2017 EXPECT_TRUE(A
.HasPerspective());
2020 TEST(XFormTest
, verifyIsInvertible
) {
2023 // Translations, rotations, scales, skews and arbitrary combinations of them
2026 EXPECT_TRUE(A
.IsInvertible());
2029 A
.Translate3d(2.0, 3.0, 4.0);
2030 EXPECT_TRUE(A
.IsInvertible());
2033 A
.Scale3d(6.0, 7.0, 8.0);
2034 EXPECT_TRUE(A
.IsInvertible());
2037 A
.RotateAboutXAxis(10.0);
2038 A
.RotateAboutYAxis(20.0);
2039 A
.RotateAboutZAxis(30.0);
2040 EXPECT_TRUE(A
.IsInvertible());
2044 EXPECT_TRUE(A
.IsInvertible());
2046 // A perspective matrix (projection plane at z=0) is invertible. The
2047 // intuitive explanation is that perspective is eqivalent to a skew of the
2048 // w-axis; skews are invertible.
2050 A
.ApplyPerspectiveDepth(1.0);
2051 EXPECT_TRUE(A
.IsInvertible());
2053 // A "pure" perspective matrix derived by similar triangles, with m44() set
2054 // to zero (i.e. camera positioned at the origin), is not invertible.
2056 A
.ApplyPerspectiveDepth(1.0);
2057 A
.matrix().set(3, 3, 0.f
);
2058 EXPECT_FALSE(A
.IsInvertible());
2060 // Adding more to a non-invertible matrix will not make it invertible in the
2063 A
.ApplyPerspectiveDepth(1.0);
2064 A
.matrix().set(3, 3, 0.f
);
2065 A
.Scale3d(6.0, 7.0, 8.0);
2066 A
.RotateAboutXAxis(10.0);
2067 A
.RotateAboutYAxis(20.0);
2068 A
.RotateAboutZAxis(30.0);
2069 A
.Translate3d(6.0, 7.0, 8.0);
2070 EXPECT_FALSE(A
.IsInvertible());
2072 // A degenerate matrix of all zeros is not invertible.
2074 A
.matrix().set(0, 0, 0.f
);
2075 A
.matrix().set(1, 1, 0.f
);
2076 A
.matrix().set(2, 2, 0.f
);
2077 A
.matrix().set(3, 3, 0.f
);
2078 EXPECT_FALSE(A
.IsInvertible());
2081 TEST(XFormTest
, verifyIsIdentity
) {
2084 InitializeTestMatrix(&A
);
2085 EXPECT_FALSE(A
.IsIdentity());
2088 EXPECT_TRUE(A
.IsIdentity());
2090 // Modifying any one individual element should cause the matrix to no longer
2093 A
.matrix().set(0, 0, 2.f
);
2094 EXPECT_FALSE(A
.IsIdentity());
2097 A
.matrix().set(1, 0, 2.f
);
2098 EXPECT_FALSE(A
.IsIdentity());
2101 A
.matrix().set(2, 0, 2.f
);
2102 EXPECT_FALSE(A
.IsIdentity());
2105 A
.matrix().set(3, 0, 2.f
);
2106 EXPECT_FALSE(A
.IsIdentity());
2109 A
.matrix().set(0, 1, 2.f
);
2110 EXPECT_FALSE(A
.IsIdentity());
2113 A
.matrix().set(1, 1, 2.f
);
2114 EXPECT_FALSE(A
.IsIdentity());
2117 A
.matrix().set(2, 1, 2.f
);
2118 EXPECT_FALSE(A
.IsIdentity());
2121 A
.matrix().set(3, 1, 2.f
);
2122 EXPECT_FALSE(A
.IsIdentity());
2125 A
.matrix().set(0, 2, 2.f
);
2126 EXPECT_FALSE(A
.IsIdentity());
2129 A
.matrix().set(1, 2, 2.f
);
2130 EXPECT_FALSE(A
.IsIdentity());
2133 A
.matrix().set(2, 2, 2.f
);
2134 EXPECT_FALSE(A
.IsIdentity());
2137 A
.matrix().set(3, 2, 2.f
);
2138 EXPECT_FALSE(A
.IsIdentity());
2141 A
.matrix().set(0, 3, 2.f
);
2142 EXPECT_FALSE(A
.IsIdentity());
2145 A
.matrix().set(1, 3, 2.f
);
2146 EXPECT_FALSE(A
.IsIdentity());
2149 A
.matrix().set(2, 3, 2.f
);
2150 EXPECT_FALSE(A
.IsIdentity());
2153 A
.matrix().set(3, 3, 2.f
);
2154 EXPECT_FALSE(A
.IsIdentity());
2157 TEST(XFormTest
, verifyIsIdentityOrTranslation
) {
2160 InitializeTestMatrix(&A
);
2161 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2164 EXPECT_TRUE(A
.IsIdentityOrTranslation());
2166 // Modifying any non-translation components should cause
2167 // IsIdentityOrTranslation() to return false. NOTE: (0, 3), (1, 3), and
2168 // (2, 3) are the translation components, so modifying them should still
2171 A
.matrix().set(0, 0, 2.f
);
2172 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2175 A
.matrix().set(1, 0, 2.f
);
2176 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2179 A
.matrix().set(2, 0, 2.f
);
2180 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2183 A
.matrix().set(3, 0, 2.f
);
2184 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2187 A
.matrix().set(0, 1, 2.f
);
2188 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2191 A
.matrix().set(1, 1, 2.f
);
2192 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2195 A
.matrix().set(2, 1, 2.f
);
2196 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2199 A
.matrix().set(3, 1, 2.f
);
2200 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2203 A
.matrix().set(0, 2, 2.f
);
2204 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2207 A
.matrix().set(1, 2, 2.f
);
2208 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2211 A
.matrix().set(2, 2, 2.f
);
2212 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2215 A
.matrix().set(3, 2, 2.f
);
2216 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2218 // Note carefully - expecting true here.
2220 A
.matrix().set(0, 3, 2.f
);
2221 EXPECT_TRUE(A
.IsIdentityOrTranslation());
2223 // Note carefully - expecting true here.
2225 A
.matrix().set(1, 3, 2.f
);
2226 EXPECT_TRUE(A
.IsIdentityOrTranslation());
2228 // Note carefully - expecting true here.
2230 A
.matrix().set(2, 3, 2.f
);
2231 EXPECT_TRUE(A
.IsIdentityOrTranslation());
2234 A
.matrix().set(3, 3, 2.f
);
2235 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2238 TEST(XFormTest
, verifyIsApproximatelyIdentityOrTranslation
) {
2240 SkMatrix44
& matrix
= A
.matrix();
2242 // Exact pure translation.
2245 // Set translate values to values other than 0 or 1.
2246 matrix
.set(0, 3, 3.4f
);
2247 matrix
.set(1, 3, 4.4f
);
2248 matrix
.set(2, 3, 5.6f
);
2250 EXPECT_TRUE(A
.IsApproximatelyIdentityOrTranslation(0));
2251 EXPECT_TRUE(A
.IsApproximatelyIdentityOrTranslation(kApproxZero
));
2253 // Approximately pure translation.
2254 InitializeApproxIdentityMatrix(&A
);
2256 // Some values must be exact.
2257 matrix
.set(3, 0, 0);
2258 matrix
.set(3, 1, 0);
2259 matrix
.set(3, 2, 0);
2260 matrix
.set(3, 3, 1);
2262 // Set translate values to values other than 0 or 1.
2263 matrix
.set(0, 3, 3.4f
);
2264 matrix
.set(1, 3, 4.4f
);
2265 matrix
.set(2, 3, 5.6f
);
2267 EXPECT_FALSE(A
.IsApproximatelyIdentityOrTranslation(0));
2268 EXPECT_TRUE(A
.IsApproximatelyIdentityOrTranslation(kApproxZero
));
2270 // Not approximately pure translation.
2271 InitializeApproxIdentityMatrix(&A
);
2273 // Some values must be exact.
2274 matrix
.set(3, 0, 0);
2275 matrix
.set(3, 1, 0);
2276 matrix
.set(3, 2, 0);
2277 matrix
.set(3, 3, 1);
2279 // Set some values (not translate values) to values other than 0 or 1.
2280 matrix
.set(0, 1, 3.4f
);
2281 matrix
.set(3, 2, 4.4f
);
2282 matrix
.set(2, 0, 5.6f
);
2284 EXPECT_FALSE(A
.IsApproximatelyIdentityOrTranslation(0));
2285 EXPECT_FALSE(A
.IsApproximatelyIdentityOrTranslation(kApproxZero
));
2288 TEST(XFormTest
, verifyIsScaleOrTranslation
) {
2291 InitializeTestMatrix(&A
);
2292 EXPECT_FALSE(A
.IsScaleOrTranslation());
2295 EXPECT_TRUE(A
.IsScaleOrTranslation());
2297 // Modifying any non-scale or non-translation components should cause
2298 // IsScaleOrTranslation() to return false. (0, 0), (1, 1), (2, 2), (0, 3),
2299 // (1, 3), and (2, 3) are the scale and translation components, so
2300 // modifying them should still return true.
2302 // Note carefully - expecting true here.
2304 A
.matrix().set(0, 0, 2.f
);
2305 EXPECT_TRUE(A
.IsScaleOrTranslation());
2308 A
.matrix().set(1, 0, 2.f
);
2309 EXPECT_FALSE(A
.IsScaleOrTranslation());
2312 A
.matrix().set(2, 0, 2.f
);
2313 EXPECT_FALSE(A
.IsScaleOrTranslation());
2316 A
.matrix().set(3, 0, 2.f
);
2317 EXPECT_FALSE(A
.IsScaleOrTranslation());
2320 A
.matrix().set(0, 1, 2.f
);
2321 EXPECT_FALSE(A
.IsScaleOrTranslation());
2323 // Note carefully - expecting true here.
2325 A
.matrix().set(1, 1, 2.f
);
2326 EXPECT_TRUE(A
.IsScaleOrTranslation());
2329 A
.matrix().set(2, 1, 2.f
);
2330 EXPECT_FALSE(A
.IsScaleOrTranslation());
2333 A
.matrix().set(3, 1, 2.f
);
2334 EXPECT_FALSE(A
.IsScaleOrTranslation());
2337 A
.matrix().set(0, 2, 2.f
);
2338 EXPECT_FALSE(A
.IsScaleOrTranslation());
2341 A
.matrix().set(1, 2, 2.f
);
2342 EXPECT_FALSE(A
.IsScaleOrTranslation());
2344 // Note carefully - expecting true here.
2346 A
.matrix().set(2, 2, 2.f
);
2347 EXPECT_TRUE(A
.IsScaleOrTranslation());
2350 A
.matrix().set(3, 2, 2.f
);
2351 EXPECT_FALSE(A
.IsScaleOrTranslation());
2353 // Note carefully - expecting true here.
2355 A
.matrix().set(0, 3, 2.f
);
2356 EXPECT_TRUE(A
.IsScaleOrTranslation());
2358 // Note carefully - expecting true here.
2360 A
.matrix().set(1, 3, 2.f
);
2361 EXPECT_TRUE(A
.IsScaleOrTranslation());
2363 // Note carefully - expecting true here.
2365 A
.matrix().set(2, 3, 2.f
);
2366 EXPECT_TRUE(A
.IsScaleOrTranslation());
2369 A
.matrix().set(3, 3, 2.f
);
2370 EXPECT_FALSE(A
.IsScaleOrTranslation());
2373 TEST(XFormTest
, verifyFlattenTo2d
) {
2375 InitializeTestMatrix(&A
);
2378 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 0.0f
, 22.0f
, A
);
2379 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 0.0f
, 23.0f
, A
);
2380 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
2381 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 0.0f
, 25.0f
, A
);
2384 TEST(XFormTest
, IsFlat
) {
2385 Transform transform
;
2386 InitializeTestMatrix(&transform
);
2388 // A transform with all entries non-zero isn't flat.
2389 EXPECT_FALSE(transform
.IsFlat());
2391 transform
.matrix().set(0, 2, 0.f
);
2392 transform
.matrix().set(1, 2, 0.f
);
2393 transform
.matrix().set(2, 2, 1.f
);
2394 transform
.matrix().set(3, 2, 0.f
);
2396 EXPECT_FALSE(transform
.IsFlat());
2398 transform
.matrix().set(2, 0, 0.f
);
2399 transform
.matrix().set(2, 1, 0.f
);
2400 transform
.matrix().set(2, 3, 0.f
);
2402 // Since the third column and row are both (0, 0, 1, 0), the transform is
2404 EXPECT_TRUE(transform
.IsFlat());
2407 // Another implementation of Preserves2dAxisAlignment that isn't as fast,
2408 // good for testing the faster implementation.
2409 static bool EmpiricallyPreserves2dAxisAlignment(const Transform
& transform
) {
2410 Point3F
p1(5.0f
, 5.0f
, 0.0f
);
2411 Point3F
p2(10.0f
, 5.0f
, 0.0f
);
2412 Point3F
p3(10.0f
, 20.0f
, 0.0f
);
2413 Point3F
p4(5.0f
, 20.0f
, 0.0f
);
2415 QuadF
test_quad(PointF(p1
.x(), p1
.y()),
2416 PointF(p2
.x(), p2
.y()),
2417 PointF(p3
.x(), p3
.y()),
2418 PointF(p4
.x(), p4
.y()));
2419 EXPECT_TRUE(test_quad
.IsRectilinear());
2421 transform
.TransformPoint(&p1
);
2422 transform
.TransformPoint(&p2
);
2423 transform
.TransformPoint(&p3
);
2424 transform
.TransformPoint(&p4
);
2426 QuadF
transformedQuad(PointF(p1
.x(), p1
.y()),
2427 PointF(p2
.x(), p2
.y()),
2428 PointF(p3
.x(), p3
.y()),
2429 PointF(p4
.x(), p4
.y()));
2430 return transformedQuad
.IsRectilinear();
2433 TEST(XFormTest
, Preserves2dAxisAlignment
) {
2434 static const struct TestCase
{
2435 SkMScalar a
; // row 1, column 1
2436 SkMScalar b
; // row 1, column 2
2437 SkMScalar c
; // row 2, column 1
2438 SkMScalar d
; // row 2, column 2
2442 0.f
, 4.f
, true }, // basic case
2444 3.f
, 0.f
, true }, // rotate by 90
2446 0.f
, 4.f
, true }, // degenerate x
2448 0.f
, 0.f
, true }, // degenerate y
2450 3.f
, 0.f
, true }, // degenerate x + rotate by 90
2452 0.f
, 0.f
, true }, // degenerate y + rotate by 90
2473 Transform transform
;
2474 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
2475 const TestCase
& value
= test_cases
[i
];
2476 transform
.MakeIdentity();
2477 transform
.matrix().set(0, 0, value
.a
);
2478 transform
.matrix().set(0, 1, value
.b
);
2479 transform
.matrix().set(1, 0, value
.c
);
2480 transform
.matrix().set(1, 1, value
.d
);
2482 if (value
.expected
) {
2483 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2484 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2486 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform
));
2487 EXPECT_FALSE(transform
.Preserves2dAxisAlignment());
2491 // Try the same test cases again, but this time make sure that other matrix
2492 // elements (except perspective) have entries, to test that they are ignored.
2493 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
2494 const TestCase
& value
= test_cases
[i
];
2495 transform
.MakeIdentity();
2496 transform
.matrix().set(0, 0, value
.a
);
2497 transform
.matrix().set(0, 1, value
.b
);
2498 transform
.matrix().set(1, 0, value
.c
);
2499 transform
.matrix().set(1, 1, value
.d
);
2501 transform
.matrix().set(0, 2, 1.f
);
2502 transform
.matrix().set(0, 3, 2.f
);
2503 transform
.matrix().set(1, 2, 3.f
);
2504 transform
.matrix().set(1, 3, 4.f
);
2505 transform
.matrix().set(2, 0, 5.f
);
2506 transform
.matrix().set(2, 1, 6.f
);
2507 transform
.matrix().set(2, 2, 7.f
);
2508 transform
.matrix().set(2, 3, 8.f
);
2510 if (value
.expected
) {
2511 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2512 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2514 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform
));
2515 EXPECT_FALSE(transform
.Preserves2dAxisAlignment());
2519 // Try the same test cases again, but this time add perspective which is
2520 // always assumed to not-preserve axis alignment.
2521 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
2522 const TestCase
& value
= test_cases
[i
];
2523 transform
.MakeIdentity();
2524 transform
.matrix().set(0, 0, value
.a
);
2525 transform
.matrix().set(0, 1, value
.b
);
2526 transform
.matrix().set(1, 0, value
.c
);
2527 transform
.matrix().set(1, 1, value
.d
);
2529 transform
.matrix().set(0, 2, 1.f
);
2530 transform
.matrix().set(0, 3, 2.f
);
2531 transform
.matrix().set(1, 2, 3.f
);
2532 transform
.matrix().set(1, 3, 4.f
);
2533 transform
.matrix().set(2, 0, 5.f
);
2534 transform
.matrix().set(2, 1, 6.f
);
2535 transform
.matrix().set(2, 2, 7.f
);
2536 transform
.matrix().set(2, 3, 8.f
);
2537 transform
.matrix().set(3, 0, 9.f
);
2538 transform
.matrix().set(3, 1, 10.f
);
2539 transform
.matrix().set(3, 2, 11.f
);
2540 transform
.matrix().set(3, 3, 12.f
);
2542 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform
));
2543 EXPECT_FALSE(transform
.Preserves2dAxisAlignment());
2546 // Try a few more practical situations to check precision
2547 transform
.MakeIdentity();
2548 transform
.RotateAboutZAxis(90.0);
2549 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2550 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2552 transform
.MakeIdentity();
2553 transform
.RotateAboutZAxis(180.0);
2554 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2555 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2557 transform
.MakeIdentity();
2558 transform
.RotateAboutZAxis(270.0);
2559 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2560 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2562 transform
.MakeIdentity();
2563 transform
.RotateAboutYAxis(90.0);
2564 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2565 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2567 transform
.MakeIdentity();
2568 transform
.RotateAboutXAxis(90.0);
2569 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2570 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2572 transform
.MakeIdentity();
2573 transform
.RotateAboutZAxis(90.0);
2574 transform
.RotateAboutYAxis(90.0);
2575 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2576 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2578 transform
.MakeIdentity();
2579 transform
.RotateAboutZAxis(90.0);
2580 transform
.RotateAboutXAxis(90.0);
2581 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2582 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2584 transform
.MakeIdentity();
2585 transform
.RotateAboutYAxis(90.0);
2586 transform
.RotateAboutZAxis(90.0);
2587 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2588 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2590 transform
.MakeIdentity();
2591 transform
.RotateAboutZAxis(45.0);
2592 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform
));
2593 EXPECT_FALSE(transform
.Preserves2dAxisAlignment());
2595 // 3-d case; In 2d after an orthographic projection, this case does
2596 // preserve 2d axis alignment. But in 3d, it does not preserve axis
2598 transform
.MakeIdentity();
2599 transform
.RotateAboutYAxis(45.0);
2600 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2601 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2603 transform
.MakeIdentity();
2604 transform
.RotateAboutXAxis(45.0);
2605 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2606 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2608 // Perspective cases.
2609 transform
.MakeIdentity();
2610 transform
.ApplyPerspectiveDepth(10.0);
2611 transform
.RotateAboutYAxis(45.0);
2612 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform
));
2613 EXPECT_FALSE(transform
.Preserves2dAxisAlignment());
2615 transform
.MakeIdentity();
2616 transform
.ApplyPerspectiveDepth(10.0);
2617 transform
.RotateAboutZAxis(90.0);
2618 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2619 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2622 TEST(XFormTest
, To2dTranslation
) {
2623 Vector2dF
translation(3.f
, 7.f
);
2624 Transform transform
;
2625 transform
.Translate(translation
.x(), translation
.y() + 1);
2626 EXPECT_NE(translation
.ToString(), transform
.To2dTranslation().ToString());
2627 transform
.MakeIdentity();
2628 transform
.Translate(translation
.x(), translation
.y());
2629 EXPECT_EQ(translation
.ToString(), transform
.To2dTranslation().ToString());
2632 TEST(XFormTest
, TransformRect
) {
2633 Transform translation
;
2634 translation
.Translate(3.f
, 7.f
);
2635 RectF
rect(1.f
, 2.f
, 3.f
, 4.f
);
2636 RectF
expected(4.f
, 9.f
, 3.f
, 4.f
);
2637 translation
.TransformRect(&rect
);
2638 EXPECT_EQ(expected
.ToString(), rect
.ToString());
2641 TEST(XFormTest
, TransformRectReverse
) {
2642 Transform translation
;
2643 translation
.Translate(3.f
, 7.f
);
2644 RectF
rect(1.f
, 2.f
, 3.f
, 4.f
);
2645 RectF
expected(-2.f
, -5.f
, 3.f
, 4.f
);
2646 EXPECT_TRUE(translation
.TransformRectReverse(&rect
));
2647 EXPECT_EQ(expected
.ToString(), rect
.ToString());
2650 singular
.Scale3d(0.f
, 0.f
, 0.f
);
2651 EXPECT_FALSE(singular
.TransformRectReverse(&rect
));
2654 TEST(XFormTest
, TransformBox
) {
2655 Transform translation
;
2656 translation
.Translate3d(3.f
, 7.f
, 6.f
);
2657 BoxF
box(1.f
, 2.f
, 3.f
, 4.f
, 5.f
, 6.f
);
2658 BoxF
expected(4.f
, 9.f
, 9.f
, 4.f
, 5.f
, 6.f
);
2659 translation
.TransformBox(&box
);
2660 EXPECT_EQ(expected
.ToString(), box
.ToString());
2663 TEST(XFormTest
, TransformBoxReverse
) {
2664 Transform translation
;
2665 translation
.Translate3d(3.f
, 7.f
, 6.f
);
2666 BoxF
box(1.f
, 2.f
, 3.f
, 4.f
, 5.f
, 6.f
);
2667 BoxF
expected(-2.f
, -5.f
, -3.f
, 4.f
, 5.f
, 6.f
);
2668 EXPECT_TRUE(translation
.TransformBoxReverse(&box
));
2669 EXPECT_EQ(expected
.ToString(), box
.ToString());
2672 singular
.Scale3d(0.f
, 0.f
, 0.f
);
2673 EXPECT_FALSE(singular
.TransformBoxReverse(&box
));
2676 TEST(XFormTest
, RoundTranslationComponents
) {
2677 Transform translation
;
2680 translation
.RoundTranslationComponents();
2681 EXPECT_EQ(expected
.ToString(), translation
.ToString());
2683 translation
.Translate(1.0f
, 1.0f
);
2684 expected
.Translate(1.0f
, 1.0f
);
2685 translation
.RoundTranslationComponents();
2686 EXPECT_EQ(expected
.ToString(), translation
.ToString());
2688 translation
.Translate(0.5f
, 0.4f
);
2689 expected
.Translate(1.0f
, 0.0f
);
2690 translation
.RoundTranslationComponents();
2691 EXPECT_EQ(expected
.ToString(), translation
.ToString());
2693 // Rounding should only affect 2d translation components.
2694 translation
.Translate3d(0.f
, 0.f
, 0.5f
);
2695 expected
.Translate3d(0.f
, 0.f
, 0.5f
);
2696 translation
.RoundTranslationComponents();
2697 EXPECT_EQ(expected
.ToString(), translation
.ToString());