1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // MSVC++ requires this to be set before any other includes to get M_PI.
6 #define _USE_MATH_DEFINES
8 #include "ui/gfx/transform.h"
14 #include "base/basictypes.h"
15 #include "base/logging.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "ui/gfx/box_f.h"
18 #include "ui/gfx/point.h"
19 #include "ui/gfx/point3_f.h"
20 #include "ui/gfx/quad_f.h"
21 #include "ui/gfx/transform_util.h"
22 #include "ui/gfx/vector3d_f.h"
28 #define EXPECT_ROW1_EQ(a, b, c, d, transform) \
29 EXPECT_FLOAT_EQ((a), (transform).matrix().get(0, 0)); \
30 EXPECT_FLOAT_EQ((b), (transform).matrix().get(0, 1)); \
31 EXPECT_FLOAT_EQ((c), (transform).matrix().get(0, 2)); \
32 EXPECT_FLOAT_EQ((d), (transform).matrix().get(0, 3));
34 #define EXPECT_ROW2_EQ(a, b, c, d, transform) \
35 EXPECT_FLOAT_EQ((a), (transform).matrix().get(1, 0)); \
36 EXPECT_FLOAT_EQ((b), (transform).matrix().get(1, 1)); \
37 EXPECT_FLOAT_EQ((c), (transform).matrix().get(1, 2)); \
38 EXPECT_FLOAT_EQ((d), (transform).matrix().get(1, 3));
40 #define EXPECT_ROW3_EQ(a, b, c, d, transform) \
41 EXPECT_FLOAT_EQ((a), (transform).matrix().get(2, 0)); \
42 EXPECT_FLOAT_EQ((b), (transform).matrix().get(2, 1)); \
43 EXPECT_FLOAT_EQ((c), (transform).matrix().get(2, 2)); \
44 EXPECT_FLOAT_EQ((d), (transform).matrix().get(2, 3));
46 #define EXPECT_ROW4_EQ(a, b, c, d, transform) \
47 EXPECT_FLOAT_EQ((a), (transform).matrix().get(3, 0)); \
48 EXPECT_FLOAT_EQ((b), (transform).matrix().get(3, 1)); \
49 EXPECT_FLOAT_EQ((c), (transform).matrix().get(3, 2)); \
50 EXPECT_FLOAT_EQ((d), (transform).matrix().get(3, 3)); \
52 // Checking float values for equality close to zero is not robust using
53 // EXPECT_FLOAT_EQ (see gtest documentation). So, to verify rotation matrices,
54 // we must use a looser absolute error threshold in some places.
55 #define EXPECT_ROW1_NEAR(a, b, c, d, transform, errorThreshold) \
56 EXPECT_NEAR((a), (transform).matrix().get(0, 0), (errorThreshold)); \
57 EXPECT_NEAR((b), (transform).matrix().get(0, 1), (errorThreshold)); \
58 EXPECT_NEAR((c), (transform).matrix().get(0, 2), (errorThreshold)); \
59 EXPECT_NEAR((d), (transform).matrix().get(0, 3), (errorThreshold));
61 #define EXPECT_ROW2_NEAR(a, b, c, d, transform, errorThreshold) \
62 EXPECT_NEAR((a), (transform).matrix().get(1, 0), (errorThreshold)); \
63 EXPECT_NEAR((b), (transform).matrix().get(1, 1), (errorThreshold)); \
64 EXPECT_NEAR((c), (transform).matrix().get(1, 2), (errorThreshold)); \
65 EXPECT_NEAR((d), (transform).matrix().get(1, 3), (errorThreshold));
67 #define EXPECT_ROW3_NEAR(a, b, c, d, transform, errorThreshold) \
68 EXPECT_NEAR((a), (transform).matrix().get(2, 0), (errorThreshold)); \
69 EXPECT_NEAR((b), (transform).matrix().get(2, 1), (errorThreshold)); \
70 EXPECT_NEAR((c), (transform).matrix().get(2, 2), (errorThreshold)); \
71 EXPECT_NEAR((d), (transform).matrix().get(2, 3), (errorThreshold));
73 bool PointsAreNearlyEqual(const Point3F
& lhs
,
75 float epsilon
= 0.0001f
;
76 return lhs
.SquaredDistanceTo(rhs
) < epsilon
;
79 bool MatricesAreNearlyEqual(const Transform
& lhs
,
80 const Transform
& rhs
) {
81 float epsilon
= 0.0001f
;
82 for (int row
= 0; row
< 4; ++row
) {
83 for (int col
= 0; col
< 4; ++col
) {
84 if (std::abs(lhs
.matrix().get(row
, col
) -
85 rhs
.matrix().get(row
, col
)) > epsilon
)
92 void InitializeTestMatrix(Transform
* transform
) {
93 SkMatrix44
& matrix
= transform
->matrix();
94 matrix
.set(0, 0, 10.f
);
95 matrix
.set(1, 0, 11.f
);
96 matrix
.set(2, 0, 12.f
);
97 matrix
.set(3, 0, 13.f
);
98 matrix
.set(0, 1, 14.f
);
99 matrix
.set(1, 1, 15.f
);
100 matrix
.set(2, 1, 16.f
);
101 matrix
.set(3, 1, 17.f
);
102 matrix
.set(0, 2, 18.f
);
103 matrix
.set(1, 2, 19.f
);
104 matrix
.set(2, 2, 20.f
);
105 matrix
.set(3, 2, 21.f
);
106 matrix
.set(0, 3, 22.f
);
107 matrix
.set(1, 3, 23.f
);
108 matrix
.set(2, 3, 24.f
);
109 matrix
.set(3, 3, 25.f
);
112 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, (*transform
));
113 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, (*transform
));
114 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, (*transform
));
115 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, (*transform
));
118 void InitializeTestMatrix2(Transform
* transform
) {
119 SkMatrix44
& matrix
= transform
->matrix();
120 matrix
.set(0, 0, 30.f
);
121 matrix
.set(1, 0, 31.f
);
122 matrix
.set(2, 0, 32.f
);
123 matrix
.set(3, 0, 33.f
);
124 matrix
.set(0, 1, 34.f
);
125 matrix
.set(1, 1, 35.f
);
126 matrix
.set(2, 1, 36.f
);
127 matrix
.set(3, 1, 37.f
);
128 matrix
.set(0, 2, 38.f
);
129 matrix
.set(1, 2, 39.f
);
130 matrix
.set(2, 2, 40.f
);
131 matrix
.set(3, 2, 41.f
);
132 matrix
.set(0, 3, 42.f
);
133 matrix
.set(1, 3, 43.f
);
134 matrix
.set(2, 3, 44.f
);
135 matrix
.set(3, 3, 45.f
);
138 EXPECT_ROW1_EQ(30.0f
, 34.0f
, 38.0f
, 42.0f
, (*transform
));
139 EXPECT_ROW2_EQ(31.0f
, 35.0f
, 39.0f
, 43.0f
, (*transform
));
140 EXPECT_ROW3_EQ(32.0f
, 36.0f
, 40.0f
, 44.0f
, (*transform
));
141 EXPECT_ROW4_EQ(33.0f
, 37.0f
, 41.0f
, 45.0f
, (*transform
));
144 const SkMScalar kApproxZero
=
145 SkFloatToMScalar(std::numeric_limits
<float>::epsilon());
146 const SkMScalar kApproxOne
= 1 - kApproxZero
;
148 void InitializeApproxIdentityMatrix(Transform
* transform
) {
149 SkMatrix44
& matrix
= transform
->matrix();
150 matrix
.set(0, 0, kApproxOne
);
151 matrix
.set(0, 1, kApproxZero
);
152 matrix
.set(0, 2, kApproxZero
);
153 matrix
.set(0, 3, kApproxZero
);
155 matrix
.set(1, 0, kApproxZero
);
156 matrix
.set(1, 1, kApproxOne
);
157 matrix
.set(1, 2, kApproxZero
);
158 matrix
.set(1, 3, kApproxZero
);
160 matrix
.set(2, 0, kApproxZero
);
161 matrix
.set(2, 1, kApproxZero
);
162 matrix
.set(2, 2, kApproxOne
);
163 matrix
.set(2, 3, kApproxZero
);
165 matrix
.set(3, 0, kApproxZero
);
166 matrix
.set(3, 1, kApproxZero
);
167 matrix
.set(3, 2, kApproxZero
);
168 matrix
.set(3, 3, kApproxOne
);
171 #ifdef SK_MSCALAR_IS_DOUBLE
172 #define ERROR_THRESHOLD 1e-14
174 #define ERROR_THRESHOLD 1e-7
176 #define LOOSE_ERROR_THRESHOLD 1e-7
178 TEST(XFormTest
, Equality
) {
179 Transform lhs
, rhs
, interpolated
;
180 rhs
.matrix().set3x3(1, 2, 3,
184 for (int i
= 0; i
<= 100; ++i
) {
185 for (int row
= 0; row
< 4; ++row
) {
186 for (int col
= 0; col
< 4; ++col
) {
187 float a
= lhs
.matrix().get(row
, col
);
188 float b
= rhs
.matrix().get(row
, col
);
189 float t
= i
/ 100.0f
;
190 interpolated
.matrix().set(row
, col
, a
+ (b
- a
) * t
);
194 EXPECT_TRUE(rhs
== interpolated
);
196 EXPECT_TRUE(rhs
!= interpolated
);
201 for (int i
= 1; i
< 100; ++i
) {
205 rhs
.Translate(-i
, -i
);
206 EXPECT_TRUE(lhs
!= rhs
);
207 rhs
.Translate(2*i
, 2*i
);
208 EXPECT_TRUE(lhs
== rhs
);
212 TEST(XFormTest
, ConcatTranslate
) {
213 static const struct TestCase
{
221 { 0, 0, 10.0f
, 20.0f
, 10, 20 },
222 { 0, 0, -10.0f
, -20.0f
, 0, 0 },
223 { 0, 0, -10.0f
, -20.0f
, -10, -20 },
225 std::numeric_limits
<float>::quiet_NaN(),
226 std::numeric_limits
<float>::quiet_NaN(),
231 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
232 const TestCase
& value
= test_cases
[i
];
233 Transform translation
;
234 translation
.Translate(value
.tx
, value
.ty
);
235 xform
= translation
* xform
;
236 Point3F
p1(value
.x1
, value
.y1
, 0);
237 Point3F
p2(value
.x2
, value
.y2
, 0);
238 xform
.TransformPoint(&p1
);
239 if (value
.tx
== value
.tx
&&
240 value
.ty
== value
.ty
) {
241 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p2
));
246 TEST(XFormTest
, ConcatScale
) {
247 static const struct TestCase
{
256 { 1, std::numeric_limits
<float>::quiet_NaN(), 1 }
260 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
261 const TestCase
& value
= test_cases
[i
];
263 scale
.Scale(value
.scale
, value
.scale
);
264 xform
= scale
* xform
;
265 Point3F
p1(value
.before
, value
.before
, 0);
266 Point3F
p2(value
.after
, value
.after
, 0);
267 xform
.TransformPoint(&p1
);
268 if (value
.scale
== value
.scale
) {
269 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p2
));
274 TEST(XFormTest
, ConcatRotate
) {
275 static const struct TestCase
{
282 { 1, 0, 90.0f
, 0, 1 },
283 { 1, 0, -90.0f
, 1, 0 },
284 { 1, 0, 90.0f
, 0, 1 },
285 { 1, 0, 360.0f
, 0, 1 },
286 { 1, 0, 0.0f
, 0, 1 },
287 { 1, 0, std::numeric_limits
<float>::quiet_NaN(), 1, 0 }
291 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
292 const TestCase
& value
= test_cases
[i
];
294 rotation
.Rotate(value
.degrees
);
295 xform
= rotation
* xform
;
296 Point3F
p1(value
.x1
, value
.y1
, 0);
297 Point3F
p2(value
.x2
, value
.y2
, 0);
298 xform
.TransformPoint(&p1
);
299 if (value
.degrees
== value
.degrees
) {
300 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p2
));
305 TEST(XFormTest
, SetTranslate
) {
306 static const struct TestCase
{
311 { 0, 0, 10.0f
, 20.0f
, 10, 20 },
312 { 10, 20, 10.0f
, 20.0f
, 20, 40 },
313 { 10, 20, 0.0f
, 0.0f
, 10, 20 },
315 std::numeric_limits
<float>::quiet_NaN(),
316 std::numeric_limits
<float>::quiet_NaN(),
320 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
321 const TestCase
& value
= test_cases
[i
];
322 for (int k
= 0; k
< 3; ++k
) {
327 p1
.SetPoint(value
.x1
, 0, 0);
328 p2
.SetPoint(value
.x2
, 0, 0);
329 xform
.Translate(value
.tx
, 0.0);
332 p1
.SetPoint(0, value
.y1
, 0);
333 p2
.SetPoint(0, value
.y2
, 0);
334 xform
.Translate(0.0, value
.ty
);
337 p1
.SetPoint(value
.x1
, value
.y1
, 0);
338 p2
.SetPoint(value
.x2
, value
.y2
, 0);
339 xform
.Translate(value
.tx
, value
.ty
);
343 xform
.TransformPoint(&p1
);
344 if (value
.tx
== value
.tx
&&
345 value
.ty
== value
.ty
) {
346 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p2
));
347 xform
.TransformPointReverse(&p1
);
348 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p0
));
354 TEST(XFormTest
, SetScale
) {
355 static const struct TestCase
{
364 { 1, std::numeric_limits
<float>::quiet_NaN(), 0 },
367 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
368 const TestCase
& value
= test_cases
[i
];
369 for (int k
= 0; k
< 3; ++k
) {
374 p1
.SetPoint(value
.before
, 0, 0);
375 p2
.SetPoint(value
.after
, 0, 0);
376 xform
.Scale(value
.s
, 1.0);
379 p1
.SetPoint(0, value
.before
, 0);
380 p2
.SetPoint(0, value
.after
, 0);
381 xform
.Scale(1.0, value
.s
);
384 p1
.SetPoint(value
.before
, value
.before
, 0);
385 p2
.SetPoint(value
.after
, value
.after
, 0);
386 xform
.Scale(value
.s
, value
.s
);
390 xform
.TransformPoint(&p1
);
391 if (value
.s
== value
.s
) {
392 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p2
));
393 if (value
.s
!= 0.0f
) {
394 xform
.TransformPointReverse(&p1
);
395 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p0
));
402 TEST(XFormTest
, SetRotate
) {
403 static const struct SetRotateCase
{
409 } set_rotate_cases
[] = {
410 { 100, 0, 90.0f
, 0, 100 },
411 { 0, 0, 90.0f
, 0, 0 },
412 { 0, 100, 90.0f
, -100, 0 },
413 { 0, 1, -90.0f
, 1, 0 },
414 { 100, 0, 0.0f
, 100, 0 },
415 { 0, 0, 0.0f
, 0, 0 },
416 { 0, 0, std::numeric_limits
<float>::quiet_NaN(), 0, 0 },
417 { 100, 0, 360.0f
, 100, 0 }
420 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(set_rotate_cases
); ++i
) {
421 const SetRotateCase
& value
= set_rotate_cases
[i
];
423 Point3F
p1(value
.x
, value
.y
, 0);
424 Point3F
p2(value
.xprime
, value
.yprime
, 0);
427 xform
.Rotate(value
.degree
);
428 // just want to make sure that we don't crash in the case of NaN.
429 if (value
.degree
== value
.degree
) {
430 xform
.TransformPoint(&p1
);
431 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p2
));
432 xform
.TransformPointReverse(&p1
);
433 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p0
));
439 TEST(XFormTest
, ConcatTranslate2D
) {
440 static const struct TestCase
{
448 { 0, 0, 10.0f
, 20.0f
, 10, 20},
449 { 0, 0, -10.0f
, -20.0f
, 0, 0},
450 { 0, 0, -10.0f
, -20.0f
, -10, -20},
452 std::numeric_limits
<float>::quiet_NaN(),
453 std::numeric_limits
<float>::quiet_NaN(),
458 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
459 const TestCase
& value
= test_cases
[i
];
460 Transform translation
;
461 translation
.Translate(value
.tx
, value
.ty
);
462 xform
= translation
* xform
;
463 Point
p1(value
.x1
, value
.y1
);
464 Point
p2(value
.x2
, value
.y2
);
465 xform
.TransformPoint(&p1
);
466 if (value
.tx
== value
.tx
&&
467 value
.ty
== value
.ty
) {
468 EXPECT_EQ(p1
.x(), p2
.x());
469 EXPECT_EQ(p1
.y(), p2
.y());
474 TEST(XFormTest
, ConcatScale2D
) {
475 static const struct TestCase
{
484 { 1, std::numeric_limits
<float>::quiet_NaN(), 1}
488 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
489 const TestCase
& value
= test_cases
[i
];
491 scale
.Scale(value
.scale
, value
.scale
);
492 xform
= scale
* xform
;
493 Point
p1(value
.before
, value
.before
);
494 Point
p2(value
.after
, value
.after
);
495 xform
.TransformPoint(&p1
);
496 if (value
.scale
== value
.scale
) {
497 EXPECT_EQ(p1
.x(), p2
.x());
498 EXPECT_EQ(p1
.y(), p2
.y());
503 TEST(XFormTest
, ConcatRotate2D
) {
504 static const struct TestCase
{
511 { 1, 0, 90.0f
, 0, 1},
512 { 1, 0, -90.0f
, 1, 0},
513 { 1, 0, 90.0f
, 0, 1},
514 { 1, 0, 360.0f
, 0, 1},
516 { 1, 0, std::numeric_limits
<float>::quiet_NaN(), 1, 0}
520 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
521 const TestCase
& value
= test_cases
[i
];
523 rotation
.Rotate(value
.degrees
);
524 xform
= rotation
* xform
;
525 Point
p1(value
.x1
, value
.y1
);
526 Point
p2(value
.x2
, value
.y2
);
527 xform
.TransformPoint(&p1
);
528 if (value
.degrees
== value
.degrees
) {
529 EXPECT_EQ(p1
.x(), p2
.x());
530 EXPECT_EQ(p1
.y(), p2
.y());
535 TEST(XFormTest
, SetTranslate2D
) {
536 static const struct TestCase
{
541 { 0, 0, 10.0f
, 20.0f
, 10, 20},
542 { 10, 20, 10.0f
, 20.0f
, 20, 40},
543 { 10, 20, 0.0f
, 0.0f
, 10, 20},
545 std::numeric_limits
<float>::quiet_NaN(),
546 std::numeric_limits
<float>::quiet_NaN(),
550 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
551 const TestCase
& value
= test_cases
[i
];
552 for (int j
= -1; j
< 2; ++j
) {
553 for (int k
= 0; k
< 3; ++k
) {
554 float epsilon
= 0.0001f
;
559 p1
.SetPoint(value
.x1
, 0);
560 p2
.SetPoint(value
.x2
, 0);
561 xform
.Translate(value
.tx
+ j
* epsilon
, 0.0);
564 p1
.SetPoint(0, value
.y1
);
565 p2
.SetPoint(0, value
.y2
);
566 xform
.Translate(0.0, value
.ty
+ j
* epsilon
);
569 p1
.SetPoint(value
.x1
, value
.y1
);
570 p2
.SetPoint(value
.x2
, value
.y2
);
571 xform
.Translate(value
.tx
+ j
* epsilon
,
572 value
.ty
+ j
* epsilon
);
576 xform
.TransformPoint(&p1
);
577 if (value
.tx
== value
.tx
&&
578 value
.ty
== value
.ty
) {
579 EXPECT_EQ(p1
.x(), p2
.x());
580 EXPECT_EQ(p1
.y(), p2
.y());
581 xform
.TransformPointReverse(&p1
);
582 EXPECT_EQ(p1
.x(), p0
.x());
583 EXPECT_EQ(p1
.y(), p0
.y());
590 TEST(XFormTest
, SetScale2D
) {
591 static const struct TestCase
{
600 { 1, std::numeric_limits
<float>::quiet_NaN(), 0},
603 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
604 const TestCase
& value
= test_cases
[i
];
605 for (int j
= -1; j
< 2; ++j
) {
606 for (int k
= 0; k
< 3; ++k
) {
607 float epsilon
= 0.0001f
;
612 p1
.SetPoint(value
.before
, 0);
613 p2
.SetPoint(value
.after
, 0);
614 xform
.Scale(value
.s
+ j
* epsilon
, 1.0);
617 p1
.SetPoint(0, value
.before
);
618 p2
.SetPoint(0, value
.after
);
619 xform
.Scale(1.0, value
.s
+ j
* epsilon
);
622 p1
.SetPoint(value
.before
,
624 p2
.SetPoint(value
.after
,
626 xform
.Scale(value
.s
+ j
* epsilon
,
627 value
.s
+ j
* epsilon
);
631 xform
.TransformPoint(&p1
);
632 if (value
.s
== value
.s
) {
633 EXPECT_EQ(p1
.x(), p2
.x());
634 EXPECT_EQ(p1
.y(), p2
.y());
635 if (value
.s
!= 0.0f
) {
636 xform
.TransformPointReverse(&p1
);
637 EXPECT_EQ(p1
.x(), p0
.x());
638 EXPECT_EQ(p1
.y(), p0
.y());
646 TEST(XFormTest
, SetRotate2D
) {
647 static const struct SetRotateCase
{
653 } set_rotate_cases
[] = {
654 { 100, 0, 90.0f
, 0, 100},
655 { 0, 0, 90.0f
, 0, 0},
656 { 0, 100, 90.0f
, -100, 0},
657 { 0, 1, -90.0f
, 1, 0},
658 { 100, 0, 0.0f
, 100, 0},
660 { 0, 0, std::numeric_limits
<float>::quiet_NaN(), 0, 0},
661 { 100, 0, 360.0f
, 100, 0}
664 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(set_rotate_cases
); ++i
) {
665 const SetRotateCase
& value
= set_rotate_cases
[i
];
666 for (int j
= 1; j
>= -1; --j
) {
667 float epsilon
= 0.1f
;
668 Point
pt(value
.x
, value
.y
);
670 // should be invariant to small floating point errors.
671 xform
.Rotate(value
.degree
+ j
* epsilon
);
672 // just want to make sure that we don't crash in the case of NaN.
673 if (value
.degree
== value
.degree
) {
674 xform
.TransformPoint(&pt
);
675 EXPECT_EQ(value
.xprime
, pt
.x());
676 EXPECT_EQ(value
.yprime
, pt
.y());
677 xform
.TransformPointReverse(&pt
);
678 EXPECT_EQ(pt
.x(), value
.x
);
679 EXPECT_EQ(pt
.y(), value
.y
);
685 TEST(XFormTest
, TransformPointWithExtremePerspective
) {
686 Point3F
point(1.f
, 1.f
, 1.f
);
687 Transform perspective
;
688 perspective
.ApplyPerspectiveDepth(1.f
);
689 Point3F transformed
= point
;
690 perspective
.TransformPoint(&transformed
);
691 EXPECT_EQ(point
.ToString(), transformed
.ToString());
694 perspective
.MakeIdentity();
695 perspective
.ApplyPerspectiveDepth(1.1f
);
696 perspective
.TransformPoint(&transformed
);
697 EXPECT_FLOAT_EQ(11.f
, transformed
.x());
698 EXPECT_FLOAT_EQ(11.f
, transformed
.y());
699 EXPECT_FLOAT_EQ(11.f
, transformed
.z());
702 TEST(XFormTest
, BlendTranslate
) {
704 for (int i
= -5; i
< 15; ++i
) {
706 to
.Translate3d(1, 1, 1);
708 EXPECT_TRUE(to
.Blend(from
, t
));
709 EXPECT_FLOAT_EQ(t
, to
.matrix().get(0, 3));
710 EXPECT_FLOAT_EQ(t
, to
.matrix().get(1, 3));
711 EXPECT_FLOAT_EQ(t
, to
.matrix().get(2, 3));
715 TEST(XFormTest
, BlendRotate
) {
723 for (size_t index
= 0; index
< ARRAYSIZE_UNSAFE(axes
); ++index
) {
724 for (int i
= -5; i
< 15; ++i
) {
726 to
.RotateAbout(axes
[index
], 90);
728 EXPECT_TRUE(to
.Blend(from
, t
));
731 expected
.RotateAbout(axes
[index
], 90 * t
);
733 EXPECT_TRUE(MatricesAreNearlyEqual(expected
, to
));
738 TEST(XFormTest
, BlendRotateFollowsShortestPath
) {
739 // Verify that we interpolate along the shortest path regardless of whether
740 // this path crosses the 180-degree point.
747 for (size_t index
= 0; index
< ARRAYSIZE_UNSAFE(axes
); ++index
) {
748 for (int i
= -5; i
< 15; ++i
) {
750 from1
.RotateAbout(axes
[index
], 130.0);
752 to1
.RotateAbout(axes
[index
], 175.0);
755 from2
.RotateAbout(axes
[index
], 140.0);
757 to2
.RotateAbout(axes
[index
], 185.0);
760 EXPECT_TRUE(to1
.Blend(from1
, t
));
761 EXPECT_TRUE(to2
.Blend(from2
, t
));
764 expected1
.RotateAbout(axes
[index
], 130.0 + 45.0 * t
);
767 expected2
.RotateAbout(axes
[index
], 140.0 + 45.0 * t
);
769 EXPECT_TRUE(MatricesAreNearlyEqual(expected1
, to1
));
770 EXPECT_TRUE(MatricesAreNearlyEqual(expected2
, to2
));
775 TEST(XFormTest
, CanBlend180DegreeRotation
) {
783 for (size_t index
= 0; index
< ARRAYSIZE_UNSAFE(axes
); ++index
) {
784 for (int i
= -5; i
< 15; ++i
) {
786 to
.RotateAbout(axes
[index
], 180.0);
788 EXPECT_TRUE(to
.Blend(from
, t
));
790 // A 180 degree rotation is exactly opposite on the sphere, therefore
791 // either great circle arc to it is equivalent (and numerical precision
792 // will determine which is closer). Test both directions.
794 expected1
.RotateAbout(axes
[index
], 180.0 * t
);
796 expected2
.RotateAbout(axes
[index
], -180.0 * t
);
798 EXPECT_TRUE(MatricesAreNearlyEqual(expected1
, to
) ||
799 MatricesAreNearlyEqual(expected2
, to
))
800 << "axis: " << index
<< ", i: " << i
;
805 TEST(XFormTest
, BlendScale
) {
807 for (int i
= -5; i
< 15; ++i
) {
811 EXPECT_TRUE(to
.Blend(from
, t
));
812 EXPECT_FLOAT_EQ(t
* 4 + 1, to
.matrix().get(0, 0)) << "i: " << i
;
813 EXPECT_FLOAT_EQ(t
* 3 + 1, to
.matrix().get(1, 1)) << "i: " << i
;
814 EXPECT_FLOAT_EQ(t
* 2 + 1, to
.matrix().get(2, 2)) << "i: " << i
;
818 TEST(XFormTest
, BlendSkew
) {
820 for (int i
= 0; i
< 2; ++i
) {
826 expected
.SkewX(t
* 10);
827 expected
.SkewY(t
* 5);
828 EXPECT_TRUE(to
.Blend(from
, t
));
829 EXPECT_TRUE(MatricesAreNearlyEqual(expected
, to
));
833 TEST(XFormTest
, ExtrapolateSkew
) {
835 for (int i
= -1; i
< 2; ++i
) {
840 expected
.SkewX(t
* 20);
841 EXPECT_TRUE(to
.Blend(from
, t
));
842 EXPECT_TRUE(MatricesAreNearlyEqual(expected
, to
));
846 TEST(XFormTest
, BlendPerspective
) {
848 from
.ApplyPerspectiveDepth(200);
849 for (int i
= -1; i
< 3; ++i
) {
851 to
.ApplyPerspectiveDepth(800);
853 double depth
= 1.0 / ((1.0 / 200) * (1.0 - t
) + (1.0 / 800) * t
);
855 expected
.ApplyPerspectiveDepth(depth
);
856 EXPECT_TRUE(to
.Blend(from
, t
));
857 EXPECT_TRUE(MatricesAreNearlyEqual(expected
, to
));
861 TEST(XFormTest
, BlendIdentity
) {
864 EXPECT_TRUE(to
.Blend(from
, 0.5));
868 TEST(XFormTest
, CannotBlendSingularMatrix
) {
871 to
.matrix().set(1, 1, SkDoubleToMScalar(0));
872 EXPECT_FALSE(to
.Blend(from
, 0.5));
875 TEST(XFormTest
, VerifyBlendForTranslation
) {
877 from
.Translate3d(100.0, 200.0, 100.0);
881 to
.Translate3d(200.0, 100.0, 300.0);
886 to
.Translate3d(200.0, 100.0, 300.0);
887 to
.Blend(from
, 0.25);
888 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 125.0f
, to
);
889 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 175.0f
, to
);
890 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 150.0f
, to
);
891 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
894 to
.Translate3d(200.0, 100.0, 300.0);
896 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 150.0f
, to
);
897 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 150.0f
, to
);
898 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 200.0f
, to
);
899 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
902 to
.Translate3d(200.0, 100.0, 300.0);
904 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 200.0f
, to
);
905 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 100.0f
, to
);
906 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 300.0f
, to
);
907 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
910 TEST(XFormTest
, VerifyBlendForScale
) {
912 from
.Scale3d(100.0, 200.0, 100.0);
916 to
.Scale3d(200.0, 100.0, 300.0);
921 to
.Scale3d(200.0, 100.0, 300.0);
922 to
.Blend(from
, 0.25);
923 EXPECT_ROW1_EQ(125.0f
, 0.0f
, 0.0f
, 0.0f
, to
);
924 EXPECT_ROW2_EQ(0.0f
, 175.0f
, 0.0f
, 0.0f
, to
);
925 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 150.0f
, 0.0f
, to
);
926 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
929 to
.Scale3d(200.0, 100.0, 300.0);
931 EXPECT_ROW1_EQ(150.0f
, 0.0f
, 0.0f
, 0.0f
, to
);
932 EXPECT_ROW2_EQ(0.0f
, 150.0f
, 0.0f
, 0.0f
, to
);
933 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 200.0f
, 0.0f
, to
);
934 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
937 to
.Scale3d(200.0, 100.0, 300.0);
939 EXPECT_ROW1_EQ(200.0f
, 0.0f
, 0.0f
, 0.0f
, to
);
940 EXPECT_ROW2_EQ(0.0f
, 100.0f
, 0.0f
, 0.0f
, to
);
941 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 300.0f
, 0.0f
, to
);
942 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
945 TEST(XFormTest
, VerifyBlendForSkewX
) {
958 EXPECT_ROW1_EQ(1.0f
, 0.5f
, 0.0f
, 0.0f
, to
);
959 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, to
);
960 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
961 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
965 to
.Blend(from
, 0.25);
966 EXPECT_ROW1_EQ(1.0f
, 0.25f
, 0.0f
, 0.0f
, to
);
967 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, to
);
968 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
969 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
974 EXPECT_ROW1_EQ(1.0f
, 1.0f
, 0.0f
, 0.0f
, to
);
975 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, to
);
976 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
977 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
980 TEST(XFormTest
, VerifyBlendForSkewY
) {
981 // NOTE CAREFULLY: Decomposition of skew and rotation terms of the matrix
982 // is inherently underconstrained, and so it does not always compute the
983 // originally intended skew parameters. The current implementation uses QR
984 // decomposition, which decomposes the shear into a rotation + non-uniform
987 // It is unlikely that the decomposition implementation will need to change
988 // very often, so to get any test coverage, the compromise is to verify the
989 // exact matrix that the.Blend() operation produces.
991 // This problem also potentially exists for skewX, but the current QR
992 // decomposition implementation just happens to decompose those test
993 // matrices intuitively.
995 // Unfortunately, this case suffers from uncomfortably large precision
1004 to
.Blend(from
, 0.0);
1005 EXPECT_EQ(from
, to
);
1009 to
.Blend(from
, 0.25);
1010 EXPECT_ROW1_NEAR(1.0823489449280947471976333,
1011 0.0464370719145053845178239,
1015 LOOSE_ERROR_THRESHOLD
);
1016 EXPECT_ROW2_NEAR(0.2152925909665224513123150,
1017 0.9541702441750861130032035,
1021 LOOSE_ERROR_THRESHOLD
);
1022 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
1023 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1027 to
.Blend(from
, 0.5);
1028 EXPECT_ROW1_NEAR(1.1152212925809066312865525,
1029 0.0676495144007326631996335,
1033 LOOSE_ERROR_THRESHOLD
);
1034 EXPECT_ROW2_NEAR(0.4619397844342648662419037,
1035 0.9519009045724774464858342,
1039 LOOSE_ERROR_THRESHOLD
);
1040 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
1041 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1045 to
.Blend(from
, 1.0);
1046 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to
, LOOSE_ERROR_THRESHOLD
);
1047 EXPECT_ROW2_NEAR(1.0, 1.0, 0.0, 0.0, to
, LOOSE_ERROR_THRESHOLD
);
1048 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
1049 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1052 TEST(XFormTest
, VerifyBlendForRotationAboutX
) {
1053 // Even though.Blending uses quaternions, axis-aligned rotations should.
1054 // Blend the same with quaternions or Euler angles. So we can test
1055 // rotation.Blending by comparing against manually specified matrices from
1059 from
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 0.0);
1063 to
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1064 to
.Blend(from
, 0.0);
1065 EXPECT_EQ(from
, to
);
1067 double expectedRotationAngle
= 22.5 * M_PI
/ 180.0;
1069 to
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1070 to
.Blend(from
, 0.25);
1071 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1072 EXPECT_ROW2_NEAR(0.0,
1073 std::cos(expectedRotationAngle
),
1074 -std::sin(expectedRotationAngle
),
1078 EXPECT_ROW3_NEAR(0.0,
1079 std::sin(expectedRotationAngle
),
1080 std::cos(expectedRotationAngle
),
1084 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1086 expectedRotationAngle
= 45.0 * M_PI
/ 180.0;
1088 to
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1089 to
.Blend(from
, 0.5);
1090 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1091 EXPECT_ROW2_NEAR(0.0,
1092 std::cos(expectedRotationAngle
),
1093 -std::sin(expectedRotationAngle
),
1097 EXPECT_ROW3_NEAR(0.0,
1098 std::sin(expectedRotationAngle
),
1099 std::cos(expectedRotationAngle
),
1103 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1106 to
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1107 to
.Blend(from
, 1.0);
1108 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1109 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, to
, ERROR_THRESHOLD
);
1110 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1111 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1114 TEST(XFormTest
, VerifyBlendForRotationAboutY
) {
1116 from
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 0.0);
1120 to
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1121 to
.Blend(from
, 0.0);
1122 EXPECT_EQ(from
, to
);
1124 double expectedRotationAngle
= 22.5 * M_PI
/ 180.0;
1126 to
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1127 to
.Blend(from
, 0.25);
1128 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle
),
1130 std::sin(expectedRotationAngle
),
1134 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1135 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle
),
1137 std::cos(expectedRotationAngle
),
1141 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1143 expectedRotationAngle
= 45.0 * M_PI
/ 180.0;
1145 to
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1146 to
.Blend(from
, 0.5);
1147 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle
),
1149 std::sin(expectedRotationAngle
),
1153 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1154 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle
),
1156 std::cos(expectedRotationAngle
),
1160 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1163 to
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1164 to
.Blend(from
, 1.0);
1165 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, to
, ERROR_THRESHOLD
);
1166 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1167 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1168 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1171 TEST(XFormTest
, VerifyBlendForRotationAboutZ
) {
1173 from
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 0.0);
1177 to
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1178 to
.Blend(from
, 0.0);
1179 EXPECT_EQ(from
, to
);
1181 double expectedRotationAngle
= 22.5 * M_PI
/ 180.0;
1183 to
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1184 to
.Blend(from
, 0.25);
1185 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle
),
1186 -std::sin(expectedRotationAngle
),
1191 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle
),
1192 std::cos(expectedRotationAngle
),
1197 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to
, ERROR_THRESHOLD
);
1198 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1200 expectedRotationAngle
= 45.0 * M_PI
/ 180.0;
1202 to
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1203 to
.Blend(from
, 0.5);
1204 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle
),
1205 -std::sin(expectedRotationAngle
),
1210 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle
),
1211 std::cos(expectedRotationAngle
),
1216 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to
, ERROR_THRESHOLD
);
1217 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1220 to
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1221 to
.Blend(from
, 1.0);
1222 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1223 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1224 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to
, ERROR_THRESHOLD
);
1225 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1228 TEST(XFormTest
, VerifyBlendForCompositeTransform
) {
1229 // Verify that the.Blending was done with a decomposition in correct order
1230 // by blending a composite transform. Using matrix x vector notation
1231 // (Ax = b, where x is column vector), the ordering should be:
1232 // perspective * translation * rotation * skew * scale
1234 // It is not as important (or meaningful) to check intermediate
1235 // interpolations; order of operations will be tested well enough by the
1236 // end cases that are easier to specify.
1241 Transform expectedEndOfAnimation
;
1242 expectedEndOfAnimation
.ApplyPerspectiveDepth(1.0);
1243 expectedEndOfAnimation
.Translate3d(10.0, 20.0, 30.0);
1244 expectedEndOfAnimation
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 25.0);
1245 expectedEndOfAnimation
.SkewY(45.0);
1246 expectedEndOfAnimation
.Scale3d(6.0, 7.0, 8.0);
1248 to
= expectedEndOfAnimation
;
1249 to
.Blend(from
, 0.0);
1250 EXPECT_EQ(from
, to
);
1252 to
= expectedEndOfAnimation
;
1253 // We short circuit if blend is >= 1, so to check the numerics, we will
1254 // check that we get close to what we expect when we're nearly done
1256 to
.Blend(from
, .99999f
);
1258 // Recomposing the matrix results in a normalized matrix, so to verify we
1259 // need to normalize the expectedEndOfAnimation before comparing elements.
1260 // Normalizing means dividing everything by expectedEndOfAnimation.m44().
1261 Transform normalizedExpectedEndOfAnimation
= expectedEndOfAnimation
;
1262 Transform normalizationMatrix
;
1263 normalizationMatrix
.matrix().set(
1266 SkDoubleToMScalar(1 / expectedEndOfAnimation
.matrix().get(3.0, 3.0)));
1267 normalizationMatrix
.matrix().set(
1270 SkDoubleToMScalar(1 / expectedEndOfAnimation
.matrix().get(3.0, 3.0)));
1271 normalizationMatrix
.matrix().set(
1274 SkDoubleToMScalar(1 / expectedEndOfAnimation
.matrix().get(3.0, 3.0)));
1275 normalizationMatrix
.matrix().set(
1278 SkDoubleToMScalar(1 / expectedEndOfAnimation
.matrix().get(3.0, 3.0)));
1279 normalizedExpectedEndOfAnimation
.PreconcatTransform(normalizationMatrix
);
1281 EXPECT_TRUE(MatricesAreNearlyEqual(normalizedExpectedEndOfAnimation
, to
));
1284 TEST(XFormTest
, DecomposedTransformCtor
) {
1285 DecomposedTransform decomp
;
1286 for (int i
= 0; i
< 3; ++i
) {
1287 EXPECT_EQ(0.0, decomp
.translate
[i
]);
1288 EXPECT_EQ(1.0, decomp
.scale
[i
]);
1289 EXPECT_EQ(0.0, decomp
.skew
[i
]);
1290 EXPECT_EQ(0.0, decomp
.quaternion
[i
]);
1291 EXPECT_EQ(0.0, decomp
.perspective
[i
]);
1293 EXPECT_EQ(1.0, decomp
.quaternion
[3]);
1294 EXPECT_EQ(1.0, decomp
.perspective
[3]);
1296 Transform composed
= ComposeTransform(decomp
);
1297 EXPECT_TRUE(MatricesAreNearlyEqual(identity
, composed
));
1300 TEST(XFormTest
, FactorTRS
) {
1301 for (int degrees
= 0; degrees
< 180; ++degrees
) {
1302 // build a transformation matrix.
1303 gfx::Transform transform
;
1304 transform
.Translate(degrees
* 2, -degrees
* 3);
1305 transform
.Rotate(degrees
);
1306 transform
.Scale(degrees
+ 1, 2 * degrees
+ 1);
1308 // factor the matrix
1309 DecomposedTransform decomp
;
1310 bool success
= DecomposeTransform(&decomp
, transform
);
1311 EXPECT_TRUE(success
);
1312 EXPECT_FLOAT_EQ(decomp
.translate
[0], degrees
* 2);
1313 EXPECT_FLOAT_EQ(decomp
.translate
[1], -degrees
* 3);
1315 std::acos(SkMScalarToDouble(decomp
.quaternion
[3])) * 360.0 / M_PI
;
1316 while (rotation
< 0.0)
1318 while (rotation
> 360.0)
1321 const float epsilon
= 0.00015f
;
1322 EXPECT_NEAR(rotation
, degrees
, epsilon
);
1323 EXPECT_NEAR(decomp
.scale
[0], degrees
+ 1, epsilon
);
1324 EXPECT_NEAR(decomp
.scale
[1], 2 * degrees
+ 1, epsilon
);
1328 TEST(XFormTest
, IntegerTranslation
) {
1329 gfx::Transform transform
;
1330 EXPECT_TRUE(transform
.IsIdentityOrIntegerTranslation());
1332 transform
.Translate3d(1, 2, 3);
1333 EXPECT_TRUE(transform
.IsIdentityOrIntegerTranslation());
1335 transform
.MakeIdentity();
1336 transform
.Translate3d(-1, -2, -3);
1337 EXPECT_TRUE(transform
.IsIdentityOrIntegerTranslation());
1339 transform
.MakeIdentity();
1340 transform
.Translate3d(4.5f
, 0, 0);
1341 EXPECT_FALSE(transform
.IsIdentityOrIntegerTranslation());
1343 transform
.MakeIdentity();
1344 transform
.Translate3d(0, -6.7f
, 0);
1345 EXPECT_FALSE(transform
.IsIdentityOrIntegerTranslation());
1347 transform
.MakeIdentity();
1348 transform
.Translate3d(0, 0, 8.9f
);
1349 EXPECT_FALSE(transform
.IsIdentityOrIntegerTranslation());
1352 TEST(XFormTest
, verifyMatrixInversion
) {
1354 // Invert a translation
1355 gfx::Transform translation
;
1356 translation
.Translate3d(2.0, 3.0, 4.0);
1357 EXPECT_TRUE(translation
.IsInvertible());
1359 gfx::Transform inverse_translation
;
1360 bool is_invertible
= translation
.GetInverse(&inverse_translation
);
1361 EXPECT_TRUE(is_invertible
);
1362 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, -2.0f
, inverse_translation
);
1363 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, -3.0f
, inverse_translation
);
1364 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, -4.0f
, inverse_translation
);
1365 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, inverse_translation
);
1369 // Invert a non-uniform scale
1370 gfx::Transform scale
;
1371 scale
.Scale3d(4.0, 10.0, 100.0);
1372 EXPECT_TRUE(scale
.IsInvertible());
1374 gfx::Transform inverse_scale
;
1375 bool is_invertible
= scale
.GetInverse(&inverse_scale
);
1376 EXPECT_TRUE(is_invertible
);
1377 EXPECT_ROW1_EQ(0.25f
, 0.0f
, 0.0f
, 0.0f
, inverse_scale
);
1378 EXPECT_ROW2_EQ(0.0f
, 0.1f
, 0.0f
, 0.0f
, inverse_scale
);
1379 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 0.01f
, 0.0f
, inverse_scale
);
1380 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, inverse_scale
);
1384 // Try to invert a matrix that is not invertible.
1385 // The inverse() function should reset the output matrix to identity.
1386 gfx::Transform uninvertible
;
1387 uninvertible
.matrix().set(0, 0, 0.f
);
1388 uninvertible
.matrix().set(1, 1, 0.f
);
1389 uninvertible
.matrix().set(2, 2, 0.f
);
1390 uninvertible
.matrix().set(3, 3, 0.f
);
1391 EXPECT_FALSE(uninvertible
.IsInvertible());
1393 gfx::Transform inverse_of_uninvertible
;
1395 // Add a scale just to more easily ensure that inverse_of_uninvertible is
1396 // reset to identity.
1397 inverse_of_uninvertible
.Scale3d(4.0, 10.0, 100.0);
1399 bool is_invertible
= uninvertible
.GetInverse(&inverse_of_uninvertible
);
1400 EXPECT_FALSE(is_invertible
);
1401 EXPECT_TRUE(inverse_of_uninvertible
.IsIdentity());
1402 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, inverse_of_uninvertible
);
1403 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, inverse_of_uninvertible
);
1404 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, inverse_of_uninvertible
);
1405 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, inverse_of_uninvertible
);
1409 TEST(XFormTest
, verifyBackfaceVisibilityBasicCases
) {
1410 Transform transform
;
1412 transform
.MakeIdentity();
1413 EXPECT_FALSE(transform
.IsBackFaceVisible());
1415 transform
.MakeIdentity();
1416 transform
.RotateAboutYAxis(80.0);
1417 EXPECT_FALSE(transform
.IsBackFaceVisible());
1419 transform
.MakeIdentity();
1420 transform
.RotateAboutYAxis(100.0);
1421 EXPECT_TRUE(transform
.IsBackFaceVisible());
1423 // Edge case, 90 degree rotation should return false.
1424 transform
.MakeIdentity();
1425 transform
.RotateAboutYAxis(90.0);
1426 EXPECT_FALSE(transform
.IsBackFaceVisible());
1429 TEST(XFormTest
, verifyBackfaceVisibilityForPerspective
) {
1430 Transform layer_space_to_projection_plane
;
1432 // This tests if IsBackFaceVisible works properly under perspective
1433 // transforms. Specifically, layers that may have their back face visible in
1434 // orthographic projection, may not actually have back face visible under
1435 // perspective projection.
1437 // Case 1: Layer is rotated by slightly more than 90 degrees, at the center
1438 // of the prespective projection. In this case, the layer's back-side
1439 // is visible to the camera.
1440 layer_space_to_projection_plane
.MakeIdentity();
1441 layer_space_to_projection_plane
.ApplyPerspectiveDepth(1.0);
1442 layer_space_to_projection_plane
.Translate3d(0.0, 0.0, 0.0);
1443 layer_space_to_projection_plane
.RotateAboutYAxis(100.0);
1444 EXPECT_TRUE(layer_space_to_projection_plane
.IsBackFaceVisible());
1446 // Case 2: Layer is rotated by slightly more than 90 degrees, but shifted off
1447 // to the side of the camera. Because of the wide field-of-view, the
1448 // layer's front side is still visible.
1450 // |<-- front side of layer is visible to camera
1455 // |\ /<-- camera field of view
1457 // back side of layer -->| \ /
1458 // \./ <-- camera origin
1460 layer_space_to_projection_plane
.MakeIdentity();
1461 layer_space_to_projection_plane
.ApplyPerspectiveDepth(1.0);
1462 layer_space_to_projection_plane
.Translate3d(-10.0, 0.0, 0.0);
1463 layer_space_to_projection_plane
.RotateAboutYAxis(100.0);
1464 EXPECT_FALSE(layer_space_to_projection_plane
.IsBackFaceVisible());
1466 // Case 3: Additionally rotating the layer by 180 degrees should of course
1467 // show the opposite result of case 2.
1468 layer_space_to_projection_plane
.RotateAboutYAxis(180.0);
1469 EXPECT_TRUE(layer_space_to_projection_plane
.IsBackFaceVisible());
1472 TEST(XFormTest
, verifyDefaultConstructorCreatesIdentityMatrix
) {
1474 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1475 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1476 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1477 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1478 EXPECT_TRUE(A
.IsIdentity());
1481 TEST(XFormTest
, verifyCopyConstructor
) {
1483 InitializeTestMatrix(&A
);
1485 // Copy constructor should produce exact same elements as matrix A.
1487 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, B
);
1488 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, B
);
1489 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, B
);
1490 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, B
);
1493 TEST(XFormTest
, verifyConstructorFor16Elements
) {
1494 Transform
transform(1.0, 2.0, 3.0, 4.0,
1496 9.0, 10.0, 11.0, 12.0,
1497 13.0, 14.0, 15.0, 16.0);
1499 EXPECT_ROW1_EQ(1.0f
, 2.0f
, 3.0f
, 4.0f
, transform
);
1500 EXPECT_ROW2_EQ(5.0f
, 6.0f
, 7.0f
, 8.0f
, transform
);
1501 EXPECT_ROW3_EQ(9.0f
, 10.0f
, 11.0f
, 12.0f
, transform
);
1502 EXPECT_ROW4_EQ(13.0f
, 14.0f
, 15.0f
, 16.0f
, transform
);
1505 TEST(XFormTest
, verifyConstructorFor2dElements
) {
1506 Transform
transform(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
1508 EXPECT_ROW1_EQ(1.0f
, 2.0f
, 0.0f
, 5.0f
, transform
);
1509 EXPECT_ROW2_EQ(3.0f
, 4.0f
, 0.0f
, 6.0f
, transform
);
1510 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, transform
);
1511 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, transform
);
1515 TEST(XFormTest
, verifyAssignmentOperator
) {
1517 InitializeTestMatrix(&A
);
1519 InitializeTestMatrix2(&B
);
1521 InitializeTestMatrix2(&C
);
1524 // Both B and C should now have been re-assigned to the value of A.
1525 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, B
);
1526 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, B
);
1527 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, B
);
1528 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, B
);
1530 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, C
);
1531 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, C
);
1532 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, C
);
1533 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, C
);
1536 TEST(XFormTest
, verifyEqualsBooleanOperator
) {
1538 InitializeTestMatrix(&A
);
1541 InitializeTestMatrix(&B
);
1542 EXPECT_TRUE(A
== B
);
1544 // Modifying multiple elements should cause equals operator to return false.
1546 InitializeTestMatrix2(&C
);
1547 EXPECT_FALSE(A
== C
);
1549 // Modifying any one individual element should cause equals operator to
1553 D
.matrix().set(0, 0, 0.f
);
1554 EXPECT_FALSE(A
== D
);
1557 D
.matrix().set(1, 0, 0.f
);
1558 EXPECT_FALSE(A
== D
);
1561 D
.matrix().set(2, 0, 0.f
);
1562 EXPECT_FALSE(A
== D
);
1565 D
.matrix().set(3, 0, 0.f
);
1566 EXPECT_FALSE(A
== D
);
1569 D
.matrix().set(0, 1, 0.f
);
1570 EXPECT_FALSE(A
== D
);
1573 D
.matrix().set(1, 1, 0.f
);
1574 EXPECT_FALSE(A
== D
);
1577 D
.matrix().set(2, 1, 0.f
);
1578 EXPECT_FALSE(A
== D
);
1581 D
.matrix().set(3, 1, 0.f
);
1582 EXPECT_FALSE(A
== D
);
1585 D
.matrix().set(0, 2, 0.f
);
1586 EXPECT_FALSE(A
== D
);
1589 D
.matrix().set(1, 2, 0.f
);
1590 EXPECT_FALSE(A
== D
);
1593 D
.matrix().set(2, 2, 0.f
);
1594 EXPECT_FALSE(A
== D
);
1597 D
.matrix().set(3, 2, 0.f
);
1598 EXPECT_FALSE(A
== D
);
1601 D
.matrix().set(0, 3, 0.f
);
1602 EXPECT_FALSE(A
== D
);
1605 D
.matrix().set(1, 3, 0.f
);
1606 EXPECT_FALSE(A
== D
);
1609 D
.matrix().set(2, 3, 0.f
);
1610 EXPECT_FALSE(A
== D
);
1613 D
.matrix().set(3, 3, 0.f
);
1614 EXPECT_FALSE(A
== D
);
1617 TEST(XFormTest
, verifyMultiplyOperator
) {
1619 InitializeTestMatrix(&A
);
1622 InitializeTestMatrix2(&B
);
1624 Transform C
= A
* B
;
1625 EXPECT_ROW1_EQ(2036.0f
, 2292.0f
, 2548.0f
, 2804.0f
, C
);
1626 EXPECT_ROW2_EQ(2162.0f
, 2434.0f
, 2706.0f
, 2978.0f
, C
);
1627 EXPECT_ROW3_EQ(2288.0f
, 2576.0f
, 2864.0f
, 3152.0f
, C
);
1628 EXPECT_ROW4_EQ(2414.0f
, 2718.0f
, 3022.0f
, 3326.0f
, C
);
1630 // Just an additional sanity check; matrix multiplication is not commutative.
1631 EXPECT_FALSE(A
* B
== B
* A
);
1634 TEST(XFormTest
, verifyMultiplyAndAssignOperator
) {
1636 InitializeTestMatrix(&A
);
1639 InitializeTestMatrix2(&B
);
1642 EXPECT_ROW1_EQ(2036.0f
, 2292.0f
, 2548.0f
, 2804.0f
, A
);
1643 EXPECT_ROW2_EQ(2162.0f
, 2434.0f
, 2706.0f
, 2978.0f
, A
);
1644 EXPECT_ROW3_EQ(2288.0f
, 2576.0f
, 2864.0f
, 3152.0f
, A
);
1645 EXPECT_ROW4_EQ(2414.0f
, 2718.0f
, 3022.0f
, 3326.0f
, A
);
1647 // Just an additional sanity check; matrix multiplication is not commutative.
1652 EXPECT_FALSE(C
== D
);
1655 TEST(XFormTest
, verifyMatrixMultiplication
) {
1657 InitializeTestMatrix(&A
);
1660 InitializeTestMatrix2(&B
);
1662 A
.PreconcatTransform(B
);
1663 EXPECT_ROW1_EQ(2036.0f
, 2292.0f
, 2548.0f
, 2804.0f
, A
);
1664 EXPECT_ROW2_EQ(2162.0f
, 2434.0f
, 2706.0f
, 2978.0f
, A
);
1665 EXPECT_ROW3_EQ(2288.0f
, 2576.0f
, 2864.0f
, 3152.0f
, A
);
1666 EXPECT_ROW4_EQ(2414.0f
, 2718.0f
, 3022.0f
, 3326.0f
, A
);
1669 TEST(XFormTest
, verifyMakeIdentiy
) {
1671 InitializeTestMatrix(&A
);
1673 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1674 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1675 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1676 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1677 EXPECT_TRUE(A
.IsIdentity());
1680 TEST(XFormTest
, verifyTranslate
) {
1682 A
.Translate(2.0, 3.0);
1683 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 2.0f
, A
);
1684 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 3.0f
, A
);
1685 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1686 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1688 // Verify that Translate() post-multiplies the existing matrix.
1691 A
.Translate(2.0, 3.0);
1692 EXPECT_ROW1_EQ(5.0f
, 0.0f
, 0.0f
, 10.0f
, A
);
1693 EXPECT_ROW2_EQ(0.0f
, 5.0f
, 0.0f
, 15.0f
, A
);
1694 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1695 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1698 TEST(XFormTest
, verifyTranslate3d
) {
1700 A
.Translate3d(2.0, 3.0, 4.0);
1701 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 2.0f
, A
);
1702 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 3.0f
, A
);
1703 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 4.0f
, A
);
1704 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1706 // Verify that Translate3d() post-multiplies the existing matrix.
1708 A
.Scale3d(6.0, 7.0, 8.0);
1709 A
.Translate3d(2.0, 3.0, 4.0);
1710 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 12.0f
, A
);
1711 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 21.0f
, A
);
1712 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 32.0f
, A
);
1713 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1716 TEST(XFormTest
, verifyScale
) {
1719 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1720 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 0.0f
, A
);
1721 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1722 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1724 // Verify that Scale() post-multiplies the existing matrix.
1726 A
.Translate3d(2.0, 3.0, 4.0);
1728 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 2.0f
, A
);
1729 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 3.0f
, A
);
1730 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 4.0f
, A
);
1731 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1734 TEST(XFormTest
, verifyScale3d
) {
1736 A
.Scale3d(6.0, 7.0, 8.0);
1737 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1738 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 0.0f
, A
);
1739 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1740 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1742 // Verify that scale3d() post-multiplies the existing matrix.
1744 A
.Translate3d(2.0, 3.0, 4.0);
1745 A
.Scale3d(6.0, 7.0, 8.0);
1746 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 2.0f
, A
);
1747 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 3.0f
, A
);
1748 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 4.0f
, A
);
1749 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1752 TEST(XFormTest
, verifyRotate
) {
1755 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1756 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1757 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1758 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1760 // Verify that Rotate() post-multiplies the existing matrix.
1762 A
.Scale3d(6.0, 7.0, 8.0);
1764 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1765 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1766 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1767 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1770 TEST(XFormTest
, verifyRotateAboutXAxis
) {
1772 double sin45
= 0.5 * sqrt(2.0);
1773 double cos45
= sin45
;
1776 A
.RotateAboutXAxis(90.0);
1777 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1778 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A
, ERROR_THRESHOLD
);
1779 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1780 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1783 A
.RotateAboutXAxis(45.0);
1784 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1785 EXPECT_ROW2_NEAR(0.0, cos45
, -sin45
, 0.0, A
, ERROR_THRESHOLD
);
1786 EXPECT_ROW3_NEAR(0.0, sin45
, cos45
, 0.0, A
, ERROR_THRESHOLD
);
1787 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1789 // Verify that RotateAboutXAxis(angle) post-multiplies the existing matrix.
1791 A
.Scale3d(6.0, 7.0, 8.0);
1792 A
.RotateAboutXAxis(90.0);
1793 EXPECT_ROW1_NEAR(6.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1794 EXPECT_ROW2_NEAR(0.0, 0.0, -7.0, 0.0, A
, ERROR_THRESHOLD
);
1795 EXPECT_ROW3_NEAR(0.0, 8.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1796 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1799 TEST(XFormTest
, verifyRotateAboutYAxis
) {
1801 double sin45
= 0.5 * sqrt(2.0);
1802 double cos45
= sin45
;
1804 // Note carefully, the expected pattern is inverted compared to rotating
1805 // about x axis or z axis.
1807 A
.RotateAboutYAxis(90.0);
1808 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A
, ERROR_THRESHOLD
);
1809 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1810 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1811 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1814 A
.RotateAboutYAxis(45.0);
1815 EXPECT_ROW1_NEAR(cos45
, 0.0, sin45
, 0.0, A
, ERROR_THRESHOLD
);
1816 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1817 EXPECT_ROW3_NEAR(-sin45
, 0.0, cos45
, 0.0, A
, ERROR_THRESHOLD
);
1818 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1820 // Verify that RotateAboutYAxis(angle) post-multiplies the existing matrix.
1822 A
.Scale3d(6.0, 7.0, 8.0);
1823 A
.RotateAboutYAxis(90.0);
1824 EXPECT_ROW1_NEAR(0.0, 0.0, 6.0, 0.0, A
, ERROR_THRESHOLD
);
1825 EXPECT_ROW2_NEAR(0.0, 7.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1826 EXPECT_ROW3_NEAR(-8.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1827 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1830 TEST(XFormTest
, verifyRotateAboutZAxis
) {
1832 double sin45
= 0.5 * sqrt(2.0);
1833 double cos45
= sin45
;
1836 A
.RotateAboutZAxis(90.0);
1837 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1838 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1839 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1840 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1843 A
.RotateAboutZAxis(45.0);
1844 EXPECT_ROW1_NEAR(cos45
, -sin45
, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1845 EXPECT_ROW2_NEAR(sin45
, cos45
, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1846 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1847 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1849 // Verify that RotateAboutZAxis(angle) post-multiplies the existing matrix.
1851 A
.Scale3d(6.0, 7.0, 8.0);
1852 A
.RotateAboutZAxis(90.0);
1853 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1854 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1855 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1856 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1859 TEST(XFormTest
, verifyRotateAboutForAlignedAxes
) {
1862 // Check rotation about z-axis
1864 A
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1865 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1866 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1867 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1868 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1870 // Check rotation about x-axis
1872 A
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1873 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1874 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A
, ERROR_THRESHOLD
);
1875 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1876 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1878 // Check rotation about y-axis. Note carefully, the expected pattern is
1879 // inverted compared to rotating about x axis or z axis.
1881 A
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1882 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A
, ERROR_THRESHOLD
);
1883 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1884 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1885 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1887 // Verify that rotate3d(axis, angle) post-multiplies the existing matrix.
1889 A
.Scale3d(6.0, 7.0, 8.0);
1890 A
.RotateAboutZAxis(90.0);
1891 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1892 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1893 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1894 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1897 TEST(XFormTest
, verifyRotateAboutForArbitraryAxis
) {
1898 // Check rotation about an arbitrary non-axis-aligned vector.
1900 A
.RotateAbout(Vector3dF(1.0, 1.0, 1.0), 90.0);
1901 EXPECT_ROW1_NEAR(0.3333333333333334258519187,
1902 -0.2440169358562924717404030,
1903 0.9106836025229592124219380,
1904 0.0, A
, ERROR_THRESHOLD
);
1905 EXPECT_ROW2_NEAR(0.9106836025229592124219380,
1906 0.3333333333333334258519187,
1907 -0.2440169358562924717404030,
1908 0.0, A
, ERROR_THRESHOLD
);
1909 EXPECT_ROW3_NEAR(-0.2440169358562924717404030,
1910 0.9106836025229592124219380,
1911 0.3333333333333334258519187,
1912 0.0, A
, ERROR_THRESHOLD
);
1913 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1916 TEST(XFormTest
, verifyRotateAboutForDegenerateAxis
) {
1917 // Check rotation about a degenerate zero vector.
1918 // It is expected to skip applying the rotation.
1921 A
.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 45.0);
1922 // Verify that A remains unchanged.
1923 EXPECT_TRUE(A
.IsIdentity());
1925 InitializeTestMatrix(&A
);
1926 A
.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 35.0);
1928 // Verify that A remains unchanged.
1929 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, A
);
1930 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, A
);
1931 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, A
);
1932 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, A
);
1935 TEST(XFormTest
, verifySkewX
) {
1938 EXPECT_ROW1_EQ(1.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1939 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1940 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1941 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1943 // Verify that skewX() post-multiplies the existing matrix. Row 1, column 2,
1944 // would incorrectly have value "7" if the matrix is pre-multiplied instead
1945 // of post-multiplied.
1947 A
.Scale3d(6.0, 7.0, 8.0);
1949 EXPECT_ROW1_EQ(6.0f
, 6.0f
, 0.0f
, 0.0f
, A
);
1950 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 0.0f
, A
);
1951 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1952 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1955 TEST(XFormTest
, verifySkewY
) {
1958 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1959 EXPECT_ROW2_EQ(1.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1960 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1961 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1963 // Verify that skewY() post-multiplies the existing matrix. Row 2, column 1 ,
1964 // would incorrectly have value "6" if the matrix is pre-multiplied instead
1965 // of post-multiplied.
1967 A
.Scale3d(6.0, 7.0, 8.0);
1969 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1970 EXPECT_ROW2_EQ(7.0f
, 7.0f
, 0.0f
, 0.0f
, A
);
1971 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1972 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1975 TEST(XFormTest
, verifyPerspectiveDepth
) {
1977 A
.ApplyPerspectiveDepth(1.0);
1978 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1979 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1980 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1981 EXPECT_ROW4_EQ(0.0f
, 0.0f
, -1.0f
, 1.0f
, A
);
1983 // Verify that PerspectiveDepth() post-multiplies the existing matrix.
1985 A
.Translate3d(2.0, 3.0, 4.0);
1986 A
.ApplyPerspectiveDepth(1.0);
1987 EXPECT_ROW1_EQ(1.0f
, 0.0f
, -2.0f
, 2.0f
, A
);
1988 EXPECT_ROW2_EQ(0.0f
, 1.0f
, -3.0f
, 3.0f
, A
);
1989 EXPECT_ROW3_EQ(0.0f
, 0.0f
, -3.0f
, 4.0f
, A
);
1990 EXPECT_ROW4_EQ(0.0f
, 0.0f
, -1.0f
, 1.0f
, A
);
1993 TEST(XFormTest
, verifyHasPerspective
) {
1995 A
.ApplyPerspectiveDepth(1.0);
1996 EXPECT_TRUE(A
.HasPerspective());
1999 A
.ApplyPerspectiveDepth(0.0);
2000 EXPECT_FALSE(A
.HasPerspective());
2003 A
.matrix().set(3, 0, -1.f
);
2004 EXPECT_TRUE(A
.HasPerspective());
2007 A
.matrix().set(3, 1, -1.f
);
2008 EXPECT_TRUE(A
.HasPerspective());
2011 A
.matrix().set(3, 2, -0.3f
);
2012 EXPECT_TRUE(A
.HasPerspective());
2015 A
.matrix().set(3, 3, 0.5f
);
2016 EXPECT_TRUE(A
.HasPerspective());
2019 A
.matrix().set(3, 3, 0.f
);
2020 EXPECT_TRUE(A
.HasPerspective());
2023 TEST(XFormTest
, verifyIsInvertible
) {
2026 // Translations, rotations, scales, skews and arbitrary combinations of them
2029 EXPECT_TRUE(A
.IsInvertible());
2032 A
.Translate3d(2.0, 3.0, 4.0);
2033 EXPECT_TRUE(A
.IsInvertible());
2036 A
.Scale3d(6.0, 7.0, 8.0);
2037 EXPECT_TRUE(A
.IsInvertible());
2040 A
.RotateAboutXAxis(10.0);
2041 A
.RotateAboutYAxis(20.0);
2042 A
.RotateAboutZAxis(30.0);
2043 EXPECT_TRUE(A
.IsInvertible());
2047 EXPECT_TRUE(A
.IsInvertible());
2049 // A perspective matrix (projection plane at z=0) is invertible. The
2050 // intuitive explanation is that perspective is eqivalent to a skew of the
2051 // w-axis; skews are invertible.
2053 A
.ApplyPerspectiveDepth(1.0);
2054 EXPECT_TRUE(A
.IsInvertible());
2056 // A "pure" perspective matrix derived by similar triangles, with m44() set
2057 // to zero (i.e. camera positioned at the origin), is not invertible.
2059 A
.ApplyPerspectiveDepth(1.0);
2060 A
.matrix().set(3, 3, 0.f
);
2061 EXPECT_FALSE(A
.IsInvertible());
2063 // Adding more to a non-invertible matrix will not make it invertible in the
2066 A
.ApplyPerspectiveDepth(1.0);
2067 A
.matrix().set(3, 3, 0.f
);
2068 A
.Scale3d(6.0, 7.0, 8.0);
2069 A
.RotateAboutXAxis(10.0);
2070 A
.RotateAboutYAxis(20.0);
2071 A
.RotateAboutZAxis(30.0);
2072 A
.Translate3d(6.0, 7.0, 8.0);
2073 EXPECT_FALSE(A
.IsInvertible());
2075 // A degenerate matrix of all zeros is not invertible.
2077 A
.matrix().set(0, 0, 0.f
);
2078 A
.matrix().set(1, 1, 0.f
);
2079 A
.matrix().set(2, 2, 0.f
);
2080 A
.matrix().set(3, 3, 0.f
);
2081 EXPECT_FALSE(A
.IsInvertible());
2084 TEST(XFormTest
, verifyIsIdentity
) {
2087 InitializeTestMatrix(&A
);
2088 EXPECT_FALSE(A
.IsIdentity());
2091 EXPECT_TRUE(A
.IsIdentity());
2093 // Modifying any one individual element should cause the matrix to no longer
2096 A
.matrix().set(0, 0, 2.f
);
2097 EXPECT_FALSE(A
.IsIdentity());
2100 A
.matrix().set(1, 0, 2.f
);
2101 EXPECT_FALSE(A
.IsIdentity());
2104 A
.matrix().set(2, 0, 2.f
);
2105 EXPECT_FALSE(A
.IsIdentity());
2108 A
.matrix().set(3, 0, 2.f
);
2109 EXPECT_FALSE(A
.IsIdentity());
2112 A
.matrix().set(0, 1, 2.f
);
2113 EXPECT_FALSE(A
.IsIdentity());
2116 A
.matrix().set(1, 1, 2.f
);
2117 EXPECT_FALSE(A
.IsIdentity());
2120 A
.matrix().set(2, 1, 2.f
);
2121 EXPECT_FALSE(A
.IsIdentity());
2124 A
.matrix().set(3, 1, 2.f
);
2125 EXPECT_FALSE(A
.IsIdentity());
2128 A
.matrix().set(0, 2, 2.f
);
2129 EXPECT_FALSE(A
.IsIdentity());
2132 A
.matrix().set(1, 2, 2.f
);
2133 EXPECT_FALSE(A
.IsIdentity());
2136 A
.matrix().set(2, 2, 2.f
);
2137 EXPECT_FALSE(A
.IsIdentity());
2140 A
.matrix().set(3, 2, 2.f
);
2141 EXPECT_FALSE(A
.IsIdentity());
2144 A
.matrix().set(0, 3, 2.f
);
2145 EXPECT_FALSE(A
.IsIdentity());
2148 A
.matrix().set(1, 3, 2.f
);
2149 EXPECT_FALSE(A
.IsIdentity());
2152 A
.matrix().set(2, 3, 2.f
);
2153 EXPECT_FALSE(A
.IsIdentity());
2156 A
.matrix().set(3, 3, 2.f
);
2157 EXPECT_FALSE(A
.IsIdentity());
2160 TEST(XFormTest
, verifyIsIdentityOrTranslation
) {
2163 InitializeTestMatrix(&A
);
2164 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2167 EXPECT_TRUE(A
.IsIdentityOrTranslation());
2169 // Modifying any non-translation components should cause
2170 // IsIdentityOrTranslation() to return false. NOTE: (0, 3), (1, 3), and
2171 // (2, 3) are the translation components, so modifying them should still
2174 A
.matrix().set(0, 0, 2.f
);
2175 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2178 A
.matrix().set(1, 0, 2.f
);
2179 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2182 A
.matrix().set(2, 0, 2.f
);
2183 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2186 A
.matrix().set(3, 0, 2.f
);
2187 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2190 A
.matrix().set(0, 1, 2.f
);
2191 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2194 A
.matrix().set(1, 1, 2.f
);
2195 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2198 A
.matrix().set(2, 1, 2.f
);
2199 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2202 A
.matrix().set(3, 1, 2.f
);
2203 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2206 A
.matrix().set(0, 2, 2.f
);
2207 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2210 A
.matrix().set(1, 2, 2.f
);
2211 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2214 A
.matrix().set(2, 2, 2.f
);
2215 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2218 A
.matrix().set(3, 2, 2.f
);
2219 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2221 // Note carefully - expecting true here.
2223 A
.matrix().set(0, 3, 2.f
);
2224 EXPECT_TRUE(A
.IsIdentityOrTranslation());
2226 // Note carefully - expecting true here.
2228 A
.matrix().set(1, 3, 2.f
);
2229 EXPECT_TRUE(A
.IsIdentityOrTranslation());
2231 // Note carefully - expecting true here.
2233 A
.matrix().set(2, 3, 2.f
);
2234 EXPECT_TRUE(A
.IsIdentityOrTranslation());
2237 A
.matrix().set(3, 3, 2.f
);
2238 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2241 TEST(XFormTest
, verifyIsApproximatelyIdentityOrTranslation
) {
2243 SkMatrix44
& matrix
= A
.matrix();
2245 // Exact pure translation.
2248 // Set translate values to values other than 0 or 1.
2249 matrix
.set(0, 3, 3.4f
);
2250 matrix
.set(1, 3, 4.4f
);
2251 matrix
.set(2, 3, 5.6f
);
2253 EXPECT_TRUE(A
.IsApproximatelyIdentityOrTranslation(0));
2254 EXPECT_TRUE(A
.IsApproximatelyIdentityOrTranslation(kApproxZero
));
2256 // Approximately pure translation.
2257 InitializeApproxIdentityMatrix(&A
);
2259 // Some values must be exact.
2260 matrix
.set(3, 0, 0);
2261 matrix
.set(3, 1, 0);
2262 matrix
.set(3, 2, 0);
2263 matrix
.set(3, 3, 1);
2265 // Set translate values to values other than 0 or 1.
2266 matrix
.set(0, 3, 3.4f
);
2267 matrix
.set(1, 3, 4.4f
);
2268 matrix
.set(2, 3, 5.6f
);
2270 EXPECT_FALSE(A
.IsApproximatelyIdentityOrTranslation(0));
2271 EXPECT_TRUE(A
.IsApproximatelyIdentityOrTranslation(kApproxZero
));
2273 // Not approximately pure translation.
2274 InitializeApproxIdentityMatrix(&A
);
2276 // Some values must be exact.
2277 matrix
.set(3, 0, 0);
2278 matrix
.set(3, 1, 0);
2279 matrix
.set(3, 2, 0);
2280 matrix
.set(3, 3, 1);
2282 // Set some values (not translate values) to values other than 0 or 1.
2283 matrix
.set(0, 1, 3.4f
);
2284 matrix
.set(3, 2, 4.4f
);
2285 matrix
.set(2, 0, 5.6f
);
2287 EXPECT_FALSE(A
.IsApproximatelyIdentityOrTranslation(0));
2288 EXPECT_FALSE(A
.IsApproximatelyIdentityOrTranslation(kApproxZero
));
2291 TEST(XFormTest
, verifyIsScaleOrTranslation
) {
2294 InitializeTestMatrix(&A
);
2295 EXPECT_FALSE(A
.IsScaleOrTranslation());
2298 EXPECT_TRUE(A
.IsScaleOrTranslation());
2300 // Modifying any non-scale or non-translation components should cause
2301 // IsScaleOrTranslation() to return false. (0, 0), (1, 1), (2, 2), (0, 3),
2302 // (1, 3), and (2, 3) are the scale and translation components, so
2303 // modifying them should still return true.
2305 // Note carefully - expecting true here.
2307 A
.matrix().set(0, 0, 2.f
);
2308 EXPECT_TRUE(A
.IsScaleOrTranslation());
2311 A
.matrix().set(1, 0, 2.f
);
2312 EXPECT_FALSE(A
.IsScaleOrTranslation());
2315 A
.matrix().set(2, 0, 2.f
);
2316 EXPECT_FALSE(A
.IsScaleOrTranslation());
2319 A
.matrix().set(3, 0, 2.f
);
2320 EXPECT_FALSE(A
.IsScaleOrTranslation());
2323 A
.matrix().set(0, 1, 2.f
);
2324 EXPECT_FALSE(A
.IsScaleOrTranslation());
2326 // Note carefully - expecting true here.
2328 A
.matrix().set(1, 1, 2.f
);
2329 EXPECT_TRUE(A
.IsScaleOrTranslation());
2332 A
.matrix().set(2, 1, 2.f
);
2333 EXPECT_FALSE(A
.IsScaleOrTranslation());
2336 A
.matrix().set(3, 1, 2.f
);
2337 EXPECT_FALSE(A
.IsScaleOrTranslation());
2340 A
.matrix().set(0, 2, 2.f
);
2341 EXPECT_FALSE(A
.IsScaleOrTranslation());
2344 A
.matrix().set(1, 2, 2.f
);
2345 EXPECT_FALSE(A
.IsScaleOrTranslation());
2347 // Note carefully - expecting true here.
2349 A
.matrix().set(2, 2, 2.f
);
2350 EXPECT_TRUE(A
.IsScaleOrTranslation());
2353 A
.matrix().set(3, 2, 2.f
);
2354 EXPECT_FALSE(A
.IsScaleOrTranslation());
2356 // Note carefully - expecting true here.
2358 A
.matrix().set(0, 3, 2.f
);
2359 EXPECT_TRUE(A
.IsScaleOrTranslation());
2361 // Note carefully - expecting true here.
2363 A
.matrix().set(1, 3, 2.f
);
2364 EXPECT_TRUE(A
.IsScaleOrTranslation());
2366 // Note carefully - expecting true here.
2368 A
.matrix().set(2, 3, 2.f
);
2369 EXPECT_TRUE(A
.IsScaleOrTranslation());
2372 A
.matrix().set(3, 3, 2.f
);
2373 EXPECT_FALSE(A
.IsScaleOrTranslation());
2376 TEST(XFormTest
, verifyFlattenTo2d
) {
2378 InitializeTestMatrix(&A
);
2381 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 0.0f
, 22.0f
, A
);
2382 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 0.0f
, 23.0f
, A
);
2383 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
2384 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 0.0f
, 25.0f
, A
);
2387 // Another implementation of Preserves2dAxisAlignment that isn't as fast,
2388 // good for testing the faster implementation.
2389 static bool EmpiricallyPreserves2dAxisAlignment(const Transform
& transform
) {
2390 Point3F
p1(5.0f
, 5.0f
, 0.0f
);
2391 Point3F
p2(10.0f
, 5.0f
, 0.0f
);
2392 Point3F
p3(10.0f
, 20.0f
, 0.0f
);
2393 Point3F
p4(5.0f
, 20.0f
, 0.0f
);
2395 QuadF
test_quad(PointF(p1
.x(), p1
.y()),
2396 PointF(p2
.x(), p2
.y()),
2397 PointF(p3
.x(), p3
.y()),
2398 PointF(p4
.x(), p4
.y()));
2399 EXPECT_TRUE(test_quad
.IsRectilinear());
2401 transform
.TransformPoint(&p1
);
2402 transform
.TransformPoint(&p2
);
2403 transform
.TransformPoint(&p3
);
2404 transform
.TransformPoint(&p4
);
2406 QuadF
transformedQuad(PointF(p1
.x(), p1
.y()),
2407 PointF(p2
.x(), p2
.y()),
2408 PointF(p3
.x(), p3
.y()),
2409 PointF(p4
.x(), p4
.y()));
2410 return transformedQuad
.IsRectilinear();
2413 TEST(XFormTest
, Preserves2dAxisAlignment
) {
2414 static const struct TestCase
{
2415 SkMScalar a
; // row 1, column 1
2416 SkMScalar b
; // row 1, column 2
2417 SkMScalar c
; // row 2, column 1
2418 SkMScalar d
; // row 2, column 2
2422 0.f
, 4.f
, true }, // basic case
2424 3.f
, 0.f
, true }, // rotate by 90
2426 0.f
, 4.f
, true }, // degenerate x
2428 0.f
, 0.f
, true }, // degenerate y
2430 3.f
, 0.f
, true }, // degenerate x + rotate by 90
2432 0.f
, 0.f
, true }, // degenerate y + rotate by 90
2453 Transform transform
;
2454 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
2455 const TestCase
& value
= test_cases
[i
];
2456 transform
.MakeIdentity();
2457 transform
.matrix().set(0, 0, value
.a
);
2458 transform
.matrix().set(0, 1, value
.b
);
2459 transform
.matrix().set(1, 0, value
.c
);
2460 transform
.matrix().set(1, 1, value
.d
);
2462 if (value
.expected
) {
2463 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2464 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2466 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform
));
2467 EXPECT_FALSE(transform
.Preserves2dAxisAlignment());
2471 // Try the same test cases again, but this time make sure that other matrix
2472 // elements (except perspective) have entries, to test that they are ignored.
2473 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
2474 const TestCase
& value
= test_cases
[i
];
2475 transform
.MakeIdentity();
2476 transform
.matrix().set(0, 0, value
.a
);
2477 transform
.matrix().set(0, 1, value
.b
);
2478 transform
.matrix().set(1, 0, value
.c
);
2479 transform
.matrix().set(1, 1, value
.d
);
2481 transform
.matrix().set(0, 2, 1.f
);
2482 transform
.matrix().set(0, 3, 2.f
);
2483 transform
.matrix().set(1, 2, 3.f
);
2484 transform
.matrix().set(1, 3, 4.f
);
2485 transform
.matrix().set(2, 0, 5.f
);
2486 transform
.matrix().set(2, 1, 6.f
);
2487 transform
.matrix().set(2, 2, 7.f
);
2488 transform
.matrix().set(2, 3, 8.f
);
2490 if (value
.expected
) {
2491 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2492 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2494 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform
));
2495 EXPECT_FALSE(transform
.Preserves2dAxisAlignment());
2499 // Try the same test cases again, but this time add perspective which is
2500 // always assumed to not-preserve axis alignment.
2501 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
2502 const TestCase
& value
= test_cases
[i
];
2503 transform
.MakeIdentity();
2504 transform
.matrix().set(0, 0, value
.a
);
2505 transform
.matrix().set(0, 1, value
.b
);
2506 transform
.matrix().set(1, 0, value
.c
);
2507 transform
.matrix().set(1, 1, value
.d
);
2509 transform
.matrix().set(0, 2, 1.f
);
2510 transform
.matrix().set(0, 3, 2.f
);
2511 transform
.matrix().set(1, 2, 3.f
);
2512 transform
.matrix().set(1, 3, 4.f
);
2513 transform
.matrix().set(2, 0, 5.f
);
2514 transform
.matrix().set(2, 1, 6.f
);
2515 transform
.matrix().set(2, 2, 7.f
);
2516 transform
.matrix().set(2, 3, 8.f
);
2517 transform
.matrix().set(3, 0, 9.f
);
2518 transform
.matrix().set(3, 1, 10.f
);
2519 transform
.matrix().set(3, 2, 11.f
);
2520 transform
.matrix().set(3, 3, 12.f
);
2522 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform
));
2523 EXPECT_FALSE(transform
.Preserves2dAxisAlignment());
2526 // Try a few more practical situations to check precision
2527 transform
.MakeIdentity();
2528 transform
.RotateAboutZAxis(90.0);
2529 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2530 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2532 transform
.MakeIdentity();
2533 transform
.RotateAboutZAxis(180.0);
2534 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2535 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2537 transform
.MakeIdentity();
2538 transform
.RotateAboutZAxis(270.0);
2539 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2540 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2542 transform
.MakeIdentity();
2543 transform
.RotateAboutYAxis(90.0);
2544 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2545 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2547 transform
.MakeIdentity();
2548 transform
.RotateAboutXAxis(90.0);
2549 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2550 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2552 transform
.MakeIdentity();
2553 transform
.RotateAboutZAxis(90.0);
2554 transform
.RotateAboutYAxis(90.0);
2555 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2556 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2558 transform
.MakeIdentity();
2559 transform
.RotateAboutZAxis(90.0);
2560 transform
.RotateAboutXAxis(90.0);
2561 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2562 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2564 transform
.MakeIdentity();
2565 transform
.RotateAboutYAxis(90.0);
2566 transform
.RotateAboutZAxis(90.0);
2567 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2568 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2570 transform
.MakeIdentity();
2571 transform
.RotateAboutZAxis(45.0);
2572 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform
));
2573 EXPECT_FALSE(transform
.Preserves2dAxisAlignment());
2575 // 3-d case; In 2d after an orthographic projection, this case does
2576 // preserve 2d axis alignment. But in 3d, it does not preserve axis
2578 transform
.MakeIdentity();
2579 transform
.RotateAboutYAxis(45.0);
2580 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2581 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2583 transform
.MakeIdentity();
2584 transform
.RotateAboutXAxis(45.0);
2585 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2586 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2588 // Perspective cases.
2589 transform
.MakeIdentity();
2590 transform
.ApplyPerspectiveDepth(10.0);
2591 transform
.RotateAboutYAxis(45.0);
2592 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform
));
2593 EXPECT_FALSE(transform
.Preserves2dAxisAlignment());
2595 transform
.MakeIdentity();
2596 transform
.ApplyPerspectiveDepth(10.0);
2597 transform
.RotateAboutZAxis(90.0);
2598 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform
));
2599 EXPECT_TRUE(transform
.Preserves2dAxisAlignment());
2602 TEST(XFormTest
, To2dTranslation
) {
2603 Vector2dF
translation(3.f
, 7.f
);
2604 Transform transform
;
2605 transform
.Translate(translation
.x(), translation
.y() + 1);
2606 EXPECT_NE(translation
.ToString(), transform
.To2dTranslation().ToString());
2607 transform
.MakeIdentity();
2608 transform
.Translate(translation
.x(), translation
.y());
2609 EXPECT_EQ(translation
.ToString(), transform
.To2dTranslation().ToString());
2612 TEST(XFormTest
, TransformRect
) {
2613 Transform translation
;
2614 translation
.Translate(3.f
, 7.f
);
2615 RectF
rect(1.f
, 2.f
, 3.f
, 4.f
);
2616 RectF
expected(4.f
, 9.f
, 3.f
, 4.f
);
2617 translation
.TransformRect(&rect
);
2618 EXPECT_EQ(expected
.ToString(), rect
.ToString());
2621 TEST(XFormTest
, TransformRectReverse
) {
2622 Transform translation
;
2623 translation
.Translate(3.f
, 7.f
);
2624 RectF
rect(1.f
, 2.f
, 3.f
, 4.f
);
2625 RectF
expected(-2.f
, -5.f
, 3.f
, 4.f
);
2626 EXPECT_TRUE(translation
.TransformRectReverse(&rect
));
2627 EXPECT_EQ(expected
.ToString(), rect
.ToString());
2630 singular
.Scale3d(0.f
, 0.f
, 0.f
);
2631 EXPECT_FALSE(singular
.TransformRectReverse(&rect
));
2634 TEST(XFormTest
, TransformBox
) {
2635 Transform translation
;
2636 translation
.Translate3d(3.f
, 7.f
, 6.f
);
2637 BoxF
box(1.f
, 2.f
, 3.f
, 4.f
, 5.f
, 6.f
);
2638 BoxF
expected(4.f
, 9.f
, 9.f
, 4.f
, 5.f
, 6.f
);
2639 translation
.TransformBox(&box
);
2640 EXPECT_EQ(expected
.ToString(), box
.ToString());
2643 TEST(XFormTest
, TransformBoxReverse
) {
2644 Transform translation
;
2645 translation
.Translate3d(3.f
, 7.f
, 6.f
);
2646 BoxF
box(1.f
, 2.f
, 3.f
, 4.f
, 5.f
, 6.f
);
2647 BoxF
expected(-2.f
, -5.f
, -3.f
, 4.f
, 5.f
, 6.f
);
2648 EXPECT_TRUE(translation
.TransformBoxReverse(&box
));
2649 EXPECT_EQ(expected
.ToString(), box
.ToString());
2652 singular
.Scale3d(0.f
, 0.f
, 0.f
);
2653 EXPECT_FALSE(singular
.TransformBoxReverse(&box
));