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 "testing/gtest/include/gtest/gtest.h"
16 #include "ui/gfx/point.h"
17 #include "ui/gfx/point3_f.h"
18 #include "ui/gfx/transform_util.h"
19 #include "ui/gfx/vector3d_f.h"
25 #define EXPECT_ROW1_EQ(a, b, c, d, transform) \
26 EXPECT_FLOAT_EQ((a), (transform).matrix().get(0, 0)); \
27 EXPECT_FLOAT_EQ((b), (transform).matrix().get(0, 1)); \
28 EXPECT_FLOAT_EQ((c), (transform).matrix().get(0, 2)); \
29 EXPECT_FLOAT_EQ((d), (transform).matrix().get(0, 3));
31 #define EXPECT_ROW2_EQ(a, b, c, d, transform) \
32 EXPECT_FLOAT_EQ((a), (transform).matrix().get(1, 0)); \
33 EXPECT_FLOAT_EQ((b), (transform).matrix().get(1, 1)); \
34 EXPECT_FLOAT_EQ((c), (transform).matrix().get(1, 2)); \
35 EXPECT_FLOAT_EQ((d), (transform).matrix().get(1, 3));
37 #define EXPECT_ROW3_EQ(a, b, c, d, transform) \
38 EXPECT_FLOAT_EQ((a), (transform).matrix().get(2, 0)); \
39 EXPECT_FLOAT_EQ((b), (transform).matrix().get(2, 1)); \
40 EXPECT_FLOAT_EQ((c), (transform).matrix().get(2, 2)); \
41 EXPECT_FLOAT_EQ((d), (transform).matrix().get(2, 3));
43 #define EXPECT_ROW4_EQ(a, b, c, d, transform) \
44 EXPECT_FLOAT_EQ((a), (transform).matrix().get(3, 0)); \
45 EXPECT_FLOAT_EQ((b), (transform).matrix().get(3, 1)); \
46 EXPECT_FLOAT_EQ((c), (transform).matrix().get(3, 2)); \
47 EXPECT_FLOAT_EQ((d), (transform).matrix().get(3, 3)); \
49 // Checking float values for equality close to zero is not robust using
50 // EXPECT_FLOAT_EQ (see gtest documentation). So, to verify rotation matrices,
51 // we must use a looser absolute error threshold in some places.
52 #define EXPECT_ROW1_NEAR(a, b, c, d, transform, errorThreshold) \
53 EXPECT_NEAR((a), (transform).matrix().get(0, 0), (errorThreshold)); \
54 EXPECT_NEAR((b), (transform).matrix().get(0, 1), (errorThreshold)); \
55 EXPECT_NEAR((c), (transform).matrix().get(0, 2), (errorThreshold)); \
56 EXPECT_NEAR((d), (transform).matrix().get(0, 3), (errorThreshold));
58 #define EXPECT_ROW2_NEAR(a, b, c, d, transform, errorThreshold) \
59 EXPECT_NEAR((a), (transform).matrix().get(1, 0), (errorThreshold)); \
60 EXPECT_NEAR((b), (transform).matrix().get(1, 1), (errorThreshold)); \
61 EXPECT_NEAR((c), (transform).matrix().get(1, 2), (errorThreshold)); \
62 EXPECT_NEAR((d), (transform).matrix().get(1, 3), (errorThreshold));
64 #define EXPECT_ROW3_NEAR(a, b, c, d, transform, errorThreshold) \
65 EXPECT_NEAR((a), (transform).matrix().get(2, 0), (errorThreshold)); \
66 EXPECT_NEAR((b), (transform).matrix().get(2, 1), (errorThreshold)); \
67 EXPECT_NEAR((c), (transform).matrix().get(2, 2), (errorThreshold)); \
68 EXPECT_NEAR((d), (transform).matrix().get(2, 3), (errorThreshold));
70 bool PointsAreNearlyEqual(const Point3F
& lhs
,
72 float epsilon
= 0.0001f
;
73 return lhs
.SquaredDistanceTo(rhs
) < epsilon
;
76 bool MatricesAreNearlyEqual(const Transform
& lhs
,
77 const Transform
& rhs
) {
78 float epsilon
= 0.0001f
;
79 for (int row
= 0; row
< 4; ++row
) {
80 for (int col
= 0; col
< 4; ++col
) {
81 if (std::abs(lhs
.matrix().get(row
, col
) -
82 rhs
.matrix().get(row
, col
)) > epsilon
)
89 void InitializeTestMatrix(Transform
* transform
) {
90 SkMatrix44
& matrix
= transform
->matrix();
91 matrix
.setDouble(0, 0, 10.0);
92 matrix
.setDouble(1, 0, 11.0);
93 matrix
.setDouble(2, 0, 12.0);
94 matrix
.setDouble(3, 0, 13.0);
95 matrix
.setDouble(0, 1, 14.0);
96 matrix
.setDouble(1, 1, 15.0);
97 matrix
.setDouble(2, 1, 16.0);
98 matrix
.setDouble(3, 1, 17.0);
99 matrix
.setDouble(0, 2, 18.0);
100 matrix
.setDouble(1, 2, 19.0);
101 matrix
.setDouble(2, 2, 20.0);
102 matrix
.setDouble(3, 2, 21.0);
103 matrix
.setDouble(0, 3, 22.0);
104 matrix
.setDouble(1, 3, 23.0);
105 matrix
.setDouble(2, 3, 24.0);
106 matrix
.setDouble(3, 3, 25.0);
109 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, (*transform
));
110 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, (*transform
));
111 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, (*transform
));
112 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, (*transform
));
115 void InitializeTestMatrix2(Transform
* transform
) {
116 SkMatrix44
& matrix
= transform
->matrix();
117 matrix
.setDouble(0, 0, 30.0);
118 matrix
.setDouble(1, 0, 31.0);
119 matrix
.setDouble(2, 0, 32.0);
120 matrix
.setDouble(3, 0, 33.0);
121 matrix
.setDouble(0, 1, 34.0);
122 matrix
.setDouble(1, 1, 35.0);
123 matrix
.setDouble(2, 1, 36.0);
124 matrix
.setDouble(3, 1, 37.0);
125 matrix
.setDouble(0, 2, 38.0);
126 matrix
.setDouble(1, 2, 39.0);
127 matrix
.setDouble(2, 2, 40.0);
128 matrix
.setDouble(3, 2, 41.0);
129 matrix
.setDouble(0, 3, 42.0);
130 matrix
.setDouble(1, 3, 43.0);
131 matrix
.setDouble(2, 3, 44.0);
132 matrix
.setDouble(3, 3, 45.0);
135 EXPECT_ROW1_EQ(30.0f
, 34.0f
, 38.0f
, 42.0f
, (*transform
));
136 EXPECT_ROW2_EQ(31.0f
, 35.0f
, 39.0f
, 43.0f
, (*transform
));
137 EXPECT_ROW3_EQ(32.0f
, 36.0f
, 40.0f
, 44.0f
, (*transform
));
138 EXPECT_ROW4_EQ(33.0f
, 37.0f
, 41.0f
, 45.0f
, (*transform
));
141 #ifdef SK_MSCALAR_IS_DOUBLE
142 #define ERROR_THRESHOLD 1e-14
144 #define ERROR_THRESHOLD 1e-7
146 #define LOOSE_ERROR_THRESHOLD 1e-7
148 TEST(XFormTest
, Equality
) {
149 Transform lhs
, rhs
, interpolated
;
150 rhs
.matrix().set3x3(1, 2, 3,
154 for (int i
= 0; i
<= 100; ++i
) {
155 for (int row
= 0; row
< 4; ++row
) {
156 for (int col
= 0; col
< 4; ++col
) {
157 float a
= lhs
.matrix().get(row
, col
);
158 float b
= rhs
.matrix().get(row
, col
);
159 float t
= i
/ 100.0f
;
160 interpolated
.matrix().set(row
, col
, a
+ (b
- a
) * t
);
164 EXPECT_TRUE(rhs
== interpolated
);
166 EXPECT_TRUE(rhs
!= interpolated
);
171 for (int i
= 1; i
< 100; ++i
) {
175 rhs
.Translate(-i
, -i
);
176 EXPECT_TRUE(lhs
!= rhs
);
177 rhs
.Translate(2*i
, 2*i
);
178 EXPECT_TRUE(lhs
== rhs
);
182 TEST(XFormTest
, ConcatTranslate
) {
183 static const struct TestCase
{
191 { 0, 0, 10.0f
, 20.0f
, 10, 20 },
192 { 0, 0, -10.0f
, -20.0f
, 0, 0 },
193 { 0, 0, -10.0f
, -20.0f
, -10, -20 },
195 std::numeric_limits
<float>::quiet_NaN(),
196 std::numeric_limits
<float>::quiet_NaN(),
201 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
202 const TestCase
& value
= test_cases
[i
];
203 Transform translation
;
204 translation
.Translate(value
.tx
, value
.ty
);
205 xform
= translation
* xform
;
206 Point3F
p1(value
.x1
, value
.y1
, 0);
207 Point3F
p2(value
.x2
, value
.y2
, 0);
208 xform
.TransformPoint(p1
);
209 if (value
.tx
== value
.tx
&&
210 value
.ty
== value
.ty
) {
211 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p2
));
216 TEST(XFormTest
, ConcatScale
) {
217 static const struct TestCase
{
226 { 1, std::numeric_limits
<float>::quiet_NaN(), 1 }
230 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
231 const TestCase
& value
= test_cases
[i
];
233 scale
.Scale(value
.scale
, value
.scale
);
234 xform
= scale
* xform
;
235 Point3F
p1(value
.before
, value
.before
, 0);
236 Point3F
p2(value
.after
, value
.after
, 0);
237 xform
.TransformPoint(p1
);
238 if (value
.scale
== value
.scale
) {
239 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p2
));
244 TEST(XFormTest
, ConcatRotate
) {
245 static const struct TestCase
{
252 { 1, 0, 90.0f
, 0, 1 },
253 { 1, 0, -90.0f
, 1, 0 },
254 { 1, 0, 90.0f
, 0, 1 },
255 { 1, 0, 360.0f
, 0, 1 },
256 { 1, 0, 0.0f
, 0, 1 },
257 { 1, 0, std::numeric_limits
<float>::quiet_NaN(), 1, 0 }
261 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
262 const TestCase
& value
= test_cases
[i
];
264 rotation
.Rotate(value
.degrees
);
265 xform
= rotation
* xform
;
266 Point3F
p1(value
.x1
, value
.y1
, 0);
267 Point3F
p2(value
.x2
, value
.y2
, 0);
268 xform
.TransformPoint(p1
);
269 if (value
.degrees
== value
.degrees
) {
270 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p2
));
275 TEST(XFormTest
, SetTranslate
) {
276 static const struct TestCase
{
281 { 0, 0, 10.0f
, 20.0f
, 10, 20 },
282 { 10, 20, 10.0f
, 20.0f
, 20, 40 },
283 { 10, 20, 0.0f
, 0.0f
, 10, 20 },
285 std::numeric_limits
<float>::quiet_NaN(),
286 std::numeric_limits
<float>::quiet_NaN(),
290 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
291 const TestCase
& value
= test_cases
[i
];
292 for (int k
= 0; k
< 3; ++k
) {
297 p1
.SetPoint(value
.x1
, 0, 0);
298 p2
.SetPoint(value
.x2
, 0, 0);
299 xform
.Translate(value
.tx
, 0.0);
302 p1
.SetPoint(0, value
.y1
, 0);
303 p2
.SetPoint(0, value
.y2
, 0);
304 xform
.Translate(0.0, value
.ty
);
307 p1
.SetPoint(value
.x1
, value
.y1
, 0);
308 p2
.SetPoint(value
.x2
, value
.y2
, 0);
309 xform
.Translate(value
.tx
, value
.ty
);
313 xform
.TransformPoint(p1
);
314 if (value
.tx
== value
.tx
&&
315 value
.ty
== value
.ty
) {
316 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p2
));
317 xform
.TransformPointReverse(p1
);
318 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p0
));
324 TEST(XFormTest
, SetScale
) {
325 static const struct TestCase
{
334 { 1, std::numeric_limits
<float>::quiet_NaN(), 0 },
337 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
338 const TestCase
& value
= test_cases
[i
];
339 for (int k
= 0; k
< 3; ++k
) {
344 p1
.SetPoint(value
.before
, 0, 0);
345 p2
.SetPoint(value
.after
, 0, 0);
346 xform
.Scale(value
.s
, 1.0);
349 p1
.SetPoint(0, value
.before
, 0);
350 p2
.SetPoint(0, value
.after
, 0);
351 xform
.Scale(1.0, value
.s
);
354 p1
.SetPoint(value
.before
, value
.before
, 0);
355 p2
.SetPoint(value
.after
, value
.after
, 0);
356 xform
.Scale(value
.s
, value
.s
);
360 xform
.TransformPoint(p1
);
361 if (value
.s
== value
.s
) {
362 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p2
));
363 if (value
.s
!= 0.0f
) {
364 xform
.TransformPointReverse(p1
);
365 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p0
));
372 TEST(XFormTest
, SetRotate
) {
373 static const struct SetRotateCase
{
379 } set_rotate_cases
[] = {
380 { 100, 0, 90.0f
, 0, 100 },
381 { 0, 0, 90.0f
, 0, 0 },
382 { 0, 100, 90.0f
, -100, 0 },
383 { 0, 1, -90.0f
, 1, 0 },
384 { 100, 0, 0.0f
, 100, 0 },
385 { 0, 0, 0.0f
, 0, 0 },
386 { 0, 0, std::numeric_limits
<float>::quiet_NaN(), 0, 0 },
387 { 100, 0, 360.0f
, 100, 0 }
390 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(set_rotate_cases
); ++i
) {
391 const SetRotateCase
& value
= set_rotate_cases
[i
];
393 Point3F
p1(value
.x
, value
.y
, 0);
394 Point3F
p2(value
.xprime
, value
.yprime
, 0);
397 xform
.Rotate(value
.degree
);
398 // just want to make sure that we don't crash in the case of NaN.
399 if (value
.degree
== value
.degree
) {
400 xform
.TransformPoint(p1
);
401 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p2
));
402 xform
.TransformPointReverse(p1
);
403 EXPECT_TRUE(PointsAreNearlyEqual(p1
, p0
));
409 TEST(XFormTest
, ConcatTranslate2D
) {
410 static const struct TestCase
{
418 { 0, 0, 10.0f
, 20.0f
, 10, 20},
419 { 0, 0, -10.0f
, -20.0f
, 0, 0},
420 { 0, 0, -10.0f
, -20.0f
, -10, -20},
422 std::numeric_limits
<float>::quiet_NaN(),
423 std::numeric_limits
<float>::quiet_NaN(),
428 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
429 const TestCase
& value
= test_cases
[i
];
430 Transform translation
;
431 translation
.Translate(value
.tx
, value
.ty
);
432 xform
= translation
* xform
;
433 Point
p1(value
.x1
, value
.y1
);
434 Point
p2(value
.x2
, value
.y2
);
435 xform
.TransformPoint(p1
);
436 if (value
.tx
== value
.tx
&&
437 value
.ty
== value
.ty
) {
438 EXPECT_EQ(p1
.x(), p2
.x());
439 EXPECT_EQ(p1
.y(), p2
.y());
444 TEST(XFormTest
, ConcatScale2D
) {
445 static const struct TestCase
{
454 { 1, std::numeric_limits
<float>::quiet_NaN(), 1}
458 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
459 const TestCase
& value
= test_cases
[i
];
461 scale
.Scale(value
.scale
, value
.scale
);
462 xform
= scale
* xform
;
463 Point
p1(value
.before
, value
.before
);
464 Point
p2(value
.after
, value
.after
);
465 xform
.TransformPoint(p1
);
466 if (value
.scale
== value
.scale
) {
467 EXPECT_EQ(p1
.x(), p2
.x());
468 EXPECT_EQ(p1
.y(), p2
.y());
473 TEST(XFormTest
, ConcatRotate2D
) {
474 static const struct TestCase
{
481 { 1, 0, 90.0f
, 0, 1},
482 { 1, 0, -90.0f
, 1, 0},
483 { 1, 0, 90.0f
, 0, 1},
484 { 1, 0, 360.0f
, 0, 1},
486 { 1, 0, std::numeric_limits
<float>::quiet_NaN(), 1, 0}
490 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
491 const TestCase
& value
= test_cases
[i
];
493 rotation
.Rotate(value
.degrees
);
494 xform
= rotation
* xform
;
495 Point
p1(value
.x1
, value
.y1
);
496 Point
p2(value
.x2
, value
.y2
);
497 xform
.TransformPoint(p1
);
498 if (value
.degrees
== value
.degrees
) {
499 EXPECT_EQ(p1
.x(), p2
.x());
500 EXPECT_EQ(p1
.y(), p2
.y());
505 TEST(XFormTest
, SetTranslate2D
) {
506 static const struct TestCase
{
511 { 0, 0, 10.0f
, 20.0f
, 10, 20},
512 { 10, 20, 10.0f
, 20.0f
, 20, 40},
513 { 10, 20, 0.0f
, 0.0f
, 10, 20},
515 std::numeric_limits
<float>::quiet_NaN(),
516 std::numeric_limits
<float>::quiet_NaN(),
520 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
521 const TestCase
& value
= test_cases
[i
];
522 for (int j
= -1; j
< 2; ++j
) {
523 for (int k
= 0; k
< 3; ++k
) {
524 float epsilon
= 0.0001f
;
529 p1
.SetPoint(value
.x1
, 0);
530 p2
.SetPoint(value
.x2
, 0);
531 xform
.Translate(value
.tx
+ j
* epsilon
, 0.0);
534 p1
.SetPoint(0, value
.y1
);
535 p2
.SetPoint(0, value
.y2
);
536 xform
.Translate(0.0, value
.ty
+ j
* epsilon
);
539 p1
.SetPoint(value
.x1
, value
.y1
);
540 p2
.SetPoint(value
.x2
, value
.y2
);
541 xform
.Translate(value
.tx
+ j
* epsilon
,
542 value
.ty
+ j
* epsilon
);
546 xform
.TransformPoint(p1
);
547 if (value
.tx
== value
.tx
&&
548 value
.ty
== value
.ty
) {
549 EXPECT_EQ(p1
.x(), p2
.x());
550 EXPECT_EQ(p1
.y(), p2
.y());
551 xform
.TransformPointReverse(p1
);
552 EXPECT_EQ(p1
.x(), p0
.x());
553 EXPECT_EQ(p1
.y(), p0
.y());
560 TEST(XFormTest
, SetScale2D
) {
561 static const struct TestCase
{
570 { 1, std::numeric_limits
<float>::quiet_NaN(), 0},
573 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
574 const TestCase
& value
= test_cases
[i
];
575 for (int j
= -1; j
< 2; ++j
) {
576 for (int k
= 0; k
< 3; ++k
) {
577 float epsilon
= 0.0001f
;
582 p1
.SetPoint(value
.before
, 0);
583 p2
.SetPoint(value
.after
, 0);
584 xform
.Scale(value
.s
+ j
* epsilon
, 1.0);
587 p1
.SetPoint(0, value
.before
);
588 p2
.SetPoint(0, value
.after
);
589 xform
.Scale(1.0, value
.s
+ j
* epsilon
);
592 p1
.SetPoint(value
.before
,
594 p2
.SetPoint(value
.after
,
596 xform
.Scale(value
.s
+ j
* epsilon
,
597 value
.s
+ j
* epsilon
);
601 xform
.TransformPoint(p1
);
602 if (value
.s
== value
.s
) {
603 EXPECT_EQ(p1
.x(), p2
.x());
604 EXPECT_EQ(p1
.y(), p2
.y());
605 if (value
.s
!= 0.0f
) {
606 xform
.TransformPointReverse(p1
);
607 EXPECT_EQ(p1
.x(), p0
.x());
608 EXPECT_EQ(p1
.y(), p0
.y());
616 TEST(XFormTest
, SetRotate2D
) {
617 static const struct SetRotateCase
{
623 } set_rotate_cases
[] = {
624 { 100, 0, 90.0f
, 0, 100},
625 { 0, 0, 90.0f
, 0, 0},
626 { 0, 100, 90.0f
, -100, 0},
627 { 0, 1, -90.0f
, 1, 0},
628 { 100, 0, 0.0f
, 100, 0},
630 { 0, 0, std::numeric_limits
<float>::quiet_NaN(), 0, 0},
631 { 100, 0, 360.0f
, 100, 0}
634 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(set_rotate_cases
); ++i
) {
635 const SetRotateCase
& value
= set_rotate_cases
[i
];
636 for (int j
= 1; j
>= -1; --j
) {
637 float epsilon
= 0.1f
;
638 Point
pt(value
.x
, value
.y
);
640 // should be invariant to small floating point errors.
641 xform
.Rotate(value
.degree
+ j
* epsilon
);
642 // just want to make sure that we don't crash in the case of NaN.
643 if (value
.degree
== value
.degree
) {
644 xform
.TransformPoint(pt
);
645 EXPECT_EQ(value
.xprime
, pt
.x());
646 EXPECT_EQ(value
.yprime
, pt
.y());
647 xform
.TransformPointReverse(pt
);
648 EXPECT_EQ(pt
.x(), value
.x
);
649 EXPECT_EQ(pt
.y(), value
.y
);
655 TEST(XFormTest
, BlendTranslate
) {
657 for (int i
= 0; i
< 10; ++i
) {
659 to
.Translate3d(1, 1, 1);
661 EXPECT_TRUE(to
.Blend(from
, t
));
662 EXPECT_FLOAT_EQ(t
, to
.matrix().get(0, 3));
663 EXPECT_FLOAT_EQ(t
, to
.matrix().get(1, 3));
664 EXPECT_FLOAT_EQ(t
, to
.matrix().get(2, 3));
668 TEST(XFormTest
, BlendRotate
) {
676 for (size_t index
= 0; index
< ARRAYSIZE_UNSAFE(axes
); ++index
) {
677 for (int i
= 0; i
< 10; ++i
) {
679 to
.RotateAbout(axes
[index
], 90);
681 EXPECT_TRUE(to
.Blend(from
, t
));
684 expected
.RotateAbout(axes
[index
], 90 * t
);
686 EXPECT_TRUE(MatricesAreNearlyEqual(expected
, to
));
691 TEST(XFormTest
, CannotBlend180DegreeRotation
) {
699 for (size_t index
= 0; index
< ARRAYSIZE_UNSAFE(axes
); ++index
) {
701 to
.RotateAbout(axes
[index
], 180);
702 EXPECT_FALSE(to
.Blend(from
, 0.5));
706 TEST(XFormTest
, BlendScale
) {
708 for (int i
= 0; i
< 10; ++i
) {
712 EXPECT_TRUE(to
.Blend(from
, t
));
713 EXPECT_FLOAT_EQ(t
* 4 + 1, to
.matrix().get(0, 0));
714 EXPECT_FLOAT_EQ(t
* 3 + 1, to
.matrix().get(1, 1));
715 EXPECT_FLOAT_EQ(t
* 2 + 1, to
.matrix().get(2, 2));
719 TEST(XFormTest
, BlendSkew
) {
721 for (int i
= 0; i
< 2; ++i
) {
727 expected
.SkewX(t
* 20);
728 expected
.SkewY(t
* 10);
729 EXPECT_TRUE(to
.Blend(from
, t
));
730 EXPECT_TRUE(MatricesAreNearlyEqual(expected
, to
));
734 TEST(XFormTest
, BlendPerspective
) {
736 from
.ApplyPerspectiveDepth(200);
737 for (int i
= 0; i
< 2; ++i
) {
739 to
.ApplyPerspectiveDepth(800);
742 expected
.ApplyPerspectiveDepth(t
* 600 + 200);
743 EXPECT_TRUE(to
.Blend(from
, t
));
744 EXPECT_TRUE(MatricesAreNearlyEqual(expected
, to
));
748 TEST(XFormTest
, BlendIdentity
) {
751 EXPECT_TRUE(to
.Blend(from
, 0.5));
755 TEST(XFormTest
, CannotBlendSingularMatrix
) {
758 to
.matrix().set(1, 1, SkDoubleToMScalar(0));
759 EXPECT_FALSE(to
.Blend(from
, 0.5));
762 TEST(XFormTest
, VerifyBlendForTranslation
) {
764 from
.Translate3d(100.0, 200.0, 100.0);
768 to
.Translate3d(200.0, 100.0, 300.0);
773 to
.Translate3d(200.0, 100.0, 300.0);
774 to
.Blend(from
, 0.25);
775 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 125.0f
, to
);
776 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 175.0f
, to
);
777 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 150.0f
, to
);
778 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
781 to
.Translate3d(200.0, 100.0, 300.0);
783 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 150.0f
, to
);
784 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 150.0f
, to
);
785 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 200.0f
, to
);
786 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
789 to
.Translate3d(200.0, 100.0, 300.0);
791 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 200.0f
, to
);
792 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 100.0f
, to
);
793 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 300.0f
, to
);
794 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
797 TEST(XFormTest
, VerifyBlendForScale
) {
799 from
.Scale3d(100.0, 200.0, 100.0);
803 to
.Scale3d(200.0, 100.0, 300.0);
808 to
.Scale3d(200.0, 100.0, 300.0);
809 to
.Blend(from
, 0.25);
810 EXPECT_ROW1_EQ(125.0f
, 0.0f
, 0.0f
, 0.0f
, to
);
811 EXPECT_ROW2_EQ(0.0f
, 175.0f
, 0.0f
, 0.0f
, to
);
812 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 150.0f
, 0.0f
, to
);
813 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
816 to
.Scale3d(200.0, 100.0, 300.0);
818 EXPECT_ROW1_EQ(150.0f
, 0.0f
, 0.0f
, 0.0f
, to
);
819 EXPECT_ROW2_EQ(0.0f
, 150.0f
, 0.0f
, 0.0f
, to
);
820 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 200.0f
, 0.0f
, to
);
821 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
824 to
.Scale3d(200.0, 100.0, 300.0);
826 EXPECT_ROW1_EQ(200.0f
, 0.0f
, 0.0f
, 0.0f
, to
);
827 EXPECT_ROW2_EQ(0.0f
, 100.0f
, 0.0f
, 0.0f
, to
);
828 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 300.0f
, 0.0f
, to
);
829 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
832 TEST(XFormTest
, VerifyBlendForSkewX
) {
845 EXPECT_ROW1_EQ(1.0f
, 0.5f
, 0.0f
, 0.0f
, to
);
846 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, to
);
847 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
848 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
852 to
.Blend(from
, 0.25);
853 EXPECT_ROW1_EQ(1.0f
, 0.25f
, 0.0f
, 0.0f
, to
);
854 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, to
);
855 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
856 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
861 EXPECT_ROW1_EQ(1.0f
, 1.0f
, 0.0f
, 0.0f
, to
);
862 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, to
);
863 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
864 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
867 TEST(XFormTest
, VerifyBlendForSkewY
) {
868 // NOTE CAREFULLY: Decomposition of skew and rotation terms of the matrix
869 // is inherently underconstrained, and so it does not always compute the
870 // originally intended skew parameters. The current implementation uses QR
871 // decomposition, which decomposes the shear into a rotation + non-uniform
874 // It is unlikely that the decomposition implementation will need to change
875 // very often, so to get any test coverage, the compromise is to verify the
876 // exact matrix that the.Blend() operation produces.
878 // This problem also potentially exists for skewX, but the current QR
879 // decomposition implementation just happens to decompose those test
880 // matrices intuitively.
882 // Unfortunately, this case suffers from uncomfortably large precision
896 to
.Blend(from
, 0.25);
897 EXPECT_ROW1_NEAR(1.0823489449280947471976333,
898 0.0464370719145053845178239,
902 LOOSE_ERROR_THRESHOLD
);
903 EXPECT_ROW2_NEAR(0.2152925909665224513123150,
904 0.9541702441750861130032035,
908 LOOSE_ERROR_THRESHOLD
);
909 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
910 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
915 EXPECT_ROW1_NEAR(1.1152212925809066312865525,
916 0.0676495144007326631996335,
920 LOOSE_ERROR_THRESHOLD
);
921 EXPECT_ROW2_NEAR(0.4619397844342648662419037,
922 0.9519009045724774464858342,
926 LOOSE_ERROR_THRESHOLD
);
927 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
928 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
933 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to
, LOOSE_ERROR_THRESHOLD
);
934 EXPECT_ROW2_NEAR(1.0, 1.0, 0.0, 0.0, to
, LOOSE_ERROR_THRESHOLD
);
935 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, to
);
936 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
939 TEST(XFormTest
, VerifyBlendForRotationAboutX
) {
940 // Even though.Blending uses quaternions, axis-aligned rotations should.
941 // Blend the same with quaternions or Euler angles. So we can test
942 // rotation.Blending by comparing against manually specified matrices from
946 from
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 0.0);
950 to
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
954 double expectedRotationAngle
= 22.5 * M_PI
/ 180.0;
956 to
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
957 to
.Blend(from
, 0.25);
958 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
959 EXPECT_ROW2_NEAR(0.0,
960 std::cos(expectedRotationAngle
),
961 -std::sin(expectedRotationAngle
),
965 EXPECT_ROW3_NEAR(0.0,
966 std::sin(expectedRotationAngle
),
967 std::cos(expectedRotationAngle
),
971 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
973 expectedRotationAngle
= 45.0 * M_PI
/ 180.0;
975 to
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
977 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
978 EXPECT_ROW2_NEAR(0.0,
979 std::cos(expectedRotationAngle
),
980 -std::sin(expectedRotationAngle
),
984 EXPECT_ROW3_NEAR(0.0,
985 std::sin(expectedRotationAngle
),
986 std::cos(expectedRotationAngle
),
990 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
993 to
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
995 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
996 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, to
, ERROR_THRESHOLD
);
997 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
998 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1001 TEST(XFormTest
, VerifyBlendForRotationAboutY
) {
1003 from
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 0.0);
1007 to
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1008 to
.Blend(from
, 0.0);
1009 EXPECT_EQ(from
, to
);
1011 double expectedRotationAngle
= 22.5 * M_PI
/ 180.0;
1013 to
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1014 to
.Blend(from
, 0.25);
1015 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle
),
1017 std::sin(expectedRotationAngle
),
1021 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1022 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle
),
1024 std::cos(expectedRotationAngle
),
1028 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1030 expectedRotationAngle
= 45.0 * M_PI
/ 180.0;
1032 to
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1033 to
.Blend(from
, 0.5);
1034 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle
),
1036 std::sin(expectedRotationAngle
),
1040 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1041 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle
),
1043 std::cos(expectedRotationAngle
),
1047 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1050 to
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1051 to
.Blend(from
, 1.0);
1052 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, to
, ERROR_THRESHOLD
);
1053 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1054 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1055 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1058 TEST(XFormTest
, VerifyBlendForRotationAboutZ
) {
1060 from
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 0.0);
1064 to
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1065 to
.Blend(from
, 0.0);
1066 EXPECT_EQ(from
, to
);
1068 double expectedRotationAngle
= 22.5 * M_PI
/ 180.0;
1070 to
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1071 to
.Blend(from
, 0.25);
1072 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle
),
1073 -std::sin(expectedRotationAngle
),
1078 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle
),
1079 std::cos(expectedRotationAngle
),
1084 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to
, ERROR_THRESHOLD
);
1085 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1087 expectedRotationAngle
= 45.0 * M_PI
/ 180.0;
1089 to
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1090 to
.Blend(from
, 0.5);
1091 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle
),
1092 -std::sin(expectedRotationAngle
),
1097 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle
),
1098 std::cos(expectedRotationAngle
),
1103 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to
, ERROR_THRESHOLD
);
1104 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1107 to
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1108 to
.Blend(from
, 1.0);
1109 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1110 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, to
, ERROR_THRESHOLD
);
1111 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to
, ERROR_THRESHOLD
);
1112 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, to
);
1115 TEST(XFormTest
, VerifyBlendForCompositeTransform
) {
1116 // Verify that the.Blending was done with a decomposition in correct order
1117 // by blending a composite transform. Using matrix x vector notation
1118 // (Ax = b, where x is column vector), the ordering should be:
1119 // perspective * translation * rotation * skew * scale
1121 // It is not as important (or meaningful) to check intermediate
1122 // interpolations; order of operations will be tested well enough by the
1123 // end cases that are easier to specify.
1128 Transform expectedEndOfAnimation
;
1129 expectedEndOfAnimation
.ApplyPerspectiveDepth(1.0);
1130 expectedEndOfAnimation
.Translate3d(10.0, 20.0, 30.0);
1131 expectedEndOfAnimation
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 25.0);
1132 expectedEndOfAnimation
.SkewY(45.0);
1133 expectedEndOfAnimation
.Scale3d(6.0, 7.0, 8.0);
1135 to
= expectedEndOfAnimation
;
1136 to
.Blend(from
, 0.0);
1137 EXPECT_EQ(from
, to
);
1139 to
= expectedEndOfAnimation
;
1140 // We short circuit if blend is >= 1, so to check the numerics, we will
1141 // check that we get close to what we expect when we're nearly done
1143 to
.Blend(from
, .99999);
1145 // Recomposing the matrix results in a normalized matrix, so to verify we
1146 // need to normalize the expectedEndOfAnimation before comparing elements.
1147 // Normalizing means dividing everything by expectedEndOfAnimation.m44().
1148 Transform normalizedExpectedEndOfAnimation
= expectedEndOfAnimation
;
1149 Transform normalizationMatrix
;
1150 normalizationMatrix
.matrix().set(
1153 SkDoubleToMScalar(1 / expectedEndOfAnimation
.matrix().get(3.0, 3.0)));
1154 normalizationMatrix
.matrix().set(
1157 SkDoubleToMScalar(1 / expectedEndOfAnimation
.matrix().get(3.0, 3.0)));
1158 normalizationMatrix
.matrix().set(
1161 SkDoubleToMScalar(1 / expectedEndOfAnimation
.matrix().get(3.0, 3.0)));
1162 normalizationMatrix
.matrix().set(
1165 SkDoubleToMScalar(1 / expectedEndOfAnimation
.matrix().get(3.0, 3.0)));
1166 normalizedExpectedEndOfAnimation
.PreconcatTransform(normalizationMatrix
);
1168 EXPECT_TRUE(MatricesAreNearlyEqual(normalizedExpectedEndOfAnimation
, to
));
1171 TEST(XFormTest
, DecomposedTransformCtor
) {
1172 DecomposedTransform decomp
;
1173 for (int i
= 0; i
< 3; ++i
) {
1174 EXPECT_EQ(0.0, decomp
.translate
[i
]);
1175 EXPECT_EQ(1.0, decomp
.scale
[i
]);
1176 EXPECT_EQ(0.0, decomp
.skew
[i
]);
1177 EXPECT_EQ(0.0, decomp
.quaternion
[i
]);
1178 EXPECT_EQ(0.0, decomp
.perspective
[i
]);
1180 EXPECT_EQ(1.0, decomp
.quaternion
[3]);
1181 EXPECT_EQ(1.0, decomp
.perspective
[3]);
1183 Transform composed
= ComposeTransform(decomp
);
1184 EXPECT_TRUE(MatricesAreNearlyEqual(identity
, composed
));
1187 TEST(XFormTest
, FactorTRS
) {
1188 for (int degrees
= 0; degrees
< 180; ++degrees
) {
1189 // build a transformation matrix.
1190 gfx::Transform transform
;
1191 transform
.Translate(degrees
* 2, -degrees
* 3);
1192 transform
.Rotate(degrees
);
1193 transform
.Scale(degrees
+ 1, 2 * degrees
+ 1);
1195 // factor the matrix
1196 DecomposedTransform decomp
;
1197 bool success
= DecomposeTransform(&decomp
, transform
);
1198 EXPECT_TRUE(success
);
1199 EXPECT_FLOAT_EQ(decomp
.translate
[0], degrees
* 2);
1200 EXPECT_FLOAT_EQ(decomp
.translate
[1], -degrees
* 3);
1201 double rotation
= std::acos(decomp
.quaternion
[3]) * 360.0 / M_PI
;
1202 while (rotation
< 0.0)
1204 while (rotation
> 360.0)
1206 EXPECT_FLOAT_EQ(rotation
, degrees
);
1207 EXPECT_FLOAT_EQ(decomp
.scale
[0], degrees
+ 1);
1208 EXPECT_FLOAT_EQ(decomp
.scale
[1], 2 * degrees
+ 1);
1212 TEST(XFormTest
, IntegerTranslation
) {
1213 gfx::Transform transform
;
1214 EXPECT_TRUE(transform
.IsIdentityOrIntegerTranslation());
1216 transform
.Translate3d(1, 2, 3);
1217 EXPECT_TRUE(transform
.IsIdentityOrIntegerTranslation());
1219 transform
.MakeIdentity();
1220 transform
.Translate3d(-1, -2, -3);
1221 EXPECT_TRUE(transform
.IsIdentityOrIntegerTranslation());
1223 transform
.MakeIdentity();
1224 transform
.Translate3d(4.5, 0, 0);
1225 EXPECT_FALSE(transform
.IsIdentityOrIntegerTranslation());
1227 transform
.MakeIdentity();
1228 transform
.Translate3d(0, -6.7, 0);
1229 EXPECT_FALSE(transform
.IsIdentityOrIntegerTranslation());
1231 transform
.MakeIdentity();
1232 transform
.Translate3d(0, 0, 8.9);
1233 EXPECT_FALSE(transform
.IsIdentityOrIntegerTranslation());
1236 TEST(XFormTest
, verifyMatrixInversion
) {
1238 // Invert a translation
1239 gfx::Transform translation
;
1240 translation
.Translate3d(2.0, 3.0, 4.0);
1241 EXPECT_TRUE(translation
.IsInvertible());
1243 gfx::Transform inverse_translation
;
1244 bool is_invertible
= translation
.GetInverse(&inverse_translation
);
1245 EXPECT_TRUE(is_invertible
);
1246 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, -2.0f
, inverse_translation
);
1247 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, -3.0f
, inverse_translation
);
1248 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, -4.0f
, inverse_translation
);
1249 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, inverse_translation
);
1253 // Invert a non-uniform scale
1254 gfx::Transform scale
;
1255 scale
.Scale3d(4.0, 10.0, 100.0);
1256 EXPECT_TRUE(scale
.IsInvertible());
1258 gfx::Transform inverse_scale
;
1259 bool is_invertible
= scale
.GetInverse(&inverse_scale
);
1260 EXPECT_TRUE(is_invertible
);
1261 EXPECT_ROW1_EQ(0.25f
, 0.0f
, 0.0f
, 0.0f
, inverse_scale
);
1262 EXPECT_ROW2_EQ(0.0f
, 0.1f
, 0.0f
, 0.0f
, inverse_scale
);
1263 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 0.01f
, 0.0f
, inverse_scale
);
1264 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, inverse_scale
);
1268 // Try to invert a matrix that is not invertible.
1269 // The inverse() function should reset the output matrix to identity.
1270 gfx::Transform uninvertible
;
1271 uninvertible
.matrix().setDouble(0, 0, 0.0);
1272 uninvertible
.matrix().setDouble(1, 1, 0.0);
1273 uninvertible
.matrix().setDouble(2, 2, 0.0);
1274 uninvertible
.matrix().setDouble(3, 3, 0.0);
1275 EXPECT_FALSE(uninvertible
.IsInvertible());
1277 gfx::Transform inverse_of_uninvertible
;
1279 // Add a scale just to more easily ensure that inverse_of_uninvertible is
1280 // reset to identity.
1281 inverse_of_uninvertible
.Scale3d(4.0, 10.0, 100.0);
1283 bool is_invertible
= uninvertible
.GetInverse(&inverse_of_uninvertible
);
1284 EXPECT_FALSE(is_invertible
);
1285 EXPECT_TRUE(inverse_of_uninvertible
.IsIdentity());
1286 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, inverse_of_uninvertible
);
1287 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, inverse_of_uninvertible
);
1288 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, inverse_of_uninvertible
);
1289 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, inverse_of_uninvertible
);
1293 TEST(XFormTest
, verifyBackfaceVisibilityBasicCases
) {
1294 Transform transform
;
1296 transform
.MakeIdentity();
1297 EXPECT_FALSE(transform
.IsBackFaceVisible());
1299 transform
.MakeIdentity();
1300 transform
.RotateAboutYAxis(80.0);
1301 EXPECT_FALSE(transform
.IsBackFaceVisible());
1303 transform
.MakeIdentity();
1304 transform
.RotateAboutYAxis(100.0);
1305 EXPECT_TRUE(transform
.IsBackFaceVisible());
1307 // Edge case, 90 degree rotation should return false.
1308 transform
.MakeIdentity();
1309 transform
.RotateAboutYAxis(90.0);
1310 EXPECT_FALSE(transform
.IsBackFaceVisible());
1313 TEST(XFormTest
, verifyBackfaceVisibilityForPerspective
) {
1314 Transform layer_space_to_projection_plane
;
1316 // This tests if IsBackFaceVisible works properly under perspective
1317 // transforms. Specifically, layers that may have their back face visible in
1318 // orthographic projection, may not actually have back face visible under
1319 // perspective projection.
1321 // Case 1: Layer is rotated by slightly more than 90 degrees, at the center
1322 // of the prespective projection. In this case, the layer's back-side
1323 // is visible to the camera.
1324 layer_space_to_projection_plane
.MakeIdentity();
1325 layer_space_to_projection_plane
.ApplyPerspectiveDepth(1.0);
1326 layer_space_to_projection_plane
.Translate3d(0.0, 0.0, 0.0);
1327 layer_space_to_projection_plane
.RotateAboutYAxis(100.0);
1328 EXPECT_TRUE(layer_space_to_projection_plane
.IsBackFaceVisible());
1330 // Case 2: Layer is rotated by slightly more than 90 degrees, but shifted off
1331 // to the side of the camera. Because of the wide field-of-view, the
1332 // layer's front side is still visible.
1334 // |<-- front side of layer is visible to camera
1339 // |\ /<-- camera field of view
1341 // back side of layer -->| \ /
1342 // \./ <-- camera origin
1344 layer_space_to_projection_plane
.MakeIdentity();
1345 layer_space_to_projection_plane
.ApplyPerspectiveDepth(1.0);
1346 layer_space_to_projection_plane
.Translate3d(-10.0, 0.0, 0.0);
1347 layer_space_to_projection_plane
.RotateAboutYAxis(100.0);
1348 EXPECT_FALSE(layer_space_to_projection_plane
.IsBackFaceVisible());
1350 // Case 3: Additionally rotating the layer by 180 degrees should of course
1351 // show the opposite result of case 2.
1352 layer_space_to_projection_plane
.RotateAboutYAxis(180.0);
1353 EXPECT_TRUE(layer_space_to_projection_plane
.IsBackFaceVisible());
1356 TEST(XFormTest
, verifyDefaultConstructorCreatesIdentityMatrix
) {
1358 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1359 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1360 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1361 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1362 EXPECT_TRUE(A
.IsIdentity());
1365 TEST(XFormTest
, verifyCopyConstructor
) {
1367 InitializeTestMatrix(&A
);
1369 // Copy constructor should produce exact same elements as matrix A.
1371 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, B
);
1372 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, B
);
1373 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, B
);
1374 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, B
);
1377 TEST(XFormTest
, verifyConstructorFor16Elements
) {
1378 Transform
transform(1.0, 2.0, 3.0, 4.0,
1380 9.0, 10.0, 11.0, 12.0,
1381 13.0, 14.0, 15.0, 16.0);
1383 EXPECT_ROW1_EQ(1.0f
, 2.0f
, 3.0f
, 4.0f
, transform
);
1384 EXPECT_ROW2_EQ(5.0f
, 6.0f
, 7.0f
, 8.0f
, transform
);
1385 EXPECT_ROW3_EQ(9.0f
, 10.0f
, 11.0f
, 12.0f
, transform
);
1386 EXPECT_ROW4_EQ(13.0f
, 14.0f
, 15.0f
, 16.0f
, transform
);
1389 TEST(XFormTest
, verifyConstructorFor2dElements
) {
1390 Transform
transform(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
1392 EXPECT_ROW1_EQ(1.0f
, 2.0f
, 0.0f
, 5.0f
, transform
);
1393 EXPECT_ROW2_EQ(3.0f
, 4.0f
, 0.0f
, 6.0f
, transform
);
1394 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, transform
);
1395 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, transform
);
1399 TEST(XFormTest
, verifyAssignmentOperator
) {
1401 InitializeTestMatrix(&A
);
1403 InitializeTestMatrix2(&B
);
1405 InitializeTestMatrix2(&C
);
1408 // Both B and C should now have been re-assigned to the value of A.
1409 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, B
);
1410 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, B
);
1411 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, B
);
1412 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, B
);
1414 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, C
);
1415 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, C
);
1416 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, C
);
1417 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, C
);
1420 TEST(XFormTest
, verifyEqualsBooleanOperator
) {
1422 InitializeTestMatrix(&A
);
1425 InitializeTestMatrix(&B
);
1426 EXPECT_TRUE(A
== B
);
1428 // Modifying multiple elements should cause equals operator to return false.
1430 InitializeTestMatrix2(&C
);
1431 EXPECT_FALSE(A
== C
);
1433 // Modifying any one individual element should cause equals operator to
1437 D
.matrix().setDouble(0, 0, 0.0);
1438 EXPECT_FALSE(A
== D
);
1441 D
.matrix().setDouble(1, 0, 0.0);
1442 EXPECT_FALSE(A
== D
);
1445 D
.matrix().setDouble(2, 0, 0.0);
1446 EXPECT_FALSE(A
== D
);
1449 D
.matrix().setDouble(3, 0, 0.0);
1450 EXPECT_FALSE(A
== D
);
1453 D
.matrix().setDouble(0, 1, 0.0);
1454 EXPECT_FALSE(A
== D
);
1457 D
.matrix().setDouble(1, 1, 0.0);
1458 EXPECT_FALSE(A
== D
);
1461 D
.matrix().setDouble(2, 1, 0.0);
1462 EXPECT_FALSE(A
== D
);
1465 D
.matrix().setDouble(3, 1, 0.0);
1466 EXPECT_FALSE(A
== D
);
1469 D
.matrix().setDouble(0, 2, 0.0);
1470 EXPECT_FALSE(A
== D
);
1473 D
.matrix().setDouble(1, 2, 0.0);
1474 EXPECT_FALSE(A
== D
);
1477 D
.matrix().setDouble(2, 2, 0.0);
1478 EXPECT_FALSE(A
== D
);
1481 D
.matrix().setDouble(3, 2, 0.0);
1482 EXPECT_FALSE(A
== D
);
1485 D
.matrix().setDouble(0, 3, 0.0);
1486 EXPECT_FALSE(A
== D
);
1489 D
.matrix().setDouble(1, 3, 0.0);
1490 EXPECT_FALSE(A
== D
);
1493 D
.matrix().setDouble(2, 3, 0.0);
1494 EXPECT_FALSE(A
== D
);
1497 D
.matrix().setDouble(3, 3, 0.0);
1498 EXPECT_FALSE(A
== D
);
1501 TEST(XFormTest
, verifyMultiplyOperator
) {
1503 InitializeTestMatrix(&A
);
1506 InitializeTestMatrix2(&B
);
1508 Transform C
= A
* B
;
1509 EXPECT_ROW1_EQ(2036.0f
, 2292.0f
, 2548.0f
, 2804.0f
, C
);
1510 EXPECT_ROW2_EQ(2162.0f
, 2434.0f
, 2706.0f
, 2978.0f
, C
);
1511 EXPECT_ROW3_EQ(2288.0f
, 2576.0f
, 2864.0f
, 3152.0f
, C
);
1512 EXPECT_ROW4_EQ(2414.0f
, 2718.0f
, 3022.0f
, 3326.0f
, C
);
1514 // Just an additional sanity check; matrix multiplication is not commutative.
1515 EXPECT_FALSE(A
* B
== B
* A
);
1518 TEST(XFormTest
, verifyMultiplyAndAssignOperator
) {
1520 InitializeTestMatrix(&A
);
1523 InitializeTestMatrix2(&B
);
1526 EXPECT_ROW1_EQ(2036.0f
, 2292.0f
, 2548.0f
, 2804.0f
, A
);
1527 EXPECT_ROW2_EQ(2162.0f
, 2434.0f
, 2706.0f
, 2978.0f
, A
);
1528 EXPECT_ROW3_EQ(2288.0f
, 2576.0f
, 2864.0f
, 3152.0f
, A
);
1529 EXPECT_ROW4_EQ(2414.0f
, 2718.0f
, 3022.0f
, 3326.0f
, A
);
1531 // Just an additional sanity check; matrix multiplication is not commutative.
1536 EXPECT_FALSE(C
== D
);
1539 TEST(XFormTest
, verifyMatrixMultiplication
) {
1541 InitializeTestMatrix(&A
);
1544 InitializeTestMatrix2(&B
);
1546 A
.PreconcatTransform(B
);
1547 EXPECT_ROW1_EQ(2036.0f
, 2292.0f
, 2548.0f
, 2804.0f
, A
);
1548 EXPECT_ROW2_EQ(2162.0f
, 2434.0f
, 2706.0f
, 2978.0f
, A
);
1549 EXPECT_ROW3_EQ(2288.0f
, 2576.0f
, 2864.0f
, 3152.0f
, A
);
1550 EXPECT_ROW4_EQ(2414.0f
, 2718.0f
, 3022.0f
, 3326.0f
, A
);
1553 TEST(XFormTest
, verifyMakeIdentiy
) {
1555 InitializeTestMatrix(&A
);
1557 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1558 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1559 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1560 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1561 EXPECT_TRUE(A
.IsIdentity());
1564 TEST(XFormTest
, verifyTranslate
) {
1566 A
.Translate(2.0, 3.0);
1567 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 2.0f
, A
);
1568 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 3.0f
, A
);
1569 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1570 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1572 // Verify that Translate() post-multiplies the existing matrix.
1575 A
.Translate(2.0, 3.0);
1576 EXPECT_ROW1_EQ(5.0f
, 0.0f
, 0.0f
, 10.0f
, A
);
1577 EXPECT_ROW2_EQ(0.0f
, 5.0f
, 0.0f
, 15.0f
, A
);
1578 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1579 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1582 TEST(XFormTest
, verifyTranslate3d
) {
1584 A
.Translate3d(2.0, 3.0, 4.0);
1585 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 2.0f
, A
);
1586 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 3.0f
, A
);
1587 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 4.0f
, A
);
1588 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1590 // Verify that Translate3d() post-multiplies the existing matrix.
1592 A
.Scale3d(6.0, 7.0, 8.0);
1593 A
.Translate3d(2.0, 3.0, 4.0);
1594 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 12.0f
, A
);
1595 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 21.0f
, A
);
1596 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 32.0f
, A
);
1597 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1600 TEST(XFormTest
, verifyScale
) {
1603 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1604 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 0.0f
, A
);
1605 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1606 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1608 // Verify that Scale() post-multiplies the existing matrix.
1610 A
.Translate3d(2.0, 3.0, 4.0);
1612 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 2.0f
, A
);
1613 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 3.0f
, A
);
1614 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 4.0f
, A
);
1615 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1618 TEST(XFormTest
, verifyScale3d
) {
1620 A
.Scale3d(6.0, 7.0, 8.0);
1621 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1622 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 0.0f
, A
);
1623 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1624 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1626 // Verify that scale3d() post-multiplies the existing matrix.
1628 A
.Translate3d(2.0, 3.0, 4.0);
1629 A
.Scale3d(6.0, 7.0, 8.0);
1630 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 2.0f
, A
);
1631 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 3.0f
, A
);
1632 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 4.0f
, A
);
1633 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1636 TEST(XFormTest
, verifyRotate
) {
1639 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1640 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1641 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1642 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1644 // Verify that Rotate() post-multiplies the existing matrix.
1646 A
.Scale3d(6.0, 7.0, 8.0);
1648 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1649 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1650 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1651 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1654 TEST(XFormTest
, verifyRotateAboutXAxis
) {
1656 double sin45
= 0.5 * sqrt(2.0);
1657 double cos45
= sin45
;
1660 A
.RotateAboutXAxis(90.0);
1661 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1662 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A
, ERROR_THRESHOLD
);
1663 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1664 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1667 A
.RotateAboutXAxis(45.0);
1668 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1669 EXPECT_ROW2_NEAR(0.0, cos45
, -sin45
, 0.0, A
, ERROR_THRESHOLD
);
1670 EXPECT_ROW3_NEAR(0.0, sin45
, cos45
, 0.0, A
, ERROR_THRESHOLD
);
1671 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1673 // Verify that RotateAboutXAxis(angle) post-multiplies the existing matrix.
1675 A
.Scale3d(6.0, 7.0, 8.0);
1676 A
.RotateAboutXAxis(90.0);
1677 EXPECT_ROW1_NEAR(6.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1678 EXPECT_ROW2_NEAR(0.0, 0.0, -7.0, 0.0, A
, ERROR_THRESHOLD
);
1679 EXPECT_ROW3_NEAR(0.0, 8.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1680 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1683 TEST(XFormTest
, verifyRotateAboutYAxis
) {
1685 double sin45
= 0.5 * sqrt(2.0);
1686 double cos45
= sin45
;
1688 // Note carefully, the expected pattern is inverted compared to rotating
1689 // about x axis or z axis.
1691 A
.RotateAboutYAxis(90.0);
1692 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A
, ERROR_THRESHOLD
);
1693 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1694 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1695 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1698 A
.RotateAboutYAxis(45.0);
1699 EXPECT_ROW1_NEAR(cos45
, 0.0, sin45
, 0.0, A
, ERROR_THRESHOLD
);
1700 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1701 EXPECT_ROW3_NEAR(-sin45
, 0.0, cos45
, 0.0, A
, ERROR_THRESHOLD
);
1702 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1704 // Verify that RotateAboutYAxis(angle) post-multiplies the existing matrix.
1706 A
.Scale3d(6.0, 7.0, 8.0);
1707 A
.RotateAboutYAxis(90.0);
1708 EXPECT_ROW1_NEAR(0.0, 0.0, 6.0, 0.0, A
, ERROR_THRESHOLD
);
1709 EXPECT_ROW2_NEAR(0.0, 7.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1710 EXPECT_ROW3_NEAR(-8.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1711 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1714 TEST(XFormTest
, verifyRotateAboutZAxis
) {
1716 double sin45
= 0.5 * sqrt(2.0);
1717 double cos45
= sin45
;
1720 A
.RotateAboutZAxis(90.0);
1721 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1722 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1723 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1724 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1727 A
.RotateAboutZAxis(45.0);
1728 EXPECT_ROW1_NEAR(cos45
, -sin45
, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1729 EXPECT_ROW2_NEAR(sin45
, cos45
, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1730 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1731 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1733 // Verify that RotateAboutZAxis(angle) post-multiplies the existing matrix.
1735 A
.Scale3d(6.0, 7.0, 8.0);
1736 A
.RotateAboutZAxis(90.0);
1737 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1738 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
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
);
1743 TEST(XFormTest
, verifyRotateAboutForAlignedAxes
) {
1746 // Check rotation about z-axis
1748 A
.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
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 // Check rotation about x-axis
1756 A
.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1757 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1758 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A
, ERROR_THRESHOLD
);
1759 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1760 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1762 // Check rotation about y-axis. Note carefully, the expected pattern is
1763 // inverted compared to rotating about x axis or z axis.
1765 A
.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1766 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A
, ERROR_THRESHOLD
);
1767 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1768 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1769 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1771 // Verify that rotate3d(axis, angle) post-multiplies the existing matrix.
1773 A
.Scale3d(6.0, 7.0, 8.0);
1774 A
.RotateAboutZAxis(90.0);
1775 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1776 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A
, ERROR_THRESHOLD
);
1777 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1778 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1781 TEST(XFormTest
, verifyRotateAboutForArbitraryAxis
) {
1782 // Check rotation about an arbitrary non-axis-aligned vector.
1784 A
.RotateAbout(Vector3dF(1.0, 1.0, 1.0), 90.0);
1785 EXPECT_ROW1_NEAR(0.3333333333333334258519187,
1786 -0.2440169358562924717404030,
1787 0.9106836025229592124219380,
1788 0.0, A
, ERROR_THRESHOLD
);
1789 EXPECT_ROW2_NEAR(0.9106836025229592124219380,
1790 0.3333333333333334258519187,
1791 -0.2440169358562924717404030,
1792 0.0, A
, ERROR_THRESHOLD
);
1793 EXPECT_ROW3_NEAR(-0.2440169358562924717404030,
1794 0.9106836025229592124219380,
1795 0.3333333333333334258519187,
1796 0.0, A
, ERROR_THRESHOLD
);
1797 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1800 TEST(XFormTest
, verifyRotateAboutForDegenerateAxis
) {
1801 // Check rotation about a degenerate zero vector.
1802 // It is expected to skip applying the rotation.
1805 A
.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 45.0);
1806 // Verify that A remains unchanged.
1807 EXPECT_TRUE(A
.IsIdentity());
1809 InitializeTestMatrix(&A
);
1810 A
.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 35.0);
1812 // Verify that A remains unchanged.
1813 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 18.0f
, 22.0f
, A
);
1814 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 19.0f
, 23.0f
, A
);
1815 EXPECT_ROW3_EQ(12.0f
, 16.0f
, 20.0f
, 24.0f
, A
);
1816 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 21.0f
, 25.0f
, A
);
1819 TEST(XFormTest
, verifySkewX
) {
1822 EXPECT_ROW1_EQ(1.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1823 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1824 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1825 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1827 // Verify that skewX() post-multiplies the existing matrix. Row 1, column 2,
1828 // would incorrectly have value "7" if the matrix is pre-multiplied instead
1829 // of post-multiplied.
1831 A
.Scale3d(6.0, 7.0, 8.0);
1833 EXPECT_ROW1_EQ(6.0f
, 6.0f
, 0.0f
, 0.0f
, A
);
1834 EXPECT_ROW2_EQ(0.0f
, 7.0f
, 0.0f
, 0.0f
, A
);
1835 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 8.0f
, 0.0f
, A
);
1836 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1839 TEST(XFormTest
, verifySkewY
) {
1842 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1843 EXPECT_ROW2_EQ(1.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1844 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1845 EXPECT_ROW4_EQ(0.0f
, 0.0f
, 0.0f
, 1.0f
, A
);
1847 // Verify that skewY() post-multiplies the existing matrix. Row 2, column 1 ,
1848 // would incorrectly have value "6" if the matrix is pre-multiplied instead
1849 // of post-multiplied.
1851 A
.Scale3d(6.0, 7.0, 8.0);
1853 EXPECT_ROW1_EQ(6.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1854 EXPECT_ROW2_EQ(7.0f
, 7.0f
, 0.0f
, 0.0f
, A
);
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
, verifyPerspectiveDepth
) {
1861 A
.ApplyPerspectiveDepth(1.0);
1862 EXPECT_ROW1_EQ(1.0f
, 0.0f
, 0.0f
, 0.0f
, A
);
1863 EXPECT_ROW2_EQ(0.0f
, 1.0f
, 0.0f
, 0.0f
, A
);
1864 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
1865 EXPECT_ROW4_EQ(0.0f
, 0.0f
, -1.0f
, 1.0f
, A
);
1867 // Verify that PerspectiveDepth() post-multiplies the existing matrix.
1869 A
.Translate3d(2.0, 3.0, 4.0);
1870 A
.ApplyPerspectiveDepth(1.0);
1871 EXPECT_ROW1_EQ(1.0f
, 0.0f
, -2.0f
, 2.0f
, A
);
1872 EXPECT_ROW2_EQ(0.0f
, 1.0f
, -3.0f
, 3.0f
, A
);
1873 EXPECT_ROW3_EQ(0.0f
, 0.0f
, -3.0f
, 4.0f
, A
);
1874 EXPECT_ROW4_EQ(0.0f
, 0.0f
, -1.0f
, 1.0f
, A
);
1877 TEST(XFormTest
, verifyHasPerspective
) {
1879 A
.ApplyPerspectiveDepth(1.0);
1880 EXPECT_TRUE(A
.HasPerspective());
1883 A
.ApplyPerspectiveDepth(0.0);
1884 EXPECT_FALSE(A
.HasPerspective());
1887 A
.matrix().setDouble(3, 0, -1.0);
1888 EXPECT_TRUE(A
.HasPerspective());
1891 A
.matrix().setDouble(3, 1, -1.0);
1892 EXPECT_TRUE(A
.HasPerspective());
1895 A
.matrix().setDouble(3, 2, -0.3);
1896 EXPECT_TRUE(A
.HasPerspective());
1899 A
.matrix().setDouble(3, 3, 0.5);
1900 EXPECT_TRUE(A
.HasPerspective());
1903 A
.matrix().setDouble(3, 3, 0.0);
1904 EXPECT_TRUE(A
.HasPerspective());
1907 TEST(XFormTest
, verifyIsInvertible
) {
1910 // Translations, rotations, scales, skews and arbitrary combinations of them
1913 EXPECT_TRUE(A
.IsInvertible());
1916 A
.Translate3d(2.0, 3.0, 4.0);
1917 EXPECT_TRUE(A
.IsInvertible());
1920 A
.Scale3d(6.0, 7.0, 8.0);
1921 EXPECT_TRUE(A
.IsInvertible());
1924 A
.RotateAboutXAxis(10.0);
1925 A
.RotateAboutYAxis(20.0);
1926 A
.RotateAboutZAxis(30.0);
1927 EXPECT_TRUE(A
.IsInvertible());
1931 EXPECT_TRUE(A
.IsInvertible());
1933 // A perspective matrix (projection plane at z=0) is invertible. The
1934 // intuitive explanation is that perspective is eqivalent to a skew of the
1935 // w-axis; skews are invertible.
1937 A
.ApplyPerspectiveDepth(1.0);
1938 EXPECT_TRUE(A
.IsInvertible());
1940 // A "pure" perspective matrix derived by similar triangles, with m44() set
1941 // to zero (i.e. camera positioned at the origin), is not invertible.
1943 A
.ApplyPerspectiveDepth(1.0);
1944 A
.matrix().setDouble(3, 3, 0.0);
1945 EXPECT_FALSE(A
.IsInvertible());
1947 // Adding more to a non-invertible matrix will not make it invertible in the
1950 A
.ApplyPerspectiveDepth(1.0);
1951 A
.matrix().setDouble(3, 3, 0.0);
1952 A
.Scale3d(6.0, 7.0, 8.0);
1953 A
.RotateAboutXAxis(10.0);
1954 A
.RotateAboutYAxis(20.0);
1955 A
.RotateAboutZAxis(30.0);
1956 A
.Translate3d(6.0, 7.0, 8.0);
1957 EXPECT_FALSE(A
.IsInvertible());
1959 // A degenerate matrix of all zeros is not invertible.
1961 A
.matrix().setDouble(0, 0, 0.0);
1962 A
.matrix().setDouble(1, 1, 0.0);
1963 A
.matrix().setDouble(2, 2, 0.0);
1964 A
.matrix().setDouble(3, 3, 0.0);
1965 EXPECT_FALSE(A
.IsInvertible());
1968 TEST(XFormTest
, verifyIsIdentity
) {
1971 InitializeTestMatrix(&A
);
1972 EXPECT_FALSE(A
.IsIdentity());
1975 EXPECT_TRUE(A
.IsIdentity());
1977 // Modifying any one individual element should cause the matrix to no longer
1980 A
.matrix().setDouble(0, 0, 2.0);
1981 EXPECT_FALSE(A
.IsIdentity());
1984 A
.matrix().setDouble(1, 0, 2.0);
1985 EXPECT_FALSE(A
.IsIdentity());
1988 A
.matrix().setDouble(2, 0, 2.0);
1989 EXPECT_FALSE(A
.IsIdentity());
1992 A
.matrix().setDouble(3, 0, 2.0);
1993 EXPECT_FALSE(A
.IsIdentity());
1996 A
.matrix().setDouble(0, 1, 2.0);
1997 EXPECT_FALSE(A
.IsIdentity());
2000 A
.matrix().setDouble(1, 1, 2.0);
2001 EXPECT_FALSE(A
.IsIdentity());
2004 A
.matrix().setDouble(2, 1, 2.0);
2005 EXPECT_FALSE(A
.IsIdentity());
2008 A
.matrix().setDouble(3, 1, 2.0);
2009 EXPECT_FALSE(A
.IsIdentity());
2012 A
.matrix().setDouble(0, 2, 2.0);
2013 EXPECT_FALSE(A
.IsIdentity());
2016 A
.matrix().setDouble(1, 2, 2.0);
2017 EXPECT_FALSE(A
.IsIdentity());
2020 A
.matrix().setDouble(2, 2, 2.0);
2021 EXPECT_FALSE(A
.IsIdentity());
2024 A
.matrix().setDouble(3, 2, 2.0);
2025 EXPECT_FALSE(A
.IsIdentity());
2028 A
.matrix().setDouble(0, 3, 2.0);
2029 EXPECT_FALSE(A
.IsIdentity());
2032 A
.matrix().setDouble(1, 3, 2.0);
2033 EXPECT_FALSE(A
.IsIdentity());
2036 A
.matrix().setDouble(2, 3, 2.0);
2037 EXPECT_FALSE(A
.IsIdentity());
2040 A
.matrix().setDouble(3, 3, 2.0);
2041 EXPECT_FALSE(A
.IsIdentity());
2044 TEST(XFormTest
, verifyIsIdentityOrTranslation
) {
2047 InitializeTestMatrix(&A
);
2048 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2051 EXPECT_TRUE(A
.IsIdentityOrTranslation());
2053 // Modifying any non-translation components should cause
2054 // IsIdentityOrTranslation() to return false. NOTE: (0, 3), (1, 3), and
2055 // (2, 3) are the translation components, so modifying them should still
2058 A
.matrix().setDouble(0, 0, 2.0);
2059 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2062 A
.matrix().setDouble(1, 0, 2.0);
2063 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2066 A
.matrix().setDouble(2, 0, 2.0);
2067 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2070 A
.matrix().setDouble(3, 0, 2.0);
2071 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2074 A
.matrix().setDouble(0, 1, 2.0);
2075 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2078 A
.matrix().setDouble(1, 1, 2.0);
2079 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2082 A
.matrix().setDouble(2, 1, 2.0);
2083 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2086 A
.matrix().setDouble(3, 1, 2.0);
2087 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2090 A
.matrix().setDouble(0, 2, 2.0);
2091 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2094 A
.matrix().setDouble(1, 2, 2.0);
2095 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2098 A
.matrix().setDouble(2, 2, 2.0);
2099 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2102 A
.matrix().setDouble(3, 2, 2.0);
2103 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2105 // Note carefully - expecting true here.
2107 A
.matrix().setDouble(0, 3, 2.0);
2108 EXPECT_TRUE(A
.IsIdentityOrTranslation());
2110 // Note carefully - expecting true here.
2112 A
.matrix().setDouble(1, 3, 2.0);
2113 EXPECT_TRUE(A
.IsIdentityOrTranslation());
2115 // Note carefully - expecting true here.
2117 A
.matrix().setDouble(2, 3, 2.0);
2118 EXPECT_TRUE(A
.IsIdentityOrTranslation());
2121 A
.matrix().setDouble(3, 3, 2.0);
2122 EXPECT_FALSE(A
.IsIdentityOrTranslation());
2125 TEST(XFormTest
, verifyIsScaleOrTranslation
) {
2128 InitializeTestMatrix(&A
);
2129 EXPECT_FALSE(A
.IsScaleOrTranslation());
2132 EXPECT_TRUE(A
.IsScaleOrTranslation());
2134 // Modifying any non-scale or non-translation components should cause
2135 // IsScaleOrTranslation() to return false. (0, 0), (1, 1), (2, 2), (0, 3),
2136 // (1, 3), and (2, 3) are the scale and translation components, so
2137 // modifying them should still return true.
2139 // Note carefully - expecting true here.
2141 A
.matrix().setDouble(0, 0, 2.0);
2142 EXPECT_TRUE(A
.IsScaleOrTranslation());
2145 A
.matrix().setDouble(1, 0, 2.0);
2146 EXPECT_FALSE(A
.IsScaleOrTranslation());
2149 A
.matrix().setDouble(2, 0, 2.0);
2150 EXPECT_FALSE(A
.IsScaleOrTranslation());
2153 A
.matrix().setDouble(3, 0, 2.0);
2154 EXPECT_FALSE(A
.IsScaleOrTranslation());
2157 A
.matrix().setDouble(0, 1, 2.0);
2158 EXPECT_FALSE(A
.IsScaleOrTranslation());
2160 // Note carefully - expecting true here.
2162 A
.matrix().setDouble(1, 1, 2.0);
2163 EXPECT_TRUE(A
.IsScaleOrTranslation());
2166 A
.matrix().setDouble(2, 1, 2.0);
2167 EXPECT_FALSE(A
.IsScaleOrTranslation());
2170 A
.matrix().setDouble(3, 1, 2.0);
2171 EXPECT_FALSE(A
.IsScaleOrTranslation());
2174 A
.matrix().setDouble(0, 2, 2.0);
2175 EXPECT_FALSE(A
.IsScaleOrTranslation());
2178 A
.matrix().setDouble(1, 2, 2.0);
2179 EXPECT_FALSE(A
.IsScaleOrTranslation());
2181 // Note carefully - expecting true here.
2183 A
.matrix().setDouble(2, 2, 2.0);
2184 EXPECT_TRUE(A
.IsScaleOrTranslation());
2187 A
.matrix().setDouble(3, 2, 2.0);
2188 EXPECT_FALSE(A
.IsScaleOrTranslation());
2190 // Note carefully - expecting true here.
2192 A
.matrix().setDouble(0, 3, 2.0);
2193 EXPECT_TRUE(A
.IsScaleOrTranslation());
2195 // Note carefully - expecting true here.
2197 A
.matrix().setDouble(1, 3, 2.0);
2198 EXPECT_TRUE(A
.IsScaleOrTranslation());
2200 // Note carefully - expecting true here.
2202 A
.matrix().setDouble(2, 3, 2.0);
2203 EXPECT_TRUE(A
.IsScaleOrTranslation());
2206 A
.matrix().setDouble(3, 3, 2.0);
2207 EXPECT_FALSE(A
.IsScaleOrTranslation());
2210 TEST(XFormTest
, verifyFlattenTo2d
) {
2212 InitializeTestMatrix(&A
);
2215 EXPECT_ROW1_EQ(10.0f
, 14.0f
, 0.0f
, 22.0f
, A
);
2216 EXPECT_ROW2_EQ(11.0f
, 15.0f
, 0.0f
, 23.0f
, A
);
2217 EXPECT_ROW3_EQ(0.0f
, 0.0f
, 1.0f
, 0.0f
, A
);
2218 EXPECT_ROW4_EQ(13.0f
, 17.0f
, 0.0f
, 25.0f
, A
);