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
) {
783 expected
.Skew(t
* 10, t
* 5);
784 EXPECT_TRUE(to
.Blend(from
, t
));
785 EXPECT_TRUE(MatricesAreNearlyEqual(expected
, to
));
789 TEST(XFormTest
, ExtrapolateSkew
) {
791 for (int i
= -1; i
< 2; ++i
) {
796 expected
.Skew(t
* 20, t
* 0);
797 EXPECT_TRUE(to
.Blend(from
, t
));
798 EXPECT_TRUE(MatricesAreNearlyEqual(expected
, to
));
803 // http://crbug.com/406574
804 #define MAYBE_BlendPerspective DISABLED_BlendPerspective
806 #define MAYBE_BlendPerspective BlendPerspective
808 TEST(XFormTest
, MAYBE_BlendPerspective
) {
810 from
.ApplyPerspectiveDepth(200);
811 for (int i
= -1; i
< 3; ++i
) {
813 to
.ApplyPerspectiveDepth(800);
815 double depth
= 1.0 / ((1.0 / 200) * (1.0 - t
) + (1.0 / 800) * t
);
817 expected
.ApplyPerspectiveDepth(depth
);
818 EXPECT_TRUE(to
.Blend(from
, t
));
819 EXPECT_TRUE(MatricesAreNearlyEqual(expected
, to
));
823 TEST(XFormTest
, BlendIdentity
) {
826 EXPECT_TRUE(to
.Blend(from
, 0.5));
830 TEST(XFormTest
, CannotBlendSingularMatrix
) {
833 to
.matrix().set(1, 1, SkDoubleToMScalar(0));
834 EXPECT_FALSE(to
.Blend(from
, 0.5));
837 TEST(XFormTest
, VerifyBlendForTranslation
) {
839 from
.Translate3d(100.0, 200.0, 100.0);
843 to
.Translate3d(200.0, 100.0, 300.0);
848 to
.Translate3d(200.0, 100.0, 300.0);
849 to
.Blend(from
, 0.25);
850 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 125.0f
, to
);
851 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 175.0f
, to
);
852 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 150.0f
, to
);
853 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
856 to
.Translate3d(200.0, 100.0, 300.0);
858 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 150.0f
, to
);
859 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 150.0f
, to
);
860 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 200.0f
, to
);
861 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
864 to
.Translate3d(200.0, 100.0, 300.0);
866 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 200.0f
, to
);
867 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 100.0f
, to
);
868 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 300.0f
, to
);
869 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
872 TEST(XFormTest
, VerifyBlendForScale
) {
874 from
.Scale3d(100.0, 200.0, 100.0);
878 to
.Scale3d(200.0, 100.0, 300.0);
883 to
.Scale3d(200.0, 100.0, 300.0);
884 to
.Blend(from
, 0.25);
885 EXPECT_ROW1_EQ(125.0f
, 0.0f
, 0.0f
, 0.0f
, to
);
886 EXPECT_ROW2_EQ(0.0f
, 175.0f
, 0.0f
, 0.0f
, to
);
887 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 150.0f
, 0.0f
, to
);
888 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
891 to
.Scale3d(200.0, 100.0, 300.0);
893 EXPECT_ROW1_EQ(150.0f
, 0.0f
, 0.0f
, 0.0f
, to
);
894 EXPECT_ROW2_EQ(0.0f
, 150.0f
, 0.0f
, 0.0f
, to
);
895 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 200.0f
, 0.0f
, to
);
896 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
899 to
.Scale3d(200.0, 100.0, 300.0);
901 EXPECT_ROW1_EQ(200.0f
, 0.0f
, 0.0f
, 0.0f
, to
);
902 EXPECT_ROW2_EQ(0.0f
, 100.0f
, 0.0f
, 0.0f
, to
);
903 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 300.0f
, 0.0f
, to
);
904 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
907 TEST(XFormTest
, VerifyBlendForSkew
) {
921 EXPECT_ROW1_EQ(1.0f
, 0.5f
, 0.0f
, 0.0f
, to
);
922 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, to
);
923 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
924 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
928 to
.Blend(from
, 0.25);
929 EXPECT_ROW1_EQ(1.0f
, 0.25f
, 0.0f
, 0.0f
, to
);
930 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, to
);
931 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
932 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
937 EXPECT_ROW1_EQ(1.0f
, 1.0f
, 0.0f
, 0.0f
, to
);
938 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, to
);
939 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
940 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
942 // NOTE CAREFULLY: Decomposition of skew and rotation terms of the matrix
943 // is inherently underconstrained, and so it does not always compute the
944 // originally intended skew parameters. The current implementation uses QR
945 // decomposition, which decomposes the shear into a rotation + non-uniform
948 // It is unlikely that the decomposition implementation will need to change
949 // very often, so to get any test coverage, the compromise is to verify the
950 // exact matrix that the.Blend() operation produces.
952 // This problem also potentially exists for skew along the X axis, but the
953 // current QR decomposition implementation just happens to decompose those
954 // test matrices intuitively.
956 // Unfortunately, this case suffers from uncomfortably large precision
970 to
.Blend(from
, 0.25);
971 EXPECT_ROW1_NEAR(1.0823489449280947471976333,
972 0.0464370719145053845178239,
976 LOOSE_ERROR_THRESHOLD
);
977 EXPECT_ROW2_NEAR(0.2152925909665224513123150,
978 0.9541702441750861130032035,
982 LOOSE_ERROR_THRESHOLD
);
983 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
984 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
989 EXPECT_ROW1_NEAR(1.1152212925809066312865525,
990 0.0676495144007326631996335,
994 LOOSE_ERROR_THRESHOLD
);
995 EXPECT_ROW2_NEAR(0.4619397844342648662419037,
996 0.9519009045724774464858342,
1000 LOOSE_ERROR_THRESHOLD
);
1001 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
1002 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1006 to
.Blend(from
, 1.0);
1007 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to
, LOOSE_ERROR_THRESHOLD
);
1008 EXPECT_ROW2_NEAR(1.0, 1.0, 0.0, 0.0, to
, LOOSE_ERROR_THRESHOLD
);
1009 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
1010 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1014 // http://crbug.com/406574
1015 #define MAYBE_VerifyBlendForRotationAboutX DISABLED_VerifyBlendForRotationAboutX
1017 #define MAYBE_VerifyBlendForRotationAboutX VerifyBlendForRotationAboutX
1019 TEST(XFormTest
, MAYBE_VerifyBlendForRotationAboutX
) {
1020 // Even though.Blending uses quaternions, axis-aligned rotations should.
1021 // Blend the same with quaternions or Euler angles. So we can test
1022 // rotation.Blending by comparing against manually specified matrices from
1026 from
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 0.0);
1030 to
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1031 to
.Blend(from
, 0.0);
1032 EXPECT_EQ(from
, to
);
1034 double expectedRotationAngle
= 22.5 * M_PI
/ 180.0;
1036 to
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1037 to
.Blend(from
, 0.25);
1038 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1039 EXPECT_ROW2_NEAR(0.0,
1040 std::cos(expectedRotationAngle
),
1041 -std::sin(expectedRotationAngle
),
1045 EXPECT_ROW3_NEAR(0.0,
1046 std::sin(expectedRotationAngle
),
1047 std::cos(expectedRotationAngle
),
1051 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1053 expectedRotationAngle
= 45.0 * M_PI
/ 180.0;
1055 to
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1056 to
.Blend(from
, 0.5);
1057 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1058 EXPECT_ROW2_NEAR(0.0,
1059 std::cos(expectedRotationAngle
),
1060 -std::sin(expectedRotationAngle
),
1064 EXPECT_ROW3_NEAR(0.0,
1065 std::sin(expectedRotationAngle
),
1066 std::cos(expectedRotationAngle
),
1070 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1073 to
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1074 to
.Blend(from
, 1.0);
1075 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1076 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, to
, ERROR_THRESHOLD
);
1077 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1078 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1082 // http://crbug.com/406574
1083 #define MAYBE_VerifyBlendForRotationAboutY DISABLED_VerifyBlendForRotationAboutY
1085 #define MAYBE_VerifyBlendForRotationAboutY VerifyBlendForRotationAboutY
1087 TEST(XFormTest
, MAYBE_VerifyBlendForRotationAboutY
) {
1089 from
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 0.0);
1093 to
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1094 to
.Blend(from
, 0.0);
1095 EXPECT_EQ(from
, to
);
1097 double expectedRotationAngle
= 22.5 * M_PI
/ 180.0;
1099 to
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1100 to
.Blend(from
, 0.25);
1101 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle
),
1103 std::sin(expectedRotationAngle
),
1107 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1108 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle
),
1110 std::cos(expectedRotationAngle
),
1114 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1116 expectedRotationAngle
= 45.0 * M_PI
/ 180.0;
1118 to
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1119 to
.Blend(from
, 0.5);
1120 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle
),
1122 std::sin(expectedRotationAngle
),
1126 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1127 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle
),
1129 std::cos(expectedRotationAngle
),
1133 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1136 to
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1137 to
.Blend(from
, 1.0);
1138 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, to
, ERROR_THRESHOLD
);
1139 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1140 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1141 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1145 // http://crbug.com/406574
1146 #define MAYBE_VerifyBlendForRotationAboutZ DISABLED_VerifyBlendForRotationAboutZ
1148 #define MAYBE_VerifyBlendForRotationAboutZ VerifyBlendForRotationAboutZ
1150 TEST(XFormTest
, MAYBE_VerifyBlendForRotationAboutZ
) {
1152 from
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 0.0);
1156 to
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1157 to
.Blend(from
, 0.0);
1158 EXPECT_EQ(from
, to
);
1160 double expectedRotationAngle
= 22.5 * M_PI
/ 180.0;
1162 to
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1163 to
.Blend(from
, 0.25);
1164 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle
),
1165 -std::sin(expectedRotationAngle
),
1170 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle
),
1171 std::cos(expectedRotationAngle
),
1176 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to
, ERROR_THRESHOLD
);
1177 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1179 expectedRotationAngle
= 45.0 * M_PI
/ 180.0;
1181 to
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1182 to
.Blend(from
, 0.5);
1183 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle
),
1184 -std::sin(expectedRotationAngle
),
1189 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle
),
1190 std::cos(expectedRotationAngle
),
1195 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to
, ERROR_THRESHOLD
);
1196 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1199 to
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1200 to
.Blend(from
, 1.0);
1201 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1202 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1203 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to
, ERROR_THRESHOLD
);
1204 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1207 TEST(XFormTest
, VerifyBlendForCompositeTransform
) {
1208 // Verify that the.Blending was done with a decomposition in correct order
1209 // by blending a composite transform. Using matrix x vector notation
1210 // (Ax = b, where x is column vector), the ordering should be:
1211 // perspective * translation * rotation * skew * scale
1213 // It is not as important (or meaningful) to check intermediate
1214 // interpolations; order of operations will be tested well enough by the
1215 // end cases that are easier to specify.
1220 Transform expectedEndOfAnimation
;
1221 expectedEndOfAnimation
.ApplyPerspectiveDepth(1.0);
1222 expectedEndOfAnimation
.Translate3d(10.0, 20.0, 30.0);
1223 expectedEndOfAnimation
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 25.0);
1224 expectedEndOfAnimation
.Skew(0.0, 45.0);
1225 expectedEndOfAnimation
.Scale3d(6.0, 7.0, 8.0);
1227 to
= expectedEndOfAnimation
;
1228 to
.Blend(from
, 0.0);
1229 EXPECT_EQ(from
, to
);
1231 to
= expectedEndOfAnimation
;
1232 // We short circuit if blend is >= 1, so to check the numerics, we will
1233 // check that we get close to what we expect when we're nearly done
1235 to
.Blend(from
, .99999f
);
1237 // Recomposing the matrix results in a normalized matrix, so to verify we
1238 // need to normalize the expectedEndOfAnimation before comparing elements.
1239 // Normalizing means dividing everything by expectedEndOfAnimation.m44().
1240 Transform normalizedExpectedEndOfAnimation
= expectedEndOfAnimation
;
1241 Transform normalizationMatrix
;
1242 normalizationMatrix
.matrix().set(
1245 SkDoubleToMScalar(1 / expectedEndOfAnimation
.matrix().get(3.0, 3.0)));
1246 normalizationMatrix
.matrix().set(
1249 SkDoubleToMScalar(1 / expectedEndOfAnimation
.matrix().get(3.0, 3.0)));
1250 normalizationMatrix
.matrix().set(
1253 SkDoubleToMScalar(1 / expectedEndOfAnimation
.matrix().get(3.0, 3.0)));
1254 normalizationMatrix
.matrix().set(
1257 SkDoubleToMScalar(1 / expectedEndOfAnimation
.matrix().get(3.0, 3.0)));
1258 normalizedExpectedEndOfAnimation
.PreconcatTransform(normalizationMatrix
);
1260 EXPECT_TRUE(MatricesAreNearlyEqual(normalizedExpectedEndOfAnimation
, to
));
1263 TEST(XFormTest
, DecomposedTransformCtor
) {
1264 DecomposedTransform decomp
;
1265 for (int i
= 0; i
< 3; ++i
) {
1266 EXPECT_EQ(0.0, decomp
.translate
[i
]);
1267 EXPECT_EQ(1.0, decomp
.scale
[i
]);
1268 EXPECT_EQ(0.0, decomp
.skew
[i
]);
1269 EXPECT_EQ(0.0, decomp
.quaternion
[i
]);
1270 EXPECT_EQ(0.0, decomp
.perspective
[i
]);
1272 EXPECT_EQ(1.0, decomp
.quaternion
[3]);
1273 EXPECT_EQ(1.0, decomp
.perspective
[3]);
1275 Transform composed
= ComposeTransform(decomp
);
1276 EXPECT_TRUE(MatricesAreNearlyEqual(identity
, composed
));
1279 TEST(XFormTest
, FactorTRS
) {
1280 for (int degrees
= 0; degrees
< 180; ++degrees
) {
1281 // build a transformation matrix.
1282 gfx::Transform transform
;
1283 transform
.Translate(degrees
* 2, -degrees
* 3);
1284 transform
.Rotate(degrees
);
1285 transform
.Scale(degrees
+ 1, 2 * degrees
+ 1);
1287 // factor the matrix
1288 DecomposedTransform decomp
;
1289 bool success
= DecomposeTransform(&decomp
, transform
);
1290 EXPECT_TRUE(success
);
1291 EXPECT_FLOAT_EQ(decomp
.translate
[0], degrees
* 2);
1292 EXPECT_FLOAT_EQ(decomp
.translate
[1], -degrees
* 3);
1294 std::acos(SkMScalarToDouble(decomp
.quaternion
[3])) * 360.0 / M_PI
;
1295 while (rotation
< 0.0)
1297 while (rotation
> 360.0)
1300 const float epsilon
= 0.00015f
;
1301 EXPECT_NEAR(rotation
, degrees
, epsilon
);
1302 EXPECT_NEAR(decomp
.scale
[0], degrees
+ 1, epsilon
);
1303 EXPECT_NEAR(decomp
.scale
[1], 2 * degrees
+ 1, epsilon
);
1307 TEST(XFormTest
, DecomposeTransform
) {
1308 for (float scale
= 0.001f
; scale
< 2.0f
; scale
+= 0.001f
) {
1309 gfx::Transform transform
;
1310 transform
.Scale(scale
, scale
);
1311 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
1313 DecomposedTransform decomp
;
1314 bool success
= DecomposeTransform(&decomp
, transform
);
1315 EXPECT_TRUE(success
);
1317 gfx::Transform compose_transform
= ComposeTransform(decomp
);
1318 EXPECT_TRUE(compose_transform
.Preserves2dAxisAlignment());
1322 TEST(XFormTest
, IntegerTranslation
) {
1323 gfx::Transform transform
;
1324 EXPECT_TRUE(transform
.IsIdentityOrIntegerTranslation());
1326 transform
.Translate3d(1, 2, 3);
1327 EXPECT_TRUE(transform
.IsIdentityOrIntegerTranslation());
1329 transform
.MakeIdentity();
1330 transform
.Translate3d(-1, -2, -3);
1331 EXPECT_TRUE(transform
.IsIdentityOrIntegerTranslation());
1333 transform
.MakeIdentity();
1334 transform
.Translate3d(4.5f
, 0, 0);
1335 EXPECT_FALSE(transform
.IsIdentityOrIntegerTranslation());
1337 transform
.MakeIdentity();
1338 transform
.Translate3d(0, -6.7f
, 0);
1339 EXPECT_FALSE(transform
.IsIdentityOrIntegerTranslation());
1341 transform
.MakeIdentity();
1342 transform
.Translate3d(0, 0, 8.9f
);
1343 EXPECT_FALSE(transform
.IsIdentityOrIntegerTranslation());
1346 TEST(XFormTest
, verifyMatrixInversion
) {
1348 // Invert a translation
1349 gfx::Transform translation
;
1350 translation
.Translate3d(2.0, 3.0, 4.0);
1351 EXPECT_TRUE(translation
.IsInvertible());
1353 gfx::Transform inverse_translation
;
1354 bool is_invertible
= translation
.GetInverse(&inverse_translation
);
1355 EXPECT_TRUE(is_invertible
);
1356 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, -2.0f
, inverse_translation
);
1357 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, -3.0f
, inverse_translation
);
1358 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, -4.0f
, inverse_translation
);
1359 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, inverse_translation
);
1363 // Invert a non-uniform scale
1364 gfx::Transform scale
;
1365 scale
.Scale3d(4.0, 10.0, 100.0);
1366 EXPECT_TRUE(scale
.IsInvertible());
1368 gfx::Transform inverse_scale
;
1369 bool is_invertible
= scale
.GetInverse(&inverse_scale
);
1370 EXPECT_TRUE(is_invertible
);
1371 EXPECT_ROW1_EQ(0.25f
, 0.0f
, 0.0f
, 0.0f
, inverse_scale
);
1372 EXPECT_ROW2_EQ(0.0f
, 0.1f
, 0.0f
, 0.0f
, inverse_scale
);
1373 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 0.01f
, 0.0f
, inverse_scale
);
1374 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, inverse_scale
);
1378 // Try to invert a matrix that is not invertible.
1379 // The inverse() function should reset the output matrix to identity.
1380 gfx::Transform uninvertible
;
1381 uninvertible
.matrix().set(0, 0, 0.f
);
1382 uninvertible
.matrix().set(1, 1, 0.f
);
1383 uninvertible
.matrix().set(2, 2, 0.f
);
1384 uninvertible
.matrix().set(3, 3, 0.f
);
1385 EXPECT_FALSE(uninvertible
.IsInvertible());
1387 gfx::Transform inverse_of_uninvertible
;
1389 // Add a scale just to more easily ensure that inverse_of_uninvertible is
1390 // reset to identity.
1391 inverse_of_uninvertible
.Scale3d(4.0, 10.0, 100.0);
1393 bool is_invertible
= uninvertible
.GetInverse(&inverse_of_uninvertible
);
1394 EXPECT_FALSE(is_invertible
);
1395 EXPECT_TRUE(inverse_of_uninvertible
.IsIdentity());
1396 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, inverse_of_uninvertible
);
1397 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, inverse_of_uninvertible
);
1398 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, inverse_of_uninvertible
);
1399 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, inverse_of_uninvertible
);
1403 TEST(XFormTest
, verifyBackfaceVisibilityBasicCases
) {
1404 Transform transform
;
1406 transform
.MakeIdentity();
1407 EXPECT_FALSE(transform
.IsBackFaceVisible());
1409 transform
.MakeIdentity();
1410 transform
.RotateAboutYAxis(80.0);
1411 EXPECT_FALSE(transform
.IsBackFaceVisible());
1413 transform
.MakeIdentity();
1414 transform
.RotateAboutYAxis(100.0);
1415 EXPECT_TRUE(transform
.IsBackFaceVisible());
1417 // Edge case, 90 degree rotation should return false.
1418 transform
.MakeIdentity();
1419 transform
.RotateAboutYAxis(90.0);
1420 EXPECT_FALSE(transform
.IsBackFaceVisible());
1423 TEST(XFormTest
, verifyBackfaceVisibilityForPerspective
) {
1424 Transform layer_space_to_projection_plane
;
1426 // This tests if IsBackFaceVisible works properly under perspective
1427 // transforms. Specifically, layers that may have their back face visible in
1428 // orthographic projection, may not actually have back face visible under
1429 // perspective projection.
1431 // Case 1: Layer is rotated by slightly more than 90 degrees, at the center
1432 // of the prespective projection. In this case, the layer's back-side
1433 // is visible to the camera.
1434 layer_space_to_projection_plane
.MakeIdentity();
1435 layer_space_to_projection_plane
.ApplyPerspectiveDepth(1.0);
1436 layer_space_to_projection_plane
.Translate3d(0.0, 0.0, 0.0);
1437 layer_space_to_projection_plane
.RotateAboutYAxis(100.0);
1438 EXPECT_TRUE(layer_space_to_projection_plane
.IsBackFaceVisible());
1440 // Case 2: Layer is rotated by slightly more than 90 degrees, but shifted off
1441 // to the side of the camera. Because of the wide field-of-view, the
1442 // layer's front side is still visible.
1444 // |<-- front side of layer is visible to camera
1449 // |\ /<-- camera field of view
1451 // back side of layer -->| \ /
1452 // \./ <-- camera origin
1454 layer_space_to_projection_plane
.MakeIdentity();
1455 layer_space_to_projection_plane
.ApplyPerspectiveDepth(1.0);
1456 layer_space_to_projection_plane
.Translate3d(-10.0, 0.0, 0.0);
1457 layer_space_to_projection_plane
.RotateAboutYAxis(100.0);
1458 EXPECT_FALSE(layer_space_to_projection_plane
.IsBackFaceVisible());
1460 // Case 3: Additionally rotating the layer by 180 degrees should of course
1461 // show the opposite result of case 2.
1462 layer_space_to_projection_plane
.RotateAboutYAxis(180.0);
1463 EXPECT_TRUE(layer_space_to_projection_plane
.IsBackFaceVisible());
1466 TEST(XFormTest
, verifyDefaultConstructorCreatesIdentityMatrix
) {
1468 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1469 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1470 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1471 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1472 EXPECT_TRUE(A
.IsIdentity());
1475 TEST(XFormTest
, verifyCopyConstructor
) {
1477 InitializeTestMatrix(&A
);
1479 // Copy constructor should produce exact same elements as matrix A.
1481 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, B
);
1482 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, B
);
1483 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, B
);
1484 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, B
);
1487 TEST(XFormTest
, verifyConstructorFor16Elements
) {
1488 Transform
transform(1.0, 2.0, 3.0, 4.0,
1490 9.0, 10.0, 11.0, 12.0,
1491 13.0, 14.0, 15.0, 16.0);
1493 EXPECT_ROW1_EQ(1.0f
, 2.0f
, 3.0f
, 4.0f
, transform
);
1494 EXPECT_ROW2_EQ(5.0f
, 6.0f
, 7.0f
, 8.0f
, transform
);
1495 EXPECT_ROW3_EQ(9.0f
, 10.0f
, 11.0f
, 12.0f
, transform
);
1496 EXPECT_ROW4_EQ(13.0f
, 14.0f
, 15.0f
, 16.0f
, transform
);
1499 TEST(XFormTest
, verifyConstructorFor2dElements
) {
1500 Transform
transform(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
1502 EXPECT_ROW1_EQ(1.0f
, 2.0f
, 0.0f
, 5.0f
, transform
);
1503 EXPECT_ROW2_EQ(3.0f
, 4.0f
, 0.0f
, 6.0f
, transform
);
1504 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, transform
);
1505 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, transform
);
1509 TEST(XFormTest
, verifyAssignmentOperator
) {
1511 InitializeTestMatrix(&A
);
1513 InitializeTestMatrix2(&B
);
1515 InitializeTestMatrix2(&C
);
1518 // Both B and C should now have been re-assigned to the value of A.
1519 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, B
);
1520 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, B
);
1521 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, B
);
1522 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, B
);
1524 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, C
);
1525 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, C
);
1526 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, C
);
1527 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, C
);
1530 TEST(XFormTest
, verifyEqualsBooleanOperator
) {
1532 InitializeTestMatrix(&A
);
1535 InitializeTestMatrix(&B
);
1536 EXPECT_TRUE(A
== B
);
1538 // Modifying multiple elements should cause equals operator to return false.
1540 InitializeTestMatrix2(&C
);
1541 EXPECT_FALSE(A
== C
);
1543 // Modifying any one individual element should cause equals operator to
1547 D
.matrix().set(0, 0, 0.f
);
1548 EXPECT_FALSE(A
== D
);
1551 D
.matrix().set(1, 0, 0.f
);
1552 EXPECT_FALSE(A
== D
);
1555 D
.matrix().set(2, 0, 0.f
);
1556 EXPECT_FALSE(A
== D
);
1559 D
.matrix().set(3, 0, 0.f
);
1560 EXPECT_FALSE(A
== D
);
1563 D
.matrix().set(0, 1, 0.f
);
1564 EXPECT_FALSE(A
== D
);
1567 D
.matrix().set(1, 1, 0.f
);
1568 EXPECT_FALSE(A
== D
);
1571 D
.matrix().set(2, 1, 0.f
);
1572 EXPECT_FALSE(A
== D
);
1575 D
.matrix().set(3, 1, 0.f
);
1576 EXPECT_FALSE(A
== D
);
1579 D
.matrix().set(0, 2, 0.f
);
1580 EXPECT_FALSE(A
== D
);
1583 D
.matrix().set(1, 2, 0.f
);
1584 EXPECT_FALSE(A
== D
);
1587 D
.matrix().set(2, 2, 0.f
);
1588 EXPECT_FALSE(A
== D
);
1591 D
.matrix().set(3, 2, 0.f
);
1592 EXPECT_FALSE(A
== D
);
1595 D
.matrix().set(0, 3, 0.f
);
1596 EXPECT_FALSE(A
== D
);
1599 D
.matrix().set(1, 3, 0.f
);
1600 EXPECT_FALSE(A
== D
);
1603 D
.matrix().set(2, 3, 0.f
);
1604 EXPECT_FALSE(A
== D
);
1607 D
.matrix().set(3, 3, 0.f
);
1608 EXPECT_FALSE(A
== D
);
1611 TEST(XFormTest
, verifyMultiplyOperator
) {
1613 InitializeTestMatrix(&A
);
1616 InitializeTestMatrix2(&B
);
1618 Transform C
= A
* B
;
1619 EXPECT_ROW1_EQ(2036.0f
, 2292.0f
, 2548.0f
, 2804.0f
, C
);
1620 EXPECT_ROW2_EQ(2162.0f
, 2434.0f
, 2706.0f
, 2978.0f
, C
);
1621 EXPECT_ROW3_EQ(2288.0f
, 2576.0f
, 2864.0f
, 3152.0f
, C
);
1622 EXPECT_ROW4_EQ(2414.0f
, 2718.0f
, 3022.0f
, 3326.0f
, C
);
1624 // Just an additional sanity check; matrix multiplication is not commutative.
1625 EXPECT_FALSE(A
* B
== B
* A
);
1628 TEST(XFormTest
, verifyMultiplyAndAssignOperator
) {
1630 InitializeTestMatrix(&A
);
1633 InitializeTestMatrix2(&B
);
1636 EXPECT_ROW1_EQ(2036.0f
, 2292.0f
, 2548.0f
, 2804.0f
, A
);
1637 EXPECT_ROW2_EQ(2162.0f
, 2434.0f
, 2706.0f
, 2978.0f
, A
);
1638 EXPECT_ROW3_EQ(2288.0f
, 2576.0f
, 2864.0f
, 3152.0f
, A
);
1639 EXPECT_ROW4_EQ(2414.0f
, 2718.0f
, 3022.0f
, 3326.0f
, A
);
1641 // Just an additional sanity check; matrix multiplication is not commutative.
1646 EXPECT_FALSE(C
== D
);
1649 TEST(XFormTest
, verifyMatrixMultiplication
) {
1651 InitializeTestMatrix(&A
);
1654 InitializeTestMatrix2(&B
);
1656 A
.PreconcatTransform(B
);
1657 EXPECT_ROW1_EQ(2036.0f
, 2292.0f
, 2548.0f
, 2804.0f
, A
);
1658 EXPECT_ROW2_EQ(2162.0f
, 2434.0f
, 2706.0f
, 2978.0f
, A
);
1659 EXPECT_ROW3_EQ(2288.0f
, 2576.0f
, 2864.0f
, 3152.0f
, A
);
1660 EXPECT_ROW4_EQ(2414.0f
, 2718.0f
, 3022.0f
, 3326.0f
, A
);
1663 TEST(XFormTest
, verifyMakeIdentiy
) {
1665 InitializeTestMatrix(&A
);
1667 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1668 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1669 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1670 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1671 EXPECT_TRUE(A
.IsIdentity());
1674 TEST(XFormTest
, verifyTranslate
) {
1676 A
.Translate(2.0, 3.0);
1677 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 2.0f
, A
);
1678 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 3.0f
, A
);
1679 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1680 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1682 // Verify that Translate() post-multiplies the existing matrix.
1685 A
.Translate(2.0, 3.0);
1686 EXPECT_ROW1_EQ(5.0f
, 0.0f
, 0.0f
, 10.0f
, A
);
1687 EXPECT_ROW2_EQ(0.0f
, 5.0f
, 0.0f
, 15.0f
, A
);
1688 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1689 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1692 TEST(XFormTest
, verifyTranslate3d
) {
1694 A
.Translate3d(2.0, 3.0, 4.0);
1695 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 2.0f
, A
);
1696 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 3.0f
, A
);
1697 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 4.0f
, A
);
1698 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1700 // Verify that Translate3d() post-multiplies the existing matrix.
1702 A
.Scale3d(6.0, 7.0, 8.0);
1703 A
.Translate3d(2.0, 3.0, 4.0);
1704 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 12.0f
, A
);
1705 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 21.0f
, A
);
1706 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 32.0f
, A
);
1707 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1710 TEST(XFormTest
, verifyScale
) {
1713 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1714 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 0.0f
, A
);
1715 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1716 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1718 // Verify that Scale() post-multiplies the existing matrix.
1720 A
.Translate3d(2.0, 3.0, 4.0);
1722 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 2.0f
, A
);
1723 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 3.0f
, A
);
1724 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 4.0f
, A
);
1725 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1728 TEST(XFormTest
, verifyScale3d
) {
1730 A
.Scale3d(6.0, 7.0, 8.0);
1731 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1732 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 0.0f
, A
);
1733 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1734 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1736 // Verify that scale3d() post-multiplies the existing matrix.
1738 A
.Translate3d(2.0, 3.0, 4.0);
1739 A
.Scale3d(6.0, 7.0, 8.0);
1740 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 2.0f
, A
);
1741 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 3.0f
, A
);
1742 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 4.0f
, A
);
1743 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1746 TEST(XFormTest
, verifyRotate
) {
1749 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1750 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1751 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1752 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1754 // Verify that Rotate() post-multiplies the existing matrix.
1756 A
.Scale3d(6.0, 7.0, 8.0);
1758 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1759 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1760 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1761 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1764 TEST(XFormTest
, verifyRotateAboutXAxis
) {
1766 double sin45
= 0.5 * sqrt(2.0);
1767 double cos45
= sin45
;
1770 A
.RotateAboutXAxis(90.0);
1771 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1772 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A
, ERROR_THRESHOLD
);
1773 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1774 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1777 A
.RotateAboutXAxis(45.0);
1778 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1779 EXPECT_ROW2_NEAR(0.0, cos45
, -sin45
, 0.0, A
, ERROR_THRESHOLD
);
1780 EXPECT_ROW3_NEAR(0.0, sin45
, cos45
, 0.0, A
, ERROR_THRESHOLD
);
1781 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1783 // Verify that RotateAboutXAxis(angle) post-multiplies the existing matrix.
1785 A
.Scale3d(6.0, 7.0, 8.0);
1786 A
.RotateAboutXAxis(90.0);
1787 EXPECT_ROW1_NEAR(6.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1788 EXPECT_ROW2_NEAR(0.0, 0.0, -7.0, 0.0, A
, ERROR_THRESHOLD
);
1789 EXPECT_ROW3_NEAR(0.0, 8.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1790 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1793 TEST(XFormTest
, verifyRotateAboutYAxis
) {
1795 double sin45
= 0.5 * sqrt(2.0);
1796 double cos45
= sin45
;
1798 // Note carefully, the expected pattern is inverted compared to rotating
1799 // about x axis or z axis.
1801 A
.RotateAboutYAxis(90.0);
1802 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A
, ERROR_THRESHOLD
);
1803 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1804 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1805 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1808 A
.RotateAboutYAxis(45.0);
1809 EXPECT_ROW1_NEAR(cos45
, 0.0, sin45
, 0.0, A
, ERROR_THRESHOLD
);
1810 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1811 EXPECT_ROW3_NEAR(-sin45
, 0.0, cos45
, 0.0, A
, ERROR_THRESHOLD
);
1812 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1814 // Verify that RotateAboutYAxis(angle) post-multiplies the existing matrix.
1816 A
.Scale3d(6.0, 7.0, 8.0);
1817 A
.RotateAboutYAxis(90.0);
1818 EXPECT_ROW1_NEAR(0.0, 0.0, 6.0, 0.0, A
, ERROR_THRESHOLD
);
1819 EXPECT_ROW2_NEAR(0.0, 7.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1820 EXPECT_ROW3_NEAR(-8.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1821 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1824 TEST(XFormTest
, verifyRotateAboutZAxis
) {
1826 double sin45
= 0.5 * sqrt(2.0);
1827 double cos45
= sin45
;
1830 A
.RotateAboutZAxis(90.0);
1831 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1832 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1833 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1834 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1837 A
.RotateAboutZAxis(45.0);
1838 EXPECT_ROW1_NEAR(cos45
, -sin45
, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1839 EXPECT_ROW2_NEAR(sin45
, cos45
, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1840 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1841 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1843 // Verify that RotateAboutZAxis(angle) post-multiplies the existing matrix.
1845 A
.Scale3d(6.0, 7.0, 8.0);
1846 A
.RotateAboutZAxis(90.0);
1847 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1848 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1849 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1850 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1853 TEST(XFormTest
, verifyRotateAboutForAlignedAxes
) {
1856 // Check rotation about z-axis
1858 A
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1859 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1860 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1861 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1862 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1864 // Check rotation about x-axis
1866 A
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1867 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1868 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A
, ERROR_THRESHOLD
);
1869 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1870 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1872 // Check rotation about y-axis. Note carefully, the expected pattern is
1873 // inverted compared to rotating about x axis or z axis.
1875 A
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1876 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A
, ERROR_THRESHOLD
);
1877 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1878 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1879 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1881 // Verify that rotate3d(axis, angle) post-multiplies the existing matrix.
1883 A
.Scale3d(6.0, 7.0, 8.0);
1884 A
.RotateAboutZAxis(90.0);
1885 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1886 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1887 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1888 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1891 TEST(XFormTest
, verifyRotateAboutForArbitraryAxis
) {
1892 // Check rotation about an arbitrary non-axis-aligned vector.
1894 A
.RotateAbout(Vector3dF(1.0, 1.0, 1.0), 90.0);
1895 EXPECT_ROW1_NEAR(0.3333333333333334258519187,
1896 -0.2440169358562924717404030,
1897 0.9106836025229592124219380,
1898 0.0, A
, ERROR_THRESHOLD
);
1899 EXPECT_ROW2_NEAR(0.9106836025229592124219380,
1900 0.3333333333333334258519187,
1901 -0.2440169358562924717404030,
1902 0.0, A
, ERROR_THRESHOLD
);
1903 EXPECT_ROW3_NEAR(-0.2440169358562924717404030,
1904 0.9106836025229592124219380,
1905 0.3333333333333334258519187,
1906 0.0, A
, ERROR_THRESHOLD
);
1907 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1910 TEST(XFormTest
, verifyRotateAboutForDegenerateAxis
) {
1911 // Check rotation about a degenerate zero vector.
1912 // It is expected to skip applying the rotation.
1915 A
.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 45.0);
1916 // Verify that A remains unchanged.
1917 EXPECT_TRUE(A
.IsIdentity());
1919 InitializeTestMatrix(&A
);
1920 A
.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 35.0);
1922 // Verify that A remains unchanged.
1923 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, A
);
1924 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, A
);
1925 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, A
);
1926 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, A
);
1929 TEST(XFormTest
, verifySkew
) {
1930 // Test a skew along X axis only
1933 EXPECT_ROW1_EQ(1.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1934 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1935 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1936 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1938 // Test a skew along Y axis only
1941 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1942 EXPECT_ROW2_EQ(1.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1943 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1944 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1946 // Verify that skew() post-multiplies the existing matrix. Row 1, column 2,
1947 // would incorrectly have value "7" if the matrix is pre-multiplied instead
1948 // of post-multiplied.
1950 A
.Scale3d(6.0, 7.0, 8.0);
1952 EXPECT_ROW1_EQ(6.0f
, 6.0f
, 0.0f
, 0.0f
, A
);
1953 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 0.0f
, A
);
1954 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1955 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1957 // Test a skew along X and Y axes both
1960 EXPECT_ROW1_EQ(1.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1961 EXPECT_ROW2_EQ(1.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1962 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1963 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1966 TEST(XFormTest
, verifyPerspectiveDepth
) {
1968 A
.ApplyPerspectiveDepth(1.0);
1969 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1970 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1971 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1972 EXPECT_ROW4_EQ(0.0f
, 0.0f
, -1.0f
, 1.0f
, A
);
1974 // Verify that PerspectiveDepth() post-multiplies the existing matrix.
1976 A
.Translate3d(2.0, 3.0, 4.0);
1977 A
.ApplyPerspectiveDepth(1.0);
1978 EXPECT_ROW1_EQ(1.0f
, 0.0f
, -2.0f
, 2.0f
, A
);
1979 EXPECT_ROW2_EQ(0.0f
, 1.0f
, -3.0f
, 3.0f
, A
);
1980 EXPECT_ROW3_EQ(0.0f
, 0.0f
, -3.0f
, 4.0f
, A
);
1981 EXPECT_ROW4_EQ(0.0f
, 0.0f
, -1.0f
, 1.0f
, A
);
1984 TEST(XFormTest
, verifyHasPerspective
) {
1986 A
.ApplyPerspectiveDepth(1.0);
1987 EXPECT_TRUE(A
.HasPerspective());
1990 A
.ApplyPerspectiveDepth(0.0);
1991 EXPECT_FALSE(A
.HasPerspective());
1994 A
.matrix().set(3, 0, -1.f
);
1995 EXPECT_TRUE(A
.HasPerspective());
1998 A
.matrix().set(3, 1, -1.f
);
1999 EXPECT_TRUE(A
.HasPerspective());
2002 A
.matrix().set(3, 2, -0.3f
);
2003 EXPECT_TRUE(A
.HasPerspective());
2006 A
.matrix().set(3, 3, 0.5f
);
2007 EXPECT_TRUE(A
.HasPerspective());
2010 A
.matrix().set(3, 3, 0.f
);
2011 EXPECT_TRUE(A
.HasPerspective());
2014 TEST(XFormTest
, verifyIsInvertible
) {
2017 // Translations, rotations, scales, skews and arbitrary combinations of them
2020 EXPECT_TRUE(A
.IsInvertible());
2023 A
.Translate3d(2.0, 3.0, 4.0);
2024 EXPECT_TRUE(A
.IsInvertible());
2027 A
.Scale3d(6.0, 7.0, 8.0);
2028 EXPECT_TRUE(A
.IsInvertible());
2031 A
.RotateAboutXAxis(10.0);
2032 A
.RotateAboutYAxis(20.0);
2033 A
.RotateAboutZAxis(30.0);
2034 EXPECT_TRUE(A
.IsInvertible());
2038 EXPECT_TRUE(A
.IsInvertible());
2040 // A perspective matrix (projection plane at z=0) is invertible. The
2041 // intuitive explanation is that perspective is eqivalent to a skew of the
2042 // w-axis; skews are invertible.
2044 A
.ApplyPerspectiveDepth(1.0);
2045 EXPECT_TRUE(A
.IsInvertible());
2047 // A "pure" perspective matrix derived by similar triangles, with m44() set
2048 // to zero (i.e. camera positioned at the origin), is not invertible.
2050 A
.ApplyPerspectiveDepth(1.0);
2051 A
.matrix().set(3, 3, 0.f
);
2052 EXPECT_FALSE(A
.IsInvertible());
2054 // Adding more to a non-invertible matrix will not make it invertible in the
2057 A
.ApplyPerspectiveDepth(1.0);
2058 A
.matrix().set(3, 3, 0.f
);
2059 A
.Scale3d(6.0, 7.0, 8.0);
2060 A
.RotateAboutXAxis(10.0);
2061 A
.RotateAboutYAxis(20.0);
2062 A
.RotateAboutZAxis(30.0);
2063 A
.Translate3d(6.0, 7.0, 8.0);
2064 EXPECT_FALSE(A
.IsInvertible());
2066 // A degenerate matrix of all zeros is not invertible.
2068 A
.matrix().set(0, 0, 0.f
);
2069 A
.matrix().set(1, 1, 0.f
);
2070 A
.matrix().set(2, 2, 0.f
);
2071 A
.matrix().set(3, 3, 0.f
);
2072 EXPECT_FALSE(A
.IsInvertible());
2075 TEST(XFormTest
, verifyIsIdentity
) {
2078 InitializeTestMatrix(&A
);
2079 EXPECT_FALSE(A
.IsIdentity());
2082 EXPECT_TRUE(A
.IsIdentity());
2084 // Modifying any one individual element should cause the matrix to no longer
2087 A
.matrix().set(0, 0, 2.f
);
2088 EXPECT_FALSE(A
.IsIdentity());
2091 A
.matrix().set(1, 0, 2.f
);
2092 EXPECT_FALSE(A
.IsIdentity());
2095 A
.matrix().set(2, 0, 2.f
);
2096 EXPECT_FALSE(A
.IsIdentity());
2099 A
.matrix().set(3, 0, 2.f
);
2100 EXPECT_FALSE(A
.IsIdentity());
2103 A
.matrix().set(0, 1, 2.f
);
2104 EXPECT_FALSE(A
.IsIdentity());
2107 A
.matrix().set(1, 1, 2.f
);
2108 EXPECT_FALSE(A
.IsIdentity());
2111 A
.matrix().set(2, 1, 2.f
);
2112 EXPECT_FALSE(A
.IsIdentity());
2115 A
.matrix().set(3, 1, 2.f
);
2116 EXPECT_FALSE(A
.IsIdentity());
2119 A
.matrix().set(0, 2, 2.f
);
2120 EXPECT_FALSE(A
.IsIdentity());
2123 A
.matrix().set(1, 2, 2.f
);
2124 EXPECT_FALSE(A
.IsIdentity());
2127 A
.matrix().set(2, 2, 2.f
);
2128 EXPECT_FALSE(A
.IsIdentity());
2131 A
.matrix().set(3, 2, 2.f
);
2132 EXPECT_FALSE(A
.IsIdentity());
2135 A
.matrix().set(0, 3, 2.f
);
2136 EXPECT_FALSE(A
.IsIdentity());
2139 A
.matrix().set(1, 3, 2.f
);
2140 EXPECT_FALSE(A
.IsIdentity());
2143 A
.matrix().set(2, 3, 2.f
);
2144 EXPECT_FALSE(A
.IsIdentity());
2147 A
.matrix().set(3, 3, 2.f
);
2148 EXPECT_FALSE(A
.IsIdentity());
2151 TEST(XFormTest
, verifyIsIdentityOrTranslation
) {
2154 InitializeTestMatrix(&A
);
2155 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2158 EXPECT_TRUE(A
.IsIdentityOrTranslation());
2160 // Modifying any non-translation components should cause
2161 // IsIdentityOrTranslation() to return false. NOTE: (0, 3), (1, 3), and
2162 // (2, 3) are the translation components, so modifying them should still
2165 A
.matrix().set(0, 0, 2.f
);
2166 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2169 A
.matrix().set(1, 0, 2.f
);
2170 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2173 A
.matrix().set(2, 0, 2.f
);
2174 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2177 A
.matrix().set(3, 0, 2.f
);
2178 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2181 A
.matrix().set(0, 1, 2.f
);
2182 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2185 A
.matrix().set(1, 1, 2.f
);
2186 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2189 A
.matrix().set(2, 1, 2.f
);
2190 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2193 A
.matrix().set(3, 1, 2.f
);
2194 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2197 A
.matrix().set(0, 2, 2.f
);
2198 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2201 A
.matrix().set(1, 2, 2.f
);
2202 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2205 A
.matrix().set(2, 2, 2.f
);
2206 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2209 A
.matrix().set(3, 2, 2.f
);
2210 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2212 // Note carefully - expecting true here.
2214 A
.matrix().set(0, 3, 2.f
);
2215 EXPECT_TRUE(A
.IsIdentityOrTranslation());
2217 // Note carefully - expecting true here.
2219 A
.matrix().set(1, 3, 2.f
);
2220 EXPECT_TRUE(A
.IsIdentityOrTranslation());
2222 // Note carefully - expecting true here.
2224 A
.matrix().set(2, 3, 2.f
);
2225 EXPECT_TRUE(A
.IsIdentityOrTranslation());
2228 A
.matrix().set(3, 3, 2.f
);
2229 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2232 TEST(XFormTest
, verifyIsApproximatelyIdentityOrTranslation
) {
2234 SkMatrix44
& matrix
= A
.matrix();
2236 // Exact pure translation.
2239 // Set translate values to values other than 0 or 1.
2240 matrix
.set(0, 3, 3.4f
);
2241 matrix
.set(1, 3, 4.4f
);
2242 matrix
.set(2, 3, 5.6f
);
2244 EXPECT_TRUE(A
.IsApproximatelyIdentityOrTranslation(0));
2245 EXPECT_TRUE(A
.IsApproximatelyIdentityOrTranslation(kApproxZero
));
2247 // Approximately pure translation.
2248 InitializeApproxIdentityMatrix(&A
);
2250 // Some values must be exact.
2251 matrix
.set(3, 0, 0);
2252 matrix
.set(3, 1, 0);
2253 matrix
.set(3, 2, 0);
2254 matrix
.set(3, 3, 1);
2256 // Set translate values to values other than 0 or 1.
2257 matrix
.set(0, 3, 3.4f
);
2258 matrix
.set(1, 3, 4.4f
);
2259 matrix
.set(2, 3, 5.6f
);
2261 EXPECT_FALSE(A
.IsApproximatelyIdentityOrTranslation(0));
2262 EXPECT_TRUE(A
.IsApproximatelyIdentityOrTranslation(kApproxZero
));
2264 // Not approximately pure translation.
2265 InitializeApproxIdentityMatrix(&A
);
2267 // Some values must be exact.
2268 matrix
.set(3, 0, 0);
2269 matrix
.set(3, 1, 0);
2270 matrix
.set(3, 2, 0);
2271 matrix
.set(3, 3, 1);
2273 // Set some values (not translate values) to values other than 0 or 1.
2274 matrix
.set(0, 1, 3.4f
);
2275 matrix
.set(3, 2, 4.4f
);
2276 matrix
.set(2, 0, 5.6f
);
2278 EXPECT_FALSE(A
.IsApproximatelyIdentityOrTranslation(0));
2279 EXPECT_FALSE(A
.IsApproximatelyIdentityOrTranslation(kApproxZero
));
2282 TEST(XFormTest
, verifyIsScaleOrTranslation
) {
2285 InitializeTestMatrix(&A
);
2286 EXPECT_FALSE(A
.IsScaleOrTranslation());
2289 EXPECT_TRUE(A
.IsScaleOrTranslation());
2291 // Modifying any non-scale or non-translation components should cause
2292 // IsScaleOrTranslation() to return false. (0, 0), (1, 1), (2, 2), (0, 3),
2293 // (1, 3), and (2, 3) are the scale and translation components, so
2294 // modifying them should still return true.
2296 // Note carefully - expecting true here.
2298 A
.matrix().set(0, 0, 2.f
);
2299 EXPECT_TRUE(A
.IsScaleOrTranslation());
2302 A
.matrix().set(1, 0, 2.f
);
2303 EXPECT_FALSE(A
.IsScaleOrTranslation());
2306 A
.matrix().set(2, 0, 2.f
);
2307 EXPECT_FALSE(A
.IsScaleOrTranslation());
2310 A
.matrix().set(3, 0, 2.f
);
2311 EXPECT_FALSE(A
.IsScaleOrTranslation());
2314 A
.matrix().set(0, 1, 2.f
);
2315 EXPECT_FALSE(A
.IsScaleOrTranslation());
2317 // Note carefully - expecting true here.
2319 A
.matrix().set(1, 1, 2.f
);
2320 EXPECT_TRUE(A
.IsScaleOrTranslation());
2323 A
.matrix().set(2, 1, 2.f
);
2324 EXPECT_FALSE(A
.IsScaleOrTranslation());
2327 A
.matrix().set(3, 1, 2.f
);
2328 EXPECT_FALSE(A
.IsScaleOrTranslation());
2331 A
.matrix().set(0, 2, 2.f
);
2332 EXPECT_FALSE(A
.IsScaleOrTranslation());
2335 A
.matrix().set(1, 2, 2.f
);
2336 EXPECT_FALSE(A
.IsScaleOrTranslation());
2338 // Note carefully - expecting true here.
2340 A
.matrix().set(2, 2, 2.f
);
2341 EXPECT_TRUE(A
.IsScaleOrTranslation());
2344 A
.matrix().set(3, 2, 2.f
);
2345 EXPECT_FALSE(A
.IsScaleOrTranslation());
2347 // Note carefully - expecting true here.
2349 A
.matrix().set(0, 3, 2.f
);
2350 EXPECT_TRUE(A
.IsScaleOrTranslation());
2352 // Note carefully - expecting true here.
2354 A
.matrix().set(1, 3, 2.f
);
2355 EXPECT_TRUE(A
.IsScaleOrTranslation());
2357 // Note carefully - expecting true here.
2359 A
.matrix().set(2, 3, 2.f
);
2360 EXPECT_TRUE(A
.IsScaleOrTranslation());
2363 A
.matrix().set(3, 3, 2.f
);
2364 EXPECT_FALSE(A
.IsScaleOrTranslation());
2367 TEST(XFormTest
, verifyFlattenTo2d
) {
2369 InitializeTestMatrix(&A
);
2372 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 0.0f
, 22.0f
, A
);
2373 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 0.0f
, 23.0f
, A
);
2374 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
2375 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 0.0f
, 25.0f
, A
);
2378 TEST(XFormTest
, IsFlat
) {
2379 Transform transform
;
2380 InitializeTestMatrix(&transform
);
2382 // A transform with all entries non-zero isn't flat.
2383 EXPECT_FALSE(transform
.IsFlat());
2385 transform
.matrix().set(0, 2, 0.f
);
2386 transform
.matrix().set(1, 2, 0.f
);
2387 transform
.matrix().set(2, 2, 1.f
);
2388 transform
.matrix().set(3, 2, 0.f
);
2390 EXPECT_FALSE(transform
.IsFlat());
2392 transform
.matrix().set(2, 0, 0.f
);
2393 transform
.matrix().set(2, 1, 0.f
);
2394 transform
.matrix().set(2, 3, 0.f
);
2396 // Since the third column and row are both (0, 0, 1, 0), the transform is
2398 EXPECT_TRUE(transform
.IsFlat());
2401 // Another implementation of Preserves2dAxisAlignment that isn't as fast,
2402 // good for testing the faster implementation.
2403 static bool EmpiricallyPreserves2dAxisAlignment(const Transform
& transform
) {
2404 Point3F
p1(5.0f
, 5.0f
, 0.0f
);
2405 Point3F
p2(10.0f
, 5.0f
, 0.0f
);
2406 Point3F
p3(10.0f
, 20.0f
, 0.0f
);
2407 Point3F
p4(5.0f
, 20.0f
, 0.0f
);
2409 QuadF
test_quad(PointF(p1
.x(), p1
.y()),
2410 PointF(p2
.x(), p2
.y()),
2411 PointF(p3
.x(), p3
.y()),
2412 PointF(p4
.x(), p4
.y()));
2413 EXPECT_TRUE(test_quad
.IsRectilinear());
2415 transform
.TransformPoint(&p1
);
2416 transform
.TransformPoint(&p2
);
2417 transform
.TransformPoint(&p3
);
2418 transform
.TransformPoint(&p4
);
2420 QuadF
transformedQuad(PointF(p1
.x(), p1
.y()),
2421 PointF(p2
.x(), p2
.y()),
2422 PointF(p3
.x(), p3
.y()),
2423 PointF(p4
.x(), p4
.y()));
2424 return transformedQuad
.IsRectilinear();
2427 TEST(XFormTest
, Preserves2dAxisAlignment
) {
2428 static const struct TestCase
{
2429 SkMScalar a
; // row 1, column 1
2430 SkMScalar b
; // row 1, column 2
2431 SkMScalar c
; // row 2, column 1
2432 SkMScalar d
; // row 2, column 2
2436 0.f
, 4.f
, true }, // basic case
2438 3.f
, 0.f
, true }, // rotate by 90
2440 0.f
, 4.f
, true }, // degenerate x
2442 0.f
, 0.f
, true }, // degenerate y
2444 3.f
, 0.f
, true }, // degenerate x + rotate by 90
2446 0.f
, 0.f
, true }, // degenerate y + rotate by 90
2467 Transform transform
;
2468 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
2469 const TestCase
& value
= test_cases
[i
];
2470 transform
.MakeIdentity();
2471 transform
.matrix().set(0, 0, value
.a
);
2472 transform
.matrix().set(0, 1, value
.b
);
2473 transform
.matrix().set(1, 0, value
.c
);
2474 transform
.matrix().set(1, 1, value
.d
);
2476 if (value
.expected
) {
2477 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2478 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2480 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform
));
2481 EXPECT_FALSE(transform
.Preserves2dAxisAlignment());
2485 // Try the same test cases again, but this time make sure that other matrix
2486 // elements (except perspective) have entries, to test that they are ignored.
2487 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
2488 const TestCase
& value
= test_cases
[i
];
2489 transform
.MakeIdentity();
2490 transform
.matrix().set(0, 0, value
.a
);
2491 transform
.matrix().set(0, 1, value
.b
);
2492 transform
.matrix().set(1, 0, value
.c
);
2493 transform
.matrix().set(1, 1, value
.d
);
2495 transform
.matrix().set(0, 2, 1.f
);
2496 transform
.matrix().set(0, 3, 2.f
);
2497 transform
.matrix().set(1, 2, 3.f
);
2498 transform
.matrix().set(1, 3, 4.f
);
2499 transform
.matrix().set(2, 0, 5.f
);
2500 transform
.matrix().set(2, 1, 6.f
);
2501 transform
.matrix().set(2, 2, 7.f
);
2502 transform
.matrix().set(2, 3, 8.f
);
2504 if (value
.expected
) {
2505 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2506 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2508 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform
));
2509 EXPECT_FALSE(transform
.Preserves2dAxisAlignment());
2513 // Try the same test cases again, but this time add perspective which is
2514 // always assumed to not-preserve axis alignment.
2515 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
2516 const TestCase
& value
= test_cases
[i
];
2517 transform
.MakeIdentity();
2518 transform
.matrix().set(0, 0, value
.a
);
2519 transform
.matrix().set(0, 1, value
.b
);
2520 transform
.matrix().set(1, 0, value
.c
);
2521 transform
.matrix().set(1, 1, value
.d
);
2523 transform
.matrix().set(0, 2, 1.f
);
2524 transform
.matrix().set(0, 3, 2.f
);
2525 transform
.matrix().set(1, 2, 3.f
);
2526 transform
.matrix().set(1, 3, 4.f
);
2527 transform
.matrix().set(2, 0, 5.f
);
2528 transform
.matrix().set(2, 1, 6.f
);
2529 transform
.matrix().set(2, 2, 7.f
);
2530 transform
.matrix().set(2, 3, 8.f
);
2531 transform
.matrix().set(3, 0, 9.f
);
2532 transform
.matrix().set(3, 1, 10.f
);
2533 transform
.matrix().set(3, 2, 11.f
);
2534 transform
.matrix().set(3, 3, 12.f
);
2536 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform
));
2537 EXPECT_FALSE(transform
.Preserves2dAxisAlignment());
2540 // Try a few more practical situations to check precision
2541 transform
.MakeIdentity();
2542 transform
.RotateAboutZAxis(90.0);
2543 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2544 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2546 transform
.MakeIdentity();
2547 transform
.RotateAboutZAxis(180.0);
2548 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2549 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2551 transform
.MakeIdentity();
2552 transform
.RotateAboutZAxis(270.0);
2553 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2554 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2556 transform
.MakeIdentity();
2557 transform
.RotateAboutYAxis(90.0);
2558 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2559 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2561 transform
.MakeIdentity();
2562 transform
.RotateAboutXAxis(90.0);
2563 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2564 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2566 transform
.MakeIdentity();
2567 transform
.RotateAboutZAxis(90.0);
2568 transform
.RotateAboutYAxis(90.0);
2569 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2570 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2572 transform
.MakeIdentity();
2573 transform
.RotateAboutZAxis(90.0);
2574 transform
.RotateAboutXAxis(90.0);
2575 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2576 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2578 transform
.MakeIdentity();
2579 transform
.RotateAboutYAxis(90.0);
2580 transform
.RotateAboutZAxis(90.0);
2581 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2582 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2584 transform
.MakeIdentity();
2585 transform
.RotateAboutZAxis(45.0);
2586 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform
));
2587 EXPECT_FALSE(transform
.Preserves2dAxisAlignment());
2589 // 3-d case; In 2d after an orthographic projection, this case does
2590 // preserve 2d axis alignment. But in 3d, it does not preserve axis
2592 transform
.MakeIdentity();
2593 transform
.RotateAboutYAxis(45.0);
2594 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2595 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2597 transform
.MakeIdentity();
2598 transform
.RotateAboutXAxis(45.0);
2599 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2600 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2602 // Perspective cases.
2603 transform
.MakeIdentity();
2604 transform
.ApplyPerspectiveDepth(10.0);
2605 transform
.RotateAboutYAxis(45.0);
2606 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform
));
2607 EXPECT_FALSE(transform
.Preserves2dAxisAlignment());
2609 transform
.MakeIdentity();
2610 transform
.ApplyPerspectiveDepth(10.0);
2611 transform
.RotateAboutZAxis(90.0);
2612 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2613 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2616 TEST(XFormTest
, To2dTranslation
) {
2617 Vector2dF
translation(3.f
, 7.f
);
2618 Transform transform
;
2619 transform
.Translate(translation
.x(), translation
.y() + 1);
2620 EXPECT_NE(translation
.ToString(), transform
.To2dTranslation().ToString());
2621 transform
.MakeIdentity();
2622 transform
.Translate(translation
.x(), translation
.y());
2623 EXPECT_EQ(translation
.ToString(), transform
.To2dTranslation().ToString());
2626 TEST(XFormTest
, TransformRect
) {
2627 Transform translation
;
2628 translation
.Translate(3.f
, 7.f
);
2629 RectF
rect(1.f
, 2.f
, 3.f
, 4.f
);
2630 RectF
expected(4.f
, 9.f
, 3.f
, 4.f
);
2631 translation
.TransformRect(&rect
);
2632 EXPECT_EQ(expected
.ToString(), rect
.ToString());
2635 TEST(XFormTest
, TransformRectReverse
) {
2636 Transform translation
;
2637 translation
.Translate(3.f
, 7.f
);
2638 RectF
rect(1.f
, 2.f
, 3.f
, 4.f
);
2639 RectF
expected(-2.f
, -5.f
, 3.f
, 4.f
);
2640 EXPECT_TRUE(translation
.TransformRectReverse(&rect
));
2641 EXPECT_EQ(expected
.ToString(), rect
.ToString());
2644 singular
.Scale3d(0.f
, 0.f
, 0.f
);
2645 EXPECT_FALSE(singular
.TransformRectReverse(&rect
));
2648 TEST(XFormTest
, TransformBox
) {
2649 Transform translation
;
2650 translation
.Translate3d(3.f
, 7.f
, 6.f
);
2651 BoxF
box(1.f
, 2.f
, 3.f
, 4.f
, 5.f
, 6.f
);
2652 BoxF
expected(4.f
, 9.f
, 9.f
, 4.f
, 5.f
, 6.f
);
2653 translation
.TransformBox(&box
);
2654 EXPECT_EQ(expected
.ToString(), box
.ToString());
2657 TEST(XFormTest
, TransformBoxReverse
) {
2658 Transform translation
;
2659 translation
.Translate3d(3.f
, 7.f
, 6.f
);
2660 BoxF
box(1.f
, 2.f
, 3.f
, 4.f
, 5.f
, 6.f
);
2661 BoxF
expected(-2.f
, -5.f
, -3.f
, 4.f
, 5.f
, 6.f
);
2662 EXPECT_TRUE(translation
.TransformBoxReverse(&box
));
2663 EXPECT_EQ(expected
.ToString(), box
.ToString());
2666 singular
.Scale3d(0.f
, 0.f
, 0.f
);
2667 EXPECT_FALSE(singular
.TransformBoxReverse(&box
));
2670 TEST(XFormTest
, RoundTranslationComponents
) {
2671 Transform translation
;
2674 translation
.RoundTranslationComponents();
2675 EXPECT_EQ(expected
.ToString(), translation
.ToString());
2677 translation
.Translate(1.0f
, 1.0f
);
2678 expected
.Translate(1.0f
, 1.0f
);
2679 translation
.RoundTranslationComponents();
2680 EXPECT_EQ(expected
.ToString(), translation
.ToString());
2682 translation
.Translate(0.5f
, 0.4f
);
2683 expected
.Translate(1.0f
, 0.0f
);
2684 translation
.RoundTranslationComponents();
2685 EXPECT_EQ(expected
.ToString(), translation
.ToString());
2687 // Rounding should only affect 2d translation components.
2688 translation
.Translate3d(0.f
, 0.f
, 0.5f
);
2689 expected
.Translate3d(0.f
, 0.f
, 0.5f
);
2690 translation
.RoundTranslationComponents();
2691 EXPECT_EQ(expected
.ToString(), translation
.ToString());