Only grant permissions to new extensions from sync if they have the expected version
[chromium-blink-merge.git] / ui / gfx / transform_unittest.cc
blob81333a39f6e62256b272fc49749f75e3bd690897
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"
10 #include <cmath>
11 #include <ostream>
12 #include <limits>
14 #include "base/basictypes.h"
15 #include "base/logging.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "ui/gfx/geometry/box_f.h"
18 #include "ui/gfx/geometry/point.h"
19 #include "ui/gfx/geometry/point3_f.h"
20 #include "ui/gfx/geometry/quad_f.h"
21 #include "ui/gfx/geometry/vector3d_f.h"
22 #include "ui/gfx/transform_util.h"
24 namespace gfx {
26 namespace {
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,
74 const Point3F& rhs) {
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)
86 return false;
89 return true;
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);
111 // Sanity check
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);
137 // Sanity check
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
173 #else
174 #define ERROR_THRESHOLD 1e-7
175 #endif
176 #define LOOSE_ERROR_THRESHOLD 1e-7
178 TEST(XFormTest, Equality) {
179 Transform lhs, rhs, interpolated;
180 rhs.matrix().set3x3(1, 2, 3,
181 4, 5, 6,
182 7, 8, 9);
183 interpolated = lhs;
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);
193 if (i == 100) {
194 EXPECT_TRUE(rhs == interpolated);
195 } else {
196 EXPECT_TRUE(rhs != interpolated);
199 lhs = Transform();
200 rhs = Transform();
201 for (int i = 1; i < 100; ++i) {
202 lhs.MakeIdentity();
203 rhs.MakeIdentity();
204 lhs.Translate(i, 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 {
214 int x1;
215 int y1;
216 float tx;
217 float ty;
218 int x2;
219 int y2;
220 } test_cases[] = {
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 },
224 { 0, 0,
225 std::numeric_limits<float>::quiet_NaN(),
226 std::numeric_limits<float>::quiet_NaN(),
227 10, 20 },
230 Transform xform;
231 for (size_t i = 0; i < arraysize(test_cases); ++i) {
232 const TestCase& value = test_cases[i];
233 Transform translation;
234 translation.Translate(value.tx, value.ty);
235 xform = translation * xform;
236 Point3F p1(value.x1, value.y1, 0);
237 Point3F p2(value.x2, value.y2, 0);
238 xform.TransformPoint(&p1);
239 if (value.tx == value.tx &&
240 value.ty == value.ty) {
241 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
246 TEST(XFormTest, ConcatScale) {
247 static const struct TestCase {
248 int before;
249 float scale;
250 int after;
251 } test_cases[] = {
252 { 1, 10.0f, 10 },
253 { 1, .1f, 1 },
254 { 1, 100.0f, 100 },
255 { 1, -1.0f, -100 },
256 { 1, std::numeric_limits<float>::quiet_NaN(), 1 }
259 Transform xform;
260 for (size_t i = 0; i < arraysize(test_cases); ++i) {
261 const TestCase& value = test_cases[i];
262 Transform scale;
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 {
276 int x1;
277 int y1;
278 float degrees;
279 int x2;
280 int y2;
281 } test_cases[] = {
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 }
290 Transform xform;
291 for (size_t i = 0; i < arraysize(test_cases); ++i) {
292 const TestCase& value = test_cases[i];
293 Transform rotation;
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 {
307 int x1; int y1;
308 float tx; float ty;
309 int x2; int y2;
310 } test_cases[] = {
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 },
314 { 0, 0,
315 std::numeric_limits<float>::quiet_NaN(),
316 std::numeric_limits<float>::quiet_NaN(),
317 0, 0 }
320 for (size_t i = 0; i < arraysize(test_cases); ++i) {
321 const TestCase& value = test_cases[i];
322 for (int k = 0; k < 3; ++k) {
323 Point3F p0, p1, p2;
324 Transform xform;
325 switch (k) {
326 case 0:
327 p1.SetPoint(value.x1, 0, 0);
328 p2.SetPoint(value.x2, 0, 0);
329 xform.Translate(value.tx, 0.0);
330 break;
331 case 1:
332 p1.SetPoint(0, value.y1, 0);
333 p2.SetPoint(0, value.y2, 0);
334 xform.Translate(0.0, value.ty);
335 break;
336 case 2:
337 p1.SetPoint(value.x1, value.y1, 0);
338 p2.SetPoint(value.x2, value.y2, 0);
339 xform.Translate(value.tx, value.ty);
340 break;
342 p0 = p1;
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 {
356 int before;
357 float s;
358 int after;
359 } test_cases[] = {
360 { 1, 10.0f, 10 },
361 { 1, 1.0f, 1 },
362 { 1, 0.0f, 0 },
363 { 0, 10.0f, 0 },
364 { 1, std::numeric_limits<float>::quiet_NaN(), 0 },
367 for (size_t i = 0; i < arraysize(test_cases); ++i) {
368 const TestCase& value = test_cases[i];
369 for (int k = 0; k < 3; ++k) {
370 Point3F p0, p1, p2;
371 Transform xform;
372 switch (k) {
373 case 0:
374 p1.SetPoint(value.before, 0, 0);
375 p2.SetPoint(value.after, 0, 0);
376 xform.Scale(value.s, 1.0);
377 break;
378 case 1:
379 p1.SetPoint(0, value.before, 0);
380 p2.SetPoint(0, value.after, 0);
381 xform.Scale(1.0, value.s);
382 break;
383 case 2:
384 p1.SetPoint(value.before, value.before, 0);
385 p2.SetPoint(value.after, value.after, 0);
386 xform.Scale(value.s, value.s);
387 break;
389 p0 = p1;
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 {
404 int x;
405 int y;
406 float degree;
407 int xprime;
408 int yprime;
409 } set_rotate_cases[] = {
410 { 100, 0, 90.0f, 0, 100 },
411 { 0, 0, 90.0f, 0, 0 },
412 { 0, 100, 90.0f, -100, 0 },
413 { 0, 1, -90.0f, 1, 0 },
414 { 100, 0, 0.0f, 100, 0 },
415 { 0, 0, 0.0f, 0, 0 },
416 { 0, 0, std::numeric_limits<float>::quiet_NaN(), 0, 0 },
417 { 100, 0, 360.0f, 100, 0 }
420 for (size_t i = 0; i < arraysize(set_rotate_cases); ++i) {
421 const SetRotateCase& value = set_rotate_cases[i];
422 Point3F p0;
423 Point3F p1(value.x, value.y, 0);
424 Point3F p2(value.xprime, value.yprime, 0);
425 p0 = p1;
426 Transform xform;
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));
438 // 2D tests
439 TEST(XFormTest, ConcatTranslate2D) {
440 static const struct TestCase {
441 int x1;
442 int y1;
443 float tx;
444 float ty;
445 int x2;
446 int y2;
447 } test_cases[] = {
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},
453 Transform xform;
454 for (size_t i = 0; i < arraysize(test_cases); ++i) {
455 const TestCase& value = test_cases[i];
456 Transform translation;
457 translation.Translate(value.tx, value.ty);
458 xform = translation * xform;
459 Point p1(value.x1, value.y1);
460 Point p2(value.x2, value.y2);
461 xform.TransformPoint(&p1);
462 if (value.tx == value.tx &&
463 value.ty == value.ty) {
464 EXPECT_EQ(p1.x(), p2.x());
465 EXPECT_EQ(p1.y(), p2.y());
470 TEST(XFormTest, ConcatScale2D) {
471 static const struct TestCase {
472 int before;
473 float scale;
474 int after;
475 } test_cases[] = {
476 { 1, 10.0f, 10},
477 { 1, .1f, 1},
478 { 1, 100.0f, 100},
479 { 1, -1.0f, -100},
482 Transform xform;
483 for (size_t i = 0; i < arraysize(test_cases); ++i) {
484 const TestCase& value = test_cases[i];
485 Transform scale;
486 scale.Scale(value.scale, value.scale);
487 xform = scale * xform;
488 Point p1(value.before, value.before);
489 Point p2(value.after, value.after);
490 xform.TransformPoint(&p1);
491 if (value.scale == value.scale) {
492 EXPECT_EQ(p1.x(), p2.x());
493 EXPECT_EQ(p1.y(), p2.y());
498 TEST(XFormTest, ConcatRotate2D) {
499 static const struct TestCase {
500 int x1;
501 int y1;
502 float degrees;
503 int x2;
504 int y2;
505 } test_cases[] = {
506 { 1, 0, 90.0f, 0, 1},
507 { 1, 0, -90.0f, 1, 0},
508 { 1, 0, 90.0f, 0, 1},
509 { 1, 0, 360.0f, 0, 1},
510 { 1, 0, 0.0f, 0, 1},
513 Transform xform;
514 for (size_t i = 0; i < arraysize(test_cases); ++i) {
515 const TestCase& value = test_cases[i];
516 Transform rotation;
517 rotation.Rotate(value.degrees);
518 xform = rotation * xform;
519 Point p1(value.x1, value.y1);
520 Point p2(value.x2, value.y2);
521 xform.TransformPoint(&p1);
522 if (value.degrees == value.degrees) {
523 EXPECT_EQ(p1.x(), p2.x());
524 EXPECT_EQ(p1.y(), p2.y());
529 TEST(XFormTest, SetTranslate2D) {
530 static const struct TestCase {
531 int x1; int y1;
532 float tx; float ty;
533 int x2; int y2;
534 } test_cases[] = {
535 { 0, 0, 10.0f, 20.0f, 10, 20},
536 { 10, 20, 10.0f, 20.0f, 20, 40},
537 { 10, 20, 0.0f, 0.0f, 10, 20},
540 for (size_t i = 0; i < arraysize(test_cases); ++i) {
541 const TestCase& value = test_cases[i];
542 for (int j = -1; j < 2; ++j) {
543 for (int k = 0; k < 3; ++k) {
544 float epsilon = 0.0001f;
545 Point p0, p1, p2;
546 Transform xform;
547 switch (k) {
548 case 0:
549 p1.SetPoint(value.x1, 0);
550 p2.SetPoint(value.x2, 0);
551 xform.Translate(value.tx + j * epsilon, 0.0);
552 break;
553 case 1:
554 p1.SetPoint(0, value.y1);
555 p2.SetPoint(0, value.y2);
556 xform.Translate(0.0, value.ty + j * epsilon);
557 break;
558 case 2:
559 p1.SetPoint(value.x1, value.y1);
560 p2.SetPoint(value.x2, value.y2);
561 xform.Translate(value.tx + j * epsilon,
562 value.ty + j * epsilon);
563 break;
565 p0 = p1;
566 xform.TransformPoint(&p1);
567 if (value.tx == value.tx &&
568 value.ty == value.ty) {
569 EXPECT_EQ(p1.x(), p2.x());
570 EXPECT_EQ(p1.y(), p2.y());
571 xform.TransformPointReverse(&p1);
572 EXPECT_EQ(p1.x(), p0.x());
573 EXPECT_EQ(p1.y(), p0.y());
580 TEST(XFormTest, SetScale2D) {
581 static const struct TestCase {
582 int before;
583 float s;
584 int after;
585 } test_cases[] = {
586 { 1, 10.0f, 10},
587 { 1, 1.0f, 1},
588 { 1, 0.0f, 0},
589 { 0, 10.0f, 0},
592 for (size_t i = 0; i < arraysize(test_cases); ++i) {
593 const TestCase& value = test_cases[i];
594 for (int j = -1; j < 2; ++j) {
595 for (int k = 0; k < 3; ++k) {
596 float epsilon = 0.0001f;
597 Point p0, p1, p2;
598 Transform xform;
599 switch (k) {
600 case 0:
601 p1.SetPoint(value.before, 0);
602 p2.SetPoint(value.after, 0);
603 xform.Scale(value.s + j * epsilon, 1.0);
604 break;
605 case 1:
606 p1.SetPoint(0, value.before);
607 p2.SetPoint(0, value.after);
608 xform.Scale(1.0, value.s + j * epsilon);
609 break;
610 case 2:
611 p1.SetPoint(value.before,
612 value.before);
613 p2.SetPoint(value.after,
614 value.after);
615 xform.Scale(value.s + j * epsilon,
616 value.s + j * epsilon);
617 break;
619 p0 = p1;
620 xform.TransformPoint(&p1);
621 if (value.s == value.s) {
622 EXPECT_EQ(p1.x(), p2.x());
623 EXPECT_EQ(p1.y(), p2.y());
624 if (value.s != 0.0f) {
625 xform.TransformPointReverse(&p1);
626 EXPECT_EQ(p1.x(), p0.x());
627 EXPECT_EQ(p1.y(), p0.y());
635 TEST(XFormTest, SetRotate2D) {
636 static const struct SetRotateCase {
637 int x;
638 int y;
639 float degree;
640 int xprime;
641 int yprime;
642 } set_rotate_cases[] = {
643 { 100, 0, 90.0f, 0, 100},
644 { 0, 0, 90.0f, 0, 0},
645 { 0, 100, 90.0f, -100, 0},
646 { 0, 1, -90.0f, 1, 0},
647 { 100, 0, 0.0f, 100, 0},
648 { 0, 0, 0.0f, 0, 0},
649 { 0, 0, std::numeric_limits<float>::quiet_NaN(), 0, 0},
650 { 100, 0, 360.0f, 100, 0}
653 for (size_t i = 0; i < arraysize(set_rotate_cases); ++i) {
654 const SetRotateCase& value = set_rotate_cases[i];
655 for (int j = 1; j >= -1; --j) {
656 float epsilon = 0.1f;
657 Point pt(value.x, value.y);
658 Transform xform;
659 // should be invariant to small floating point errors.
660 xform.Rotate(value.degree + j * epsilon);
661 // just want to make sure that we don't crash in the case of NaN.
662 if (value.degree == value.degree) {
663 xform.TransformPoint(&pt);
664 EXPECT_EQ(value.xprime, pt.x());
665 EXPECT_EQ(value.yprime, pt.y());
666 xform.TransformPointReverse(&pt);
667 EXPECT_EQ(pt.x(), value.x);
668 EXPECT_EQ(pt.y(), value.y);
674 TEST(XFormTest, TransformPointWithExtremePerspective) {
675 Point3F point(1.f, 1.f, 1.f);
676 Transform perspective;
677 perspective.ApplyPerspectiveDepth(1.f);
678 Point3F transformed = point;
679 perspective.TransformPoint(&transformed);
680 EXPECT_EQ(point.ToString(), transformed.ToString());
682 transformed = point;
683 perspective.MakeIdentity();
684 perspective.ApplyPerspectiveDepth(1.1f);
685 perspective.TransformPoint(&transformed);
686 EXPECT_FLOAT_EQ(11.f, transformed.x());
687 EXPECT_FLOAT_EQ(11.f, transformed.y());
688 EXPECT_FLOAT_EQ(11.f, transformed.z());
691 TEST(XFormTest, BlendTranslate) {
692 Transform from;
693 for (int i = -5; i < 15; ++i) {
694 Transform to;
695 to.Translate3d(1, 1, 1);
696 double t = i / 9.0;
697 EXPECT_TRUE(to.Blend(from, t));
698 EXPECT_FLOAT_EQ(t, to.matrix().get(0, 3));
699 EXPECT_FLOAT_EQ(t, to.matrix().get(1, 3));
700 EXPECT_FLOAT_EQ(t, to.matrix().get(2, 3));
704 TEST(XFormTest, BlendRotate) {
705 Vector3dF axes[] = {
706 Vector3dF(1, 0, 0),
707 Vector3dF(0, 1, 0),
708 Vector3dF(0, 0, 1),
709 Vector3dF(1, 1, 1)
711 Transform from;
712 for (size_t index = 0; index < arraysize(axes); ++index) {
713 for (int i = -5; i < 15; ++i) {
714 Transform to;
715 to.RotateAbout(axes[index], 90);
716 double t = i / 9.0;
717 EXPECT_TRUE(to.Blend(from, t));
719 Transform expected;
720 expected.RotateAbout(axes[index], 90 * t);
722 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
727 TEST(XFormTest, CanBlend180DegreeRotation) {
728 Vector3dF axes[] = {
729 Vector3dF(1, 0, 0),
730 Vector3dF(0, 1, 0),
731 Vector3dF(0, 0, 1),
732 Vector3dF(1, 1, 1)
734 Transform from;
735 for (size_t index = 0; index < arraysize(axes); ++index) {
736 for (int i = -5; i < 15; ++i) {
737 Transform to;
738 to.RotateAbout(axes[index], 180.0);
739 double t = i / 9.0;
740 EXPECT_TRUE(to.Blend(from, t));
742 // A 180 degree rotation is exactly opposite on the sphere, therefore
743 // either great circle arc to it is equivalent (and numerical precision
744 // will determine which is closer). Test both directions.
745 Transform expected1;
746 expected1.RotateAbout(axes[index], 180.0 * t);
747 Transform expected2;
748 expected2.RotateAbout(axes[index], -180.0 * t);
750 EXPECT_TRUE(MatricesAreNearlyEqual(expected1, to) ||
751 MatricesAreNearlyEqual(expected2, to))
752 << "axis: " << index << ", i: " << i;
757 #if defined(_WIN64)
758 // http://crbug.com/406574
759 #define MAYBE_BlendScale DISABLED_BlendScale
760 #else
761 #define MAYBE_BlendScale BlendScale
762 #endif
763 TEST(XFormTest, MAYBE_BlendScale) {
764 Transform from;
765 for (int i = -5; i < 15; ++i) {
766 Transform to;
767 to.Scale3d(5, 4, 3);
768 double t = i / 9.0;
769 EXPECT_TRUE(to.Blend(from, t));
770 EXPECT_FLOAT_EQ(t * 4 + 1, to.matrix().get(0, 0)) << "i: " << i;
771 EXPECT_FLOAT_EQ(t * 3 + 1, to.matrix().get(1, 1)) << "i: " << i;
772 EXPECT_FLOAT_EQ(t * 2 + 1, to.matrix().get(2, 2)) << "i: " << i;
776 TEST(XFormTest, BlendSkew) {
777 Transform from;
778 for (int i = 0; i < 2; ++i) {
779 Transform to;
780 to.Skew(10, 5);
781 double t = i;
782 Transform expected;
783 expected.Skew(t * 10, t * 5);
784 EXPECT_TRUE(to.Blend(from, t));
785 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
789 TEST(XFormTest, ExtrapolateSkew) {
790 Transform from;
791 for (int i = -1; i < 2; ++i) {
792 Transform to;
793 to.Skew(20, 0);
794 double t = i;
795 Transform expected;
796 expected.Skew(t * 20, t * 0);
797 EXPECT_TRUE(to.Blend(from, t));
798 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
802 #if defined(_WIN64)
803 // http://crbug.com/406574
804 #define MAYBE_BlendPerspective DISABLED_BlendPerspective
805 #else
806 #define MAYBE_BlendPerspective BlendPerspective
807 #endif
808 TEST(XFormTest, MAYBE_BlendPerspective) {
809 Transform from;
810 from.ApplyPerspectiveDepth(200);
811 for (int i = -1; i < 3; ++i) {
812 Transform to;
813 to.ApplyPerspectiveDepth(800);
814 double t = i;
815 double depth = 1.0 / ((1.0 / 200) * (1.0 - t) + (1.0 / 800) * t);
816 Transform expected;
817 expected.ApplyPerspectiveDepth(depth);
818 EXPECT_TRUE(to.Blend(from, t));
819 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
823 TEST(XFormTest, BlendIdentity) {
824 Transform from;
825 Transform to;
826 EXPECT_TRUE(to.Blend(from, 0.5));
827 EXPECT_EQ(to, from);
830 TEST(XFormTest, CannotBlendSingularMatrix) {
831 Transform from;
832 Transform to;
833 to.matrix().set(1, 1, SkDoubleToMScalar(0));
834 EXPECT_FALSE(to.Blend(from, 0.5));
837 TEST(XFormTest, VerifyBlendForTranslation) {
838 Transform from;
839 from.Translate3d(100.0, 200.0, 100.0);
841 Transform to;
843 to.Translate3d(200.0, 100.0, 300.0);
844 to.Blend(from, 0.0);
845 EXPECT_EQ(from, to);
847 to = Transform();
848 to.Translate3d(200.0, 100.0, 300.0);
849 to.Blend(from, 0.25);
850 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 125.0f, to);
851 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 175.0f, to);
852 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 150.0f, to);
853 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
855 to = Transform();
856 to.Translate3d(200.0, 100.0, 300.0);
857 to.Blend(from, 0.5);
858 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 150.0f, to);
859 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 150.0f, to);
860 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 200.0f, to);
861 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
863 to = Transform();
864 to.Translate3d(200.0, 100.0, 300.0);
865 to.Blend(from, 1.0);
866 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 200.0f, to);
867 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 100.0f, to);
868 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 300.0f, to);
869 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
872 TEST(XFormTest, VerifyBlendForScale) {
873 Transform from;
874 from.Scale3d(100.0, 200.0, 100.0);
876 Transform to;
878 to.Scale3d(200.0, 100.0, 300.0);
879 to.Blend(from, 0.0);
880 EXPECT_EQ(from, to);
882 to = Transform();
883 to.Scale3d(200.0, 100.0, 300.0);
884 to.Blend(from, 0.25);
885 EXPECT_ROW1_EQ(125.0f, 0.0f, 0.0f, 0.0f, to);
886 EXPECT_ROW2_EQ(0.0f, 175.0f, 0.0f, 0.0f, to);
887 EXPECT_ROW3_EQ(0.0f, 0.0f, 150.0f, 0.0f, to);
888 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
890 to = Transform();
891 to.Scale3d(200.0, 100.0, 300.0);
892 to.Blend(from, 0.5);
893 EXPECT_ROW1_EQ(150.0f, 0.0f, 0.0f, 0.0f, to);
894 EXPECT_ROW2_EQ(0.0f, 150.0f, 0.0f, 0.0f, to);
895 EXPECT_ROW3_EQ(0.0f, 0.0f, 200.0f, 0.0f, to);
896 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
898 to = Transform();
899 to.Scale3d(200.0, 100.0, 300.0);
900 to.Blend(from, 1.0);
901 EXPECT_ROW1_EQ(200.0f, 0.0f, 0.0f, 0.0f, to);
902 EXPECT_ROW2_EQ(0.0f, 100.0f, 0.0f, 0.0f, to);
903 EXPECT_ROW3_EQ(0.0f, 0.0f, 300.0f, 0.0f, to);
904 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
907 TEST(XFormTest, VerifyBlendForSkew) {
908 // Along X axis only
909 Transform from;
910 from.Skew(0.0, 0.0);
912 Transform to;
914 to.Skew(45.0, 0.0);
915 to.Blend(from, 0.0);
916 EXPECT_EQ(from, to);
918 to = Transform();
919 to.Skew(45.0, 0.0);
920 to.Blend(from, 0.5);
921 EXPECT_ROW1_EQ(1.0f, 0.5f, 0.0f, 0.0f, to);
922 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
923 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
924 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
926 to = Transform();
927 to.Skew(45.0, 0.0);
928 to.Blend(from, 0.25);
929 EXPECT_ROW1_EQ(1.0f, 0.25f, 0.0f, 0.0f, to);
930 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
931 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
932 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
934 to = Transform();
935 to.Skew(45.0, 0.0);
936 to.Blend(from, 1.0);
937 EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, to);
938 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
939 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
940 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
942 // NOTE CAREFULLY: Decomposition of skew and rotation terms of the matrix
943 // is inherently underconstrained, and so it does not always compute the
944 // originally intended skew parameters. The current implementation uses QR
945 // decomposition, which decomposes the shear into a rotation + non-uniform
946 // scale.
948 // It is unlikely that the decomposition implementation will need to change
949 // very often, so to get any test coverage, the compromise is to verify the
950 // exact matrix that the.Blend() operation produces.
952 // This problem also potentially exists for skew along the X axis, but the
953 // current QR decomposition implementation just happens to decompose those
954 // test matrices intuitively.
956 // Unfortunately, this case suffers from uncomfortably large precision
957 // error.
959 from = Transform();
960 from.Skew(0.0, 0.0);
962 to = Transform();
964 to.Skew(0.0, 45.0);
965 to.Blend(from, 0.0);
966 EXPECT_EQ(from, to);
968 to = Transform();
969 to.Skew(0.0, 45.0);
970 to.Blend(from, 0.25);
971 EXPECT_ROW1_NEAR(1.0823489449280947471976333,
972 0.0464370719145053845178239,
973 0.0,
974 0.0,
976 LOOSE_ERROR_THRESHOLD);
977 EXPECT_ROW2_NEAR(0.2152925909665224513123150,
978 0.9541702441750861130032035,
979 0.0,
980 0.0,
982 LOOSE_ERROR_THRESHOLD);
983 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
984 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
986 to = Transform();
987 to.Skew(0.0, 45.0);
988 to.Blend(from, 0.5);
989 EXPECT_ROW1_NEAR(1.1152212925809066312865525,
990 0.0676495144007326631996335,
991 0.0,
992 0.0,
994 LOOSE_ERROR_THRESHOLD);
995 EXPECT_ROW2_NEAR(0.4619397844342648662419037,
996 0.9519009045724774464858342,
997 0.0,
998 0.0,
1000 LOOSE_ERROR_THRESHOLD);
1001 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
1002 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1004 to = Transform();
1005 to.Skew(0.0, 45.0);
1006 to.Blend(from, 1.0);
1007 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD);
1008 EXPECT_ROW2_NEAR(1.0, 1.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD);
1009 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
1010 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1013 #if defined(_WIN64)
1014 // http://crbug.com/406574
1015 #define MAYBE_VerifyBlendForRotationAboutX DISABLED_VerifyBlendForRotationAboutX
1016 #else
1017 #define MAYBE_VerifyBlendForRotationAboutX VerifyBlendForRotationAboutX
1018 #endif
1019 TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutX) {
1020 // Even though.Blending uses quaternions, axis-aligned rotations should.
1021 // Blend the same with quaternions or Euler angles. So we can test
1022 // rotation.Blending by comparing against manually specified matrices from
1023 // Euler angles.
1025 Transform from;
1026 from.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 0.0);
1028 Transform to;
1030 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1031 to.Blend(from, 0.0);
1032 EXPECT_EQ(from, to);
1034 double expectedRotationAngle = 22.5 * M_PI / 180.0;
1035 to = Transform();
1036 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1037 to.Blend(from, 0.25);
1038 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1039 EXPECT_ROW2_NEAR(0.0,
1040 std::cos(expectedRotationAngle),
1041 -std::sin(expectedRotationAngle),
1042 0.0,
1044 ERROR_THRESHOLD);
1045 EXPECT_ROW3_NEAR(0.0,
1046 std::sin(expectedRotationAngle),
1047 std::cos(expectedRotationAngle),
1048 0.0,
1050 ERROR_THRESHOLD);
1051 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1053 expectedRotationAngle = 45.0 * M_PI / 180.0;
1054 to = Transform();
1055 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1056 to.Blend(from, 0.5);
1057 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1058 EXPECT_ROW2_NEAR(0.0,
1059 std::cos(expectedRotationAngle),
1060 -std::sin(expectedRotationAngle),
1061 0.0,
1063 ERROR_THRESHOLD);
1064 EXPECT_ROW3_NEAR(0.0,
1065 std::sin(expectedRotationAngle),
1066 std::cos(expectedRotationAngle),
1067 0.0,
1069 ERROR_THRESHOLD);
1070 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1072 to = Transform();
1073 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1074 to.Blend(from, 1.0);
1075 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1076 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, to, ERROR_THRESHOLD);
1077 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1078 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1081 #if defined(_WIN64)
1082 // http://crbug.com/406574
1083 #define MAYBE_VerifyBlendForRotationAboutY DISABLED_VerifyBlendForRotationAboutY
1084 #else
1085 #define MAYBE_VerifyBlendForRotationAboutY VerifyBlendForRotationAboutY
1086 #endif
1087 TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutY) {
1088 Transform from;
1089 from.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 0.0);
1091 Transform to;
1093 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1094 to.Blend(from, 0.0);
1095 EXPECT_EQ(from, to);
1097 double expectedRotationAngle = 22.5 * M_PI / 180.0;
1098 to = Transform();
1099 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1100 to.Blend(from, 0.25);
1101 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1102 0.0,
1103 std::sin(expectedRotationAngle),
1104 0.0,
1106 ERROR_THRESHOLD);
1107 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1108 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle),
1109 0.0,
1110 std::cos(expectedRotationAngle),
1111 0.0,
1113 ERROR_THRESHOLD);
1114 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1116 expectedRotationAngle = 45.0 * M_PI / 180.0;
1117 to = Transform();
1118 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1119 to.Blend(from, 0.5);
1120 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1121 0.0,
1122 std::sin(expectedRotationAngle),
1123 0.0,
1125 ERROR_THRESHOLD);
1126 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1127 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle),
1128 0.0,
1129 std::cos(expectedRotationAngle),
1130 0.0,
1132 ERROR_THRESHOLD);
1133 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1135 to = Transform();
1136 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1137 to.Blend(from, 1.0);
1138 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1139 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1140 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1141 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1144 #if defined(_WIN64)
1145 // http://crbug.com/406574
1146 #define MAYBE_VerifyBlendForRotationAboutZ DISABLED_VerifyBlendForRotationAboutZ
1147 #else
1148 #define MAYBE_VerifyBlendForRotationAboutZ VerifyBlendForRotationAboutZ
1149 #endif
1150 TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutZ) {
1151 Transform from;
1152 from.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 0.0);
1154 Transform to;
1156 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1157 to.Blend(from, 0.0);
1158 EXPECT_EQ(from, to);
1160 double expectedRotationAngle = 22.5 * M_PI / 180.0;
1161 to = Transform();
1162 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1163 to.Blend(from, 0.25);
1164 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1165 -std::sin(expectedRotationAngle),
1166 0.0,
1167 0.0,
1169 ERROR_THRESHOLD);
1170 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle),
1171 std::cos(expectedRotationAngle),
1172 0.0,
1173 0.0,
1175 ERROR_THRESHOLD);
1176 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1177 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1179 expectedRotationAngle = 45.0 * M_PI / 180.0;
1180 to = Transform();
1181 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1182 to.Blend(from, 0.5);
1183 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1184 -std::sin(expectedRotationAngle),
1185 0.0,
1186 0.0,
1188 ERROR_THRESHOLD);
1189 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle),
1190 std::cos(expectedRotationAngle),
1191 0.0,
1192 0.0,
1194 ERROR_THRESHOLD);
1195 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1196 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1198 to = Transform();
1199 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1200 to.Blend(from, 1.0);
1201 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1202 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1203 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1204 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1207 TEST(XFormTest, VerifyBlendForCompositeTransform) {
1208 // Verify that the.Blending was done with a decomposition in correct order
1209 // by blending a composite transform. Using matrix x vector notation
1210 // (Ax = b, where x is column vector), the ordering should be:
1211 // perspective * translation * rotation * skew * scale
1213 // It is not as important (or meaningful) to check intermediate
1214 // interpolations; order of operations will be tested well enough by the
1215 // end cases that are easier to specify.
1217 Transform from;
1218 Transform to;
1220 Transform expectedEndOfAnimation;
1221 expectedEndOfAnimation.ApplyPerspectiveDepth(1.0);
1222 expectedEndOfAnimation.Translate3d(10.0, 20.0, 30.0);
1223 expectedEndOfAnimation.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 25.0);
1224 expectedEndOfAnimation.Skew(0.0, 45.0);
1225 expectedEndOfAnimation.Scale3d(6.0, 7.0, 8.0);
1227 to = expectedEndOfAnimation;
1228 to.Blend(from, 0.0);
1229 EXPECT_EQ(from, to);
1231 to = expectedEndOfAnimation;
1232 // We short circuit if blend is >= 1, so to check the numerics, we will
1233 // check that we get close to what we expect when we're nearly done
1234 // interpolating.
1235 to.Blend(from, .99999f);
1237 // Recomposing the matrix results in a normalized matrix, so to verify we
1238 // need to normalize the expectedEndOfAnimation before comparing elements.
1239 // Normalizing means dividing everything by expectedEndOfAnimation.m44().
1240 Transform normalizedExpectedEndOfAnimation = expectedEndOfAnimation;
1241 Transform normalizationMatrix;
1242 normalizationMatrix.matrix().set(
1243 0.0,
1244 0.0,
1245 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1246 normalizationMatrix.matrix().set(
1247 1.0,
1248 1.0,
1249 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1250 normalizationMatrix.matrix().set(
1251 2.0,
1252 2.0,
1253 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1254 normalizationMatrix.matrix().set(
1255 3.0,
1256 3.0,
1257 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1258 normalizedExpectedEndOfAnimation.PreconcatTransform(normalizationMatrix);
1260 EXPECT_TRUE(MatricesAreNearlyEqual(normalizedExpectedEndOfAnimation, to));
1263 TEST(XFormTest, DecomposedTransformCtor) {
1264 DecomposedTransform decomp;
1265 for (int i = 0; i < 3; ++i) {
1266 EXPECT_EQ(0.0, decomp.translate[i]);
1267 EXPECT_EQ(1.0, decomp.scale[i]);
1268 EXPECT_EQ(0.0, decomp.skew[i]);
1269 EXPECT_EQ(0.0, decomp.quaternion[i]);
1270 EXPECT_EQ(0.0, decomp.perspective[i]);
1272 EXPECT_EQ(1.0, decomp.quaternion[3]);
1273 EXPECT_EQ(1.0, decomp.perspective[3]);
1274 Transform identity;
1275 Transform composed = ComposeTransform(decomp);
1276 EXPECT_TRUE(MatricesAreNearlyEqual(identity, composed));
1279 TEST(XFormTest, FactorTRS) {
1280 for (int degrees = 0; degrees < 180; ++degrees) {
1281 // build a transformation matrix.
1282 gfx::Transform transform;
1283 transform.Translate(degrees * 2, -degrees * 3);
1284 transform.Rotate(degrees);
1285 transform.Scale(degrees + 1, 2 * degrees + 1);
1287 // factor the matrix
1288 DecomposedTransform decomp;
1289 bool success = DecomposeTransform(&decomp, transform);
1290 EXPECT_TRUE(success);
1291 EXPECT_FLOAT_EQ(decomp.translate[0], degrees * 2);
1292 EXPECT_FLOAT_EQ(decomp.translate[1], -degrees * 3);
1293 double rotation =
1294 std::acos(SkMScalarToDouble(decomp.quaternion[3])) * 360.0 / M_PI;
1295 while (rotation < 0.0)
1296 rotation += 360.0;
1297 while (rotation > 360.0)
1298 rotation -= 360.0;
1300 const float epsilon = 0.00015f;
1301 EXPECT_NEAR(rotation, degrees, epsilon);
1302 EXPECT_NEAR(decomp.scale[0], degrees + 1, epsilon);
1303 EXPECT_NEAR(decomp.scale[1], 2 * degrees + 1, epsilon);
1307 TEST(XFormTest, DecomposeTransform) {
1308 for (float scale = 0.001f; scale < 2.0f; scale += 0.001f) {
1309 gfx::Transform transform;
1310 transform.Scale(scale, scale);
1311 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
1313 DecomposedTransform decomp;
1314 bool success = DecomposeTransform(&decomp, transform);
1315 EXPECT_TRUE(success);
1317 gfx::Transform compose_transform = ComposeTransform(decomp);
1318 EXPECT_TRUE(compose_transform.Preserves2dAxisAlignment());
1322 TEST(XFormTest, IntegerTranslation) {
1323 gfx::Transform transform;
1324 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1326 transform.Translate3d(1, 2, 3);
1327 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1329 transform.MakeIdentity();
1330 transform.Translate3d(-1, -2, -3);
1331 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1333 transform.MakeIdentity();
1334 transform.Translate3d(4.5f, 0, 0);
1335 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1337 transform.MakeIdentity();
1338 transform.Translate3d(0, -6.7f, 0);
1339 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1341 transform.MakeIdentity();
1342 transform.Translate3d(0, 0, 8.9f);
1343 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1346 TEST(XFormTest, verifyMatrixInversion) {
1348 // Invert a translation
1349 gfx::Transform translation;
1350 translation.Translate3d(2.0, 3.0, 4.0);
1351 EXPECT_TRUE(translation.IsInvertible());
1353 gfx::Transform inverse_translation;
1354 bool is_invertible = translation.GetInverse(&inverse_translation);
1355 EXPECT_TRUE(is_invertible);
1356 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, -2.0f, inverse_translation);
1357 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, -3.0f, inverse_translation);
1358 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, -4.0f, inverse_translation);
1359 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_translation);
1363 // Invert a non-uniform scale
1364 gfx::Transform scale;
1365 scale.Scale3d(4.0, 10.0, 100.0);
1366 EXPECT_TRUE(scale.IsInvertible());
1368 gfx::Transform inverse_scale;
1369 bool is_invertible = scale.GetInverse(&inverse_scale);
1370 EXPECT_TRUE(is_invertible);
1371 EXPECT_ROW1_EQ(0.25f, 0.0f, 0.0f, 0.0f, inverse_scale);
1372 EXPECT_ROW2_EQ(0.0f, 0.1f, 0.0f, 0.0f, inverse_scale);
1373 EXPECT_ROW3_EQ(0.0f, 0.0f, 0.01f, 0.0f, inverse_scale);
1374 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_scale);
1378 // Try to invert a matrix that is not invertible.
1379 // The inverse() function should reset the output matrix to identity.
1380 gfx::Transform uninvertible;
1381 uninvertible.matrix().set(0, 0, 0.f);
1382 uninvertible.matrix().set(1, 1, 0.f);
1383 uninvertible.matrix().set(2, 2, 0.f);
1384 uninvertible.matrix().set(3, 3, 0.f);
1385 EXPECT_FALSE(uninvertible.IsInvertible());
1387 gfx::Transform inverse_of_uninvertible;
1389 // Add a scale just to more easily ensure that inverse_of_uninvertible is
1390 // reset to identity.
1391 inverse_of_uninvertible.Scale3d(4.0, 10.0, 100.0);
1393 bool is_invertible = uninvertible.GetInverse(&inverse_of_uninvertible);
1394 EXPECT_FALSE(is_invertible);
1395 EXPECT_TRUE(inverse_of_uninvertible.IsIdentity());
1396 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, inverse_of_uninvertible);
1397 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, inverse_of_uninvertible);
1398 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, inverse_of_uninvertible);
1399 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_of_uninvertible);
1403 TEST(XFormTest, verifyBackfaceVisibilityBasicCases) {
1404 Transform transform;
1406 transform.MakeIdentity();
1407 EXPECT_FALSE(transform.IsBackFaceVisible());
1409 transform.MakeIdentity();
1410 transform.RotateAboutYAxis(80.0);
1411 EXPECT_FALSE(transform.IsBackFaceVisible());
1413 transform.MakeIdentity();
1414 transform.RotateAboutYAxis(100.0);
1415 EXPECT_TRUE(transform.IsBackFaceVisible());
1417 // Edge case, 90 degree rotation should return false.
1418 transform.MakeIdentity();
1419 transform.RotateAboutYAxis(90.0);
1420 EXPECT_FALSE(transform.IsBackFaceVisible());
1423 TEST(XFormTest, verifyBackfaceVisibilityForPerspective) {
1424 Transform layer_space_to_projection_plane;
1426 // This tests if IsBackFaceVisible works properly under perspective
1427 // transforms. Specifically, layers that may have their back face visible in
1428 // orthographic projection, may not actually have back face visible under
1429 // perspective projection.
1431 // Case 1: Layer is rotated by slightly more than 90 degrees, at the center
1432 // of the prespective projection. In this case, the layer's back-side
1433 // is visible to the camera.
1434 layer_space_to_projection_plane.MakeIdentity();
1435 layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0);
1436 layer_space_to_projection_plane.Translate3d(0.0, 0.0, 0.0);
1437 layer_space_to_projection_plane.RotateAboutYAxis(100.0);
1438 EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible());
1440 // Case 2: Layer is rotated by slightly more than 90 degrees, but shifted off
1441 // to the side of the camera. Because of the wide field-of-view, the
1442 // layer's front side is still visible.
1444 // |<-- front side of layer is visible to camera
1445 // \ | /
1446 // \ | /
1447 // \| /
1448 // | /
1449 // |\ /<-- camera field of view
1450 // | \ /
1451 // back side of layer -->| \ /
1452 // \./ <-- camera origin
1454 layer_space_to_projection_plane.MakeIdentity();
1455 layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0);
1456 layer_space_to_projection_plane.Translate3d(-10.0, 0.0, 0.0);
1457 layer_space_to_projection_plane.RotateAboutYAxis(100.0);
1458 EXPECT_FALSE(layer_space_to_projection_plane.IsBackFaceVisible());
1460 // Case 3: Additionally rotating the layer by 180 degrees should of course
1461 // show the opposite result of case 2.
1462 layer_space_to_projection_plane.RotateAboutYAxis(180.0);
1463 EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible());
1466 TEST(XFormTest, verifyDefaultConstructorCreatesIdentityMatrix) {
1467 Transform A;
1468 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1469 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1470 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1471 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1472 EXPECT_TRUE(A.IsIdentity());
1475 TEST(XFormTest, verifyCopyConstructor) {
1476 Transform A;
1477 InitializeTestMatrix(&A);
1479 // Copy constructor should produce exact same elements as matrix A.
1480 Transform B(A);
1481 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B);
1482 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B);
1483 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B);
1484 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B);
1487 TEST(XFormTest, verifyConstructorFor16Elements) {
1488 Transform transform(1.0, 2.0, 3.0, 4.0,
1489 5.0, 6.0, 7.0, 8.0,
1490 9.0, 10.0, 11.0, 12.0,
1491 13.0, 14.0, 15.0, 16.0);
1493 EXPECT_ROW1_EQ(1.0f, 2.0f, 3.0f, 4.0f, transform);
1494 EXPECT_ROW2_EQ(5.0f, 6.0f, 7.0f, 8.0f, transform);
1495 EXPECT_ROW3_EQ(9.0f, 10.0f, 11.0f, 12.0f, transform);
1496 EXPECT_ROW4_EQ(13.0f, 14.0f, 15.0f, 16.0f, transform);
1499 TEST(XFormTest, verifyConstructorFor2dElements) {
1500 Transform transform(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
1502 EXPECT_ROW1_EQ(1.0f, 2.0f, 0.0f, 5.0f, transform);
1503 EXPECT_ROW2_EQ(3.0f, 4.0f, 0.0f, 6.0f, transform);
1504 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, transform);
1505 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, transform);
1509 TEST(XFormTest, verifyAssignmentOperator) {
1510 Transform A;
1511 InitializeTestMatrix(&A);
1512 Transform B;
1513 InitializeTestMatrix2(&B);
1514 Transform C;
1515 InitializeTestMatrix2(&C);
1516 C = B = A;
1518 // Both B and C should now have been re-assigned to the value of A.
1519 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B);
1520 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B);
1521 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B);
1522 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B);
1524 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, C);
1525 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, C);
1526 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, C);
1527 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, C);
1530 TEST(XFormTest, verifyEqualsBooleanOperator) {
1531 Transform A;
1532 InitializeTestMatrix(&A);
1534 Transform B;
1535 InitializeTestMatrix(&B);
1536 EXPECT_TRUE(A == B);
1538 // Modifying multiple elements should cause equals operator to return false.
1539 Transform C;
1540 InitializeTestMatrix2(&C);
1541 EXPECT_FALSE(A == C);
1543 // Modifying any one individual element should cause equals operator to
1544 // return false.
1545 Transform D;
1546 D = A;
1547 D.matrix().set(0, 0, 0.f);
1548 EXPECT_FALSE(A == D);
1550 D = A;
1551 D.matrix().set(1, 0, 0.f);
1552 EXPECT_FALSE(A == D);
1554 D = A;
1555 D.matrix().set(2, 0, 0.f);
1556 EXPECT_FALSE(A == D);
1558 D = A;
1559 D.matrix().set(3, 0, 0.f);
1560 EXPECT_FALSE(A == D);
1562 D = A;
1563 D.matrix().set(0, 1, 0.f);
1564 EXPECT_FALSE(A == D);
1566 D = A;
1567 D.matrix().set(1, 1, 0.f);
1568 EXPECT_FALSE(A == D);
1570 D = A;
1571 D.matrix().set(2, 1, 0.f);
1572 EXPECT_FALSE(A == D);
1574 D = A;
1575 D.matrix().set(3, 1, 0.f);
1576 EXPECT_FALSE(A == D);
1578 D = A;
1579 D.matrix().set(0, 2, 0.f);
1580 EXPECT_FALSE(A == D);
1582 D = A;
1583 D.matrix().set(1, 2, 0.f);
1584 EXPECT_FALSE(A == D);
1586 D = A;
1587 D.matrix().set(2, 2, 0.f);
1588 EXPECT_FALSE(A == D);
1590 D = A;
1591 D.matrix().set(3, 2, 0.f);
1592 EXPECT_FALSE(A == D);
1594 D = A;
1595 D.matrix().set(0, 3, 0.f);
1596 EXPECT_FALSE(A == D);
1598 D = A;
1599 D.matrix().set(1, 3, 0.f);
1600 EXPECT_FALSE(A == D);
1602 D = A;
1603 D.matrix().set(2, 3, 0.f);
1604 EXPECT_FALSE(A == D);
1606 D = A;
1607 D.matrix().set(3, 3, 0.f);
1608 EXPECT_FALSE(A == D);
1611 TEST(XFormTest, verifyMultiplyOperator) {
1612 Transform A;
1613 InitializeTestMatrix(&A);
1615 Transform B;
1616 InitializeTestMatrix2(&B);
1618 Transform C = A * B;
1619 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, C);
1620 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, C);
1621 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, C);
1622 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, C);
1624 // Just an additional sanity check; matrix multiplication is not commutative.
1625 EXPECT_FALSE(A * B == B * A);
1628 TEST(XFormTest, verifyMultiplyAndAssignOperator) {
1629 Transform A;
1630 InitializeTestMatrix(&A);
1632 Transform B;
1633 InitializeTestMatrix2(&B);
1635 A *= B;
1636 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
1637 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
1638 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
1639 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
1641 // Just an additional sanity check; matrix multiplication is not commutative.
1642 Transform C = A;
1643 C *= B;
1644 Transform D = B;
1645 D *= A;
1646 EXPECT_FALSE(C == D);
1649 TEST(XFormTest, verifyMatrixMultiplication) {
1650 Transform A;
1651 InitializeTestMatrix(&A);
1653 Transform B;
1654 InitializeTestMatrix2(&B);
1656 A.PreconcatTransform(B);
1657 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
1658 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
1659 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
1660 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
1663 TEST(XFormTest, verifyMakeIdentiy) {
1664 Transform A;
1665 InitializeTestMatrix(&A);
1666 A.MakeIdentity();
1667 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1668 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1669 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1670 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1671 EXPECT_TRUE(A.IsIdentity());
1674 TEST(XFormTest, verifyTranslate) {
1675 Transform A;
1676 A.Translate(2.0, 3.0);
1677 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
1678 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
1679 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1680 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1682 // Verify that Translate() post-multiplies the existing matrix.
1683 A.MakeIdentity();
1684 A.Scale(5.0, 5.0);
1685 A.Translate(2.0, 3.0);
1686 EXPECT_ROW1_EQ(5.0f, 0.0f, 0.0f, 10.0f, A);
1687 EXPECT_ROW2_EQ(0.0f, 5.0f, 0.0f, 15.0f, A);
1688 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1689 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1692 TEST(XFormTest, verifyTranslate3d) {
1693 Transform A;
1694 A.Translate3d(2.0, 3.0, 4.0);
1695 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
1696 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
1697 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
1698 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1700 // Verify that Translate3d() post-multiplies the existing matrix.
1701 A.MakeIdentity();
1702 A.Scale3d(6.0, 7.0, 8.0);
1703 A.Translate3d(2.0, 3.0, 4.0);
1704 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 12.0f, A);
1705 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 21.0f, A);
1706 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 32.0f, A);
1707 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1710 TEST(XFormTest, verifyScale) {
1711 Transform A;
1712 A.Scale(6.0, 7.0);
1713 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
1714 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
1715 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1716 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1718 // Verify that Scale() post-multiplies the existing matrix.
1719 A.MakeIdentity();
1720 A.Translate3d(2.0, 3.0, 4.0);
1721 A.Scale(6.0, 7.0);
1722 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
1723 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
1724 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
1725 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1728 TEST(XFormTest, verifyScale3d) {
1729 Transform A;
1730 A.Scale3d(6.0, 7.0, 8.0);
1731 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
1732 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
1733 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1734 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1736 // Verify that scale3d() post-multiplies the existing matrix.
1737 A.MakeIdentity();
1738 A.Translate3d(2.0, 3.0, 4.0);
1739 A.Scale3d(6.0, 7.0, 8.0);
1740 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
1741 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
1742 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 4.0f, A);
1743 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1746 TEST(XFormTest, verifyRotate) {
1747 Transform A;
1748 A.Rotate(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 // Verify that Rotate() post-multiplies the existing matrix.
1755 A.MakeIdentity();
1756 A.Scale3d(6.0, 7.0, 8.0);
1757 A.Rotate(90.0);
1758 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1759 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1760 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1761 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1764 TEST(XFormTest, verifyRotateAboutXAxis) {
1765 Transform A;
1766 double sin45 = 0.5 * sqrt(2.0);
1767 double cos45 = sin45;
1769 A.MakeIdentity();
1770 A.RotateAboutXAxis(90.0);
1771 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1772 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD);
1773 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1774 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1776 A.MakeIdentity();
1777 A.RotateAboutXAxis(45.0);
1778 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1779 EXPECT_ROW2_NEAR(0.0, cos45, -sin45, 0.0, A, ERROR_THRESHOLD);
1780 EXPECT_ROW3_NEAR(0.0, sin45, cos45, 0.0, A, ERROR_THRESHOLD);
1781 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1783 // Verify that RotateAboutXAxis(angle) post-multiplies the existing matrix.
1784 A.MakeIdentity();
1785 A.Scale3d(6.0, 7.0, 8.0);
1786 A.RotateAboutXAxis(90.0);
1787 EXPECT_ROW1_NEAR(6.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1788 EXPECT_ROW2_NEAR(0.0, 0.0, -7.0, 0.0, A, ERROR_THRESHOLD);
1789 EXPECT_ROW3_NEAR(0.0, 8.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1790 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1793 TEST(XFormTest, verifyRotateAboutYAxis) {
1794 Transform A;
1795 double sin45 = 0.5 * sqrt(2.0);
1796 double cos45 = sin45;
1798 // Note carefully, the expected pattern is inverted compared to rotating
1799 // about x axis or z axis.
1800 A.MakeIdentity();
1801 A.RotateAboutYAxis(90.0);
1802 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD);
1803 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1804 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1805 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1807 A.MakeIdentity();
1808 A.RotateAboutYAxis(45.0);
1809 EXPECT_ROW1_NEAR(cos45, 0.0, sin45, 0.0, A, ERROR_THRESHOLD);
1810 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1811 EXPECT_ROW3_NEAR(-sin45, 0.0, cos45, 0.0, A, ERROR_THRESHOLD);
1812 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1814 // Verify that RotateAboutYAxis(angle) post-multiplies the existing matrix.
1815 A.MakeIdentity();
1816 A.Scale3d(6.0, 7.0, 8.0);
1817 A.RotateAboutYAxis(90.0);
1818 EXPECT_ROW1_NEAR(0.0, 0.0, 6.0, 0.0, A, ERROR_THRESHOLD);
1819 EXPECT_ROW2_NEAR(0.0, 7.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1820 EXPECT_ROW3_NEAR(-8.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1821 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1824 TEST(XFormTest, verifyRotateAboutZAxis) {
1825 Transform A;
1826 double sin45 = 0.5 * sqrt(2.0);
1827 double cos45 = sin45;
1829 A.MakeIdentity();
1830 A.RotateAboutZAxis(90.0);
1831 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1832 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1833 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1834 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1836 A.MakeIdentity();
1837 A.RotateAboutZAxis(45.0);
1838 EXPECT_ROW1_NEAR(cos45, -sin45, 0.0, 0.0, A, ERROR_THRESHOLD);
1839 EXPECT_ROW2_NEAR(sin45, cos45, 0.0, 0.0, A, ERROR_THRESHOLD);
1840 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1841 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1843 // Verify that RotateAboutZAxis(angle) post-multiplies the existing matrix.
1844 A.MakeIdentity();
1845 A.Scale3d(6.0, 7.0, 8.0);
1846 A.RotateAboutZAxis(90.0);
1847 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1848 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1849 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1850 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1853 TEST(XFormTest, verifyRotateAboutForAlignedAxes) {
1854 Transform A;
1856 // Check rotation about z-axis
1857 A.MakeIdentity();
1858 A.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1859 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1860 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1861 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1862 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1864 // Check rotation about x-axis
1865 A.MakeIdentity();
1866 A.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1867 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1868 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD);
1869 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1870 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1872 // Check rotation about y-axis. Note carefully, the expected pattern is
1873 // inverted compared to rotating about x axis or z axis.
1874 A.MakeIdentity();
1875 A.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1876 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD);
1877 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1878 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1879 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1881 // Verify that rotate3d(axis, angle) post-multiplies the existing matrix.
1882 A.MakeIdentity();
1883 A.Scale3d(6.0, 7.0, 8.0);
1884 A.RotateAboutZAxis(90.0);
1885 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1886 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1887 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1888 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1891 TEST(XFormTest, verifyRotateAboutForArbitraryAxis) {
1892 // Check rotation about an arbitrary non-axis-aligned vector.
1893 Transform A;
1894 A.RotateAbout(Vector3dF(1.0, 1.0, 1.0), 90.0);
1895 EXPECT_ROW1_NEAR(0.3333333333333334258519187,
1896 -0.2440169358562924717404030,
1897 0.9106836025229592124219380,
1898 0.0, A, ERROR_THRESHOLD);
1899 EXPECT_ROW2_NEAR(0.9106836025229592124219380,
1900 0.3333333333333334258519187,
1901 -0.2440169358562924717404030,
1902 0.0, A, ERROR_THRESHOLD);
1903 EXPECT_ROW3_NEAR(-0.2440169358562924717404030,
1904 0.9106836025229592124219380,
1905 0.3333333333333334258519187,
1906 0.0, A, ERROR_THRESHOLD);
1907 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1910 TEST(XFormTest, verifyRotateAboutForDegenerateAxis) {
1911 // Check rotation about a degenerate zero vector.
1912 // It is expected to skip applying the rotation.
1913 Transform A;
1915 A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 45.0);
1916 // Verify that A remains unchanged.
1917 EXPECT_TRUE(A.IsIdentity());
1919 InitializeTestMatrix(&A);
1920 A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 35.0);
1922 // Verify that A remains unchanged.
1923 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, A);
1924 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, A);
1925 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, A);
1926 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, A);
1929 TEST(XFormTest, verifySkew) {
1930 // Test a skew along X axis only
1931 Transform A;
1932 A.Skew(45.0, 0.0);
1933 EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
1934 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1935 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1936 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1938 // Test a skew along Y axis only
1939 A.MakeIdentity();
1940 A.Skew(0.0, 45.0);
1941 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1942 EXPECT_ROW2_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
1943 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1944 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1946 // Verify that skew() post-multiplies the existing matrix. Row 1, column 2,
1947 // would incorrectly have value "7" if the matrix is pre-multiplied instead
1948 // of post-multiplied.
1949 A.MakeIdentity();
1950 A.Scale3d(6.0, 7.0, 8.0);
1951 A.Skew(45.0, 0.0);
1952 EXPECT_ROW1_EQ(6.0f, 6.0f, 0.0f, 0.0f, A);
1953 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
1954 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1955 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1957 // Test a skew along X and Y axes both
1958 A.MakeIdentity();
1959 A.Skew(45.0, 45.0);
1960 EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
1961 EXPECT_ROW2_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
1962 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1963 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1966 TEST(XFormTest, verifyPerspectiveDepth) {
1967 Transform A;
1968 A.ApplyPerspectiveDepth(1.0);
1969 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1970 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1971 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1972 EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
1974 // Verify that PerspectiveDepth() post-multiplies the existing matrix.
1975 A.MakeIdentity();
1976 A.Translate3d(2.0, 3.0, 4.0);
1977 A.ApplyPerspectiveDepth(1.0);
1978 EXPECT_ROW1_EQ(1.0f, 0.0f, -2.0f, 2.0f, A);
1979 EXPECT_ROW2_EQ(0.0f, 1.0f, -3.0f, 3.0f, A);
1980 EXPECT_ROW3_EQ(0.0f, 0.0f, -3.0f, 4.0f, A);
1981 EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
1984 TEST(XFormTest, verifyHasPerspective) {
1985 Transform A;
1986 A.ApplyPerspectiveDepth(1.0);
1987 EXPECT_TRUE(A.HasPerspective());
1989 A.MakeIdentity();
1990 A.ApplyPerspectiveDepth(0.0);
1991 EXPECT_FALSE(A.HasPerspective());
1993 A.MakeIdentity();
1994 A.matrix().set(3, 0, -1.f);
1995 EXPECT_TRUE(A.HasPerspective());
1997 A.MakeIdentity();
1998 A.matrix().set(3, 1, -1.f);
1999 EXPECT_TRUE(A.HasPerspective());
2001 A.MakeIdentity();
2002 A.matrix().set(3, 2, -0.3f);
2003 EXPECT_TRUE(A.HasPerspective());
2005 A.MakeIdentity();
2006 A.matrix().set(3, 3, 0.5f);
2007 EXPECT_TRUE(A.HasPerspective());
2009 A.MakeIdentity();
2010 A.matrix().set(3, 3, 0.f);
2011 EXPECT_TRUE(A.HasPerspective());
2014 TEST(XFormTest, verifyIsInvertible) {
2015 Transform A;
2017 // Translations, rotations, scales, skews and arbitrary combinations of them
2018 // are invertible.
2019 A.MakeIdentity();
2020 EXPECT_TRUE(A.IsInvertible());
2022 A.MakeIdentity();
2023 A.Translate3d(2.0, 3.0, 4.0);
2024 EXPECT_TRUE(A.IsInvertible());
2026 A.MakeIdentity();
2027 A.Scale3d(6.0, 7.0, 8.0);
2028 EXPECT_TRUE(A.IsInvertible());
2030 A.MakeIdentity();
2031 A.RotateAboutXAxis(10.0);
2032 A.RotateAboutYAxis(20.0);
2033 A.RotateAboutZAxis(30.0);
2034 EXPECT_TRUE(A.IsInvertible());
2036 A.MakeIdentity();
2037 A.Skew(45.0, 0.0);
2038 EXPECT_TRUE(A.IsInvertible());
2040 // A perspective matrix (projection plane at z=0) is invertible. The
2041 // intuitive explanation is that perspective is eqivalent to a skew of the
2042 // w-axis; skews are invertible.
2043 A.MakeIdentity();
2044 A.ApplyPerspectiveDepth(1.0);
2045 EXPECT_TRUE(A.IsInvertible());
2047 // A "pure" perspective matrix derived by similar triangles, with m44() set
2048 // to zero (i.e. camera positioned at the origin), is not invertible.
2049 A.MakeIdentity();
2050 A.ApplyPerspectiveDepth(1.0);
2051 A.matrix().set(3, 3, 0.f);
2052 EXPECT_FALSE(A.IsInvertible());
2054 // Adding more to a non-invertible matrix will not make it invertible in the
2055 // general case.
2056 A.MakeIdentity();
2057 A.ApplyPerspectiveDepth(1.0);
2058 A.matrix().set(3, 3, 0.f);
2059 A.Scale3d(6.0, 7.0, 8.0);
2060 A.RotateAboutXAxis(10.0);
2061 A.RotateAboutYAxis(20.0);
2062 A.RotateAboutZAxis(30.0);
2063 A.Translate3d(6.0, 7.0, 8.0);
2064 EXPECT_FALSE(A.IsInvertible());
2066 // A degenerate matrix of all zeros is not invertible.
2067 A.MakeIdentity();
2068 A.matrix().set(0, 0, 0.f);
2069 A.matrix().set(1, 1, 0.f);
2070 A.matrix().set(2, 2, 0.f);
2071 A.matrix().set(3, 3, 0.f);
2072 EXPECT_FALSE(A.IsInvertible());
2075 TEST(XFormTest, verifyIsIdentity) {
2076 Transform A;
2078 InitializeTestMatrix(&A);
2079 EXPECT_FALSE(A.IsIdentity());
2081 A.MakeIdentity();
2082 EXPECT_TRUE(A.IsIdentity());
2084 // Modifying any one individual element should cause the matrix to no longer
2085 // be identity.
2086 A.MakeIdentity();
2087 A.matrix().set(0, 0, 2.f);
2088 EXPECT_FALSE(A.IsIdentity());
2090 A.MakeIdentity();
2091 A.matrix().set(1, 0, 2.f);
2092 EXPECT_FALSE(A.IsIdentity());
2094 A.MakeIdentity();
2095 A.matrix().set(2, 0, 2.f);
2096 EXPECT_FALSE(A.IsIdentity());
2098 A.MakeIdentity();
2099 A.matrix().set(3, 0, 2.f);
2100 EXPECT_FALSE(A.IsIdentity());
2102 A.MakeIdentity();
2103 A.matrix().set(0, 1, 2.f);
2104 EXPECT_FALSE(A.IsIdentity());
2106 A.MakeIdentity();
2107 A.matrix().set(1, 1, 2.f);
2108 EXPECT_FALSE(A.IsIdentity());
2110 A.MakeIdentity();
2111 A.matrix().set(2, 1, 2.f);
2112 EXPECT_FALSE(A.IsIdentity());
2114 A.MakeIdentity();
2115 A.matrix().set(3, 1, 2.f);
2116 EXPECT_FALSE(A.IsIdentity());
2118 A.MakeIdentity();
2119 A.matrix().set(0, 2, 2.f);
2120 EXPECT_FALSE(A.IsIdentity());
2122 A.MakeIdentity();
2123 A.matrix().set(1, 2, 2.f);
2124 EXPECT_FALSE(A.IsIdentity());
2126 A.MakeIdentity();
2127 A.matrix().set(2, 2, 2.f);
2128 EXPECT_FALSE(A.IsIdentity());
2130 A.MakeIdentity();
2131 A.matrix().set(3, 2, 2.f);
2132 EXPECT_FALSE(A.IsIdentity());
2134 A.MakeIdentity();
2135 A.matrix().set(0, 3, 2.f);
2136 EXPECT_FALSE(A.IsIdentity());
2138 A.MakeIdentity();
2139 A.matrix().set(1, 3, 2.f);
2140 EXPECT_FALSE(A.IsIdentity());
2142 A.MakeIdentity();
2143 A.matrix().set(2, 3, 2.f);
2144 EXPECT_FALSE(A.IsIdentity());
2146 A.MakeIdentity();
2147 A.matrix().set(3, 3, 2.f);
2148 EXPECT_FALSE(A.IsIdentity());
2151 TEST(XFormTest, verifyIsIdentityOrTranslation) {
2152 Transform A;
2154 InitializeTestMatrix(&A);
2155 EXPECT_FALSE(A.IsIdentityOrTranslation());
2157 A.MakeIdentity();
2158 EXPECT_TRUE(A.IsIdentityOrTranslation());
2160 // Modifying any non-translation components should cause
2161 // IsIdentityOrTranslation() to return false. NOTE: (0, 3), (1, 3), and
2162 // (2, 3) are the translation components, so modifying them should still
2163 // return true.
2164 A.MakeIdentity();
2165 A.matrix().set(0, 0, 2.f);
2166 EXPECT_FALSE(A.IsIdentityOrTranslation());
2168 A.MakeIdentity();
2169 A.matrix().set(1, 0, 2.f);
2170 EXPECT_FALSE(A.IsIdentityOrTranslation());
2172 A.MakeIdentity();
2173 A.matrix().set(2, 0, 2.f);
2174 EXPECT_FALSE(A.IsIdentityOrTranslation());
2176 A.MakeIdentity();
2177 A.matrix().set(3, 0, 2.f);
2178 EXPECT_FALSE(A.IsIdentityOrTranslation());
2180 A.MakeIdentity();
2181 A.matrix().set(0, 1, 2.f);
2182 EXPECT_FALSE(A.IsIdentityOrTranslation());
2184 A.MakeIdentity();
2185 A.matrix().set(1, 1, 2.f);
2186 EXPECT_FALSE(A.IsIdentityOrTranslation());
2188 A.MakeIdentity();
2189 A.matrix().set(2, 1, 2.f);
2190 EXPECT_FALSE(A.IsIdentityOrTranslation());
2192 A.MakeIdentity();
2193 A.matrix().set(3, 1, 2.f);
2194 EXPECT_FALSE(A.IsIdentityOrTranslation());
2196 A.MakeIdentity();
2197 A.matrix().set(0, 2, 2.f);
2198 EXPECT_FALSE(A.IsIdentityOrTranslation());
2200 A.MakeIdentity();
2201 A.matrix().set(1, 2, 2.f);
2202 EXPECT_FALSE(A.IsIdentityOrTranslation());
2204 A.MakeIdentity();
2205 A.matrix().set(2, 2, 2.f);
2206 EXPECT_FALSE(A.IsIdentityOrTranslation());
2208 A.MakeIdentity();
2209 A.matrix().set(3, 2, 2.f);
2210 EXPECT_FALSE(A.IsIdentityOrTranslation());
2212 // Note carefully - expecting true here.
2213 A.MakeIdentity();
2214 A.matrix().set(0, 3, 2.f);
2215 EXPECT_TRUE(A.IsIdentityOrTranslation());
2217 // Note carefully - expecting true here.
2218 A.MakeIdentity();
2219 A.matrix().set(1, 3, 2.f);
2220 EXPECT_TRUE(A.IsIdentityOrTranslation());
2222 // Note carefully - expecting true here.
2223 A.MakeIdentity();
2224 A.matrix().set(2, 3, 2.f);
2225 EXPECT_TRUE(A.IsIdentityOrTranslation());
2227 A.MakeIdentity();
2228 A.matrix().set(3, 3, 2.f);
2229 EXPECT_FALSE(A.IsIdentityOrTranslation());
2232 TEST(XFormTest, verifyIsApproximatelyIdentityOrTranslation) {
2233 Transform A;
2234 SkMatrix44& matrix = A.matrix();
2236 // Exact pure translation.
2237 A.MakeIdentity();
2239 // Set translate values to values other than 0 or 1.
2240 matrix.set(0, 3, 3.4f);
2241 matrix.set(1, 3, 4.4f);
2242 matrix.set(2, 3, 5.6f);
2244 EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(0));
2245 EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2247 // Approximately pure translation.
2248 InitializeApproxIdentityMatrix(&A);
2250 // Some values must be exact.
2251 matrix.set(3, 0, 0);
2252 matrix.set(3, 1, 0);
2253 matrix.set(3, 2, 0);
2254 matrix.set(3, 3, 1);
2256 // Set translate values to values other than 0 or 1.
2257 matrix.set(0, 3, 3.4f);
2258 matrix.set(1, 3, 4.4f);
2259 matrix.set(2, 3, 5.6f);
2261 EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
2262 EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2264 // Not approximately pure translation.
2265 InitializeApproxIdentityMatrix(&A);
2267 // Some values must be exact.
2268 matrix.set(3, 0, 0);
2269 matrix.set(3, 1, 0);
2270 matrix.set(3, 2, 0);
2271 matrix.set(3, 3, 1);
2273 // Set some values (not translate values) to values other than 0 or 1.
2274 matrix.set(0, 1, 3.4f);
2275 matrix.set(3, 2, 4.4f);
2276 matrix.set(2, 0, 5.6f);
2278 EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
2279 EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2282 TEST(XFormTest, verifyIsScaleOrTranslation) {
2283 Transform A;
2285 InitializeTestMatrix(&A);
2286 EXPECT_FALSE(A.IsScaleOrTranslation());
2288 A.MakeIdentity();
2289 EXPECT_TRUE(A.IsScaleOrTranslation());
2291 // Modifying any non-scale or non-translation components should cause
2292 // IsScaleOrTranslation() to return false. (0, 0), (1, 1), (2, 2), (0, 3),
2293 // (1, 3), and (2, 3) are the scale and translation components, so
2294 // modifying them should still return true.
2296 // Note carefully - expecting true here.
2297 A.MakeIdentity();
2298 A.matrix().set(0, 0, 2.f);
2299 EXPECT_TRUE(A.IsScaleOrTranslation());
2301 A.MakeIdentity();
2302 A.matrix().set(1, 0, 2.f);
2303 EXPECT_FALSE(A.IsScaleOrTranslation());
2305 A.MakeIdentity();
2306 A.matrix().set(2, 0, 2.f);
2307 EXPECT_FALSE(A.IsScaleOrTranslation());
2309 A.MakeIdentity();
2310 A.matrix().set(3, 0, 2.f);
2311 EXPECT_FALSE(A.IsScaleOrTranslation());
2313 A.MakeIdentity();
2314 A.matrix().set(0, 1, 2.f);
2315 EXPECT_FALSE(A.IsScaleOrTranslation());
2317 // Note carefully - expecting true here.
2318 A.MakeIdentity();
2319 A.matrix().set(1, 1, 2.f);
2320 EXPECT_TRUE(A.IsScaleOrTranslation());
2322 A.MakeIdentity();
2323 A.matrix().set(2, 1, 2.f);
2324 EXPECT_FALSE(A.IsScaleOrTranslation());
2326 A.MakeIdentity();
2327 A.matrix().set(3, 1, 2.f);
2328 EXPECT_FALSE(A.IsScaleOrTranslation());
2330 A.MakeIdentity();
2331 A.matrix().set(0, 2, 2.f);
2332 EXPECT_FALSE(A.IsScaleOrTranslation());
2334 A.MakeIdentity();
2335 A.matrix().set(1, 2, 2.f);
2336 EXPECT_FALSE(A.IsScaleOrTranslation());
2338 // Note carefully - expecting true here.
2339 A.MakeIdentity();
2340 A.matrix().set(2, 2, 2.f);
2341 EXPECT_TRUE(A.IsScaleOrTranslation());
2343 A.MakeIdentity();
2344 A.matrix().set(3, 2, 2.f);
2345 EXPECT_FALSE(A.IsScaleOrTranslation());
2347 // Note carefully - expecting true here.
2348 A.MakeIdentity();
2349 A.matrix().set(0, 3, 2.f);
2350 EXPECT_TRUE(A.IsScaleOrTranslation());
2352 // Note carefully - expecting true here.
2353 A.MakeIdentity();
2354 A.matrix().set(1, 3, 2.f);
2355 EXPECT_TRUE(A.IsScaleOrTranslation());
2357 // Note carefully - expecting true here.
2358 A.MakeIdentity();
2359 A.matrix().set(2, 3, 2.f);
2360 EXPECT_TRUE(A.IsScaleOrTranslation());
2362 A.MakeIdentity();
2363 A.matrix().set(3, 3, 2.f);
2364 EXPECT_FALSE(A.IsScaleOrTranslation());
2367 TEST(XFormTest, verifyFlattenTo2d) {
2368 Transform A;
2369 InitializeTestMatrix(&A);
2371 A.FlattenTo2d();
2372 EXPECT_ROW1_EQ(10.0f, 14.0f, 0.0f, 22.0f, A);
2373 EXPECT_ROW2_EQ(11.0f, 15.0f, 0.0f, 23.0f, A);
2374 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
2375 EXPECT_ROW4_EQ(13.0f, 17.0f, 0.0f, 25.0f, A);
2378 TEST(XFormTest, IsFlat) {
2379 Transform transform;
2380 InitializeTestMatrix(&transform);
2382 // A transform with all entries non-zero isn't flat.
2383 EXPECT_FALSE(transform.IsFlat());
2385 transform.matrix().set(0, 2, 0.f);
2386 transform.matrix().set(1, 2, 0.f);
2387 transform.matrix().set(2, 2, 1.f);
2388 transform.matrix().set(3, 2, 0.f);
2390 EXPECT_FALSE(transform.IsFlat());
2392 transform.matrix().set(2, 0, 0.f);
2393 transform.matrix().set(2, 1, 0.f);
2394 transform.matrix().set(2, 3, 0.f);
2396 // Since the third column and row are both (0, 0, 1, 0), the transform is
2397 // flat.
2398 EXPECT_TRUE(transform.IsFlat());
2401 // Another implementation of Preserves2dAxisAlignment that isn't as fast,
2402 // good for testing the faster implementation.
2403 static bool EmpiricallyPreserves2dAxisAlignment(const Transform& transform) {
2404 Point3F p1(5.0f, 5.0f, 0.0f);
2405 Point3F p2(10.0f, 5.0f, 0.0f);
2406 Point3F p3(10.0f, 20.0f, 0.0f);
2407 Point3F p4(5.0f, 20.0f, 0.0f);
2409 QuadF test_quad(PointF(p1.x(), p1.y()),
2410 PointF(p2.x(), p2.y()),
2411 PointF(p3.x(), p3.y()),
2412 PointF(p4.x(), p4.y()));
2413 EXPECT_TRUE(test_quad.IsRectilinear());
2415 transform.TransformPoint(&p1);
2416 transform.TransformPoint(&p2);
2417 transform.TransformPoint(&p3);
2418 transform.TransformPoint(&p4);
2420 QuadF transformedQuad(PointF(p1.x(), p1.y()),
2421 PointF(p2.x(), p2.y()),
2422 PointF(p3.x(), p3.y()),
2423 PointF(p4.x(), p4.y()));
2424 return transformedQuad.IsRectilinear();
2427 TEST(XFormTest, Preserves2dAxisAlignment) {
2428 static const struct TestCase {
2429 SkMScalar a; // row 1, column 1
2430 SkMScalar b; // row 1, column 2
2431 SkMScalar c; // row 2, column 1
2432 SkMScalar d; // row 2, column 2
2433 bool expected;
2434 } test_cases[] = {
2435 { 3.f, 0.f,
2436 0.f, 4.f, true }, // basic case
2437 { 0.f, 4.f,
2438 3.f, 0.f, true }, // rotate by 90
2439 { 0.f, 0.f,
2440 0.f, 4.f, true }, // degenerate x
2441 { 3.f, 0.f,
2442 0.f, 0.f, true }, // degenerate y
2443 { 0.f, 0.f,
2444 3.f, 0.f, true }, // degenerate x + rotate by 90
2445 { 0.f, 4.f,
2446 0.f, 0.f, true }, // degenerate y + rotate by 90
2447 { 3.f, 4.f,
2448 0.f, 0.f, false },
2449 { 0.f, 0.f,
2450 3.f, 4.f, false },
2451 { 0.f, 3.f,
2452 0.f, 4.f, false },
2453 { 3.f, 0.f,
2454 4.f, 0.f, false },
2455 { 3.f, 4.f,
2456 5.f, 0.f, false },
2457 { 3.f, 4.f,
2458 0.f, 5.f, false },
2459 { 3.f, 0.f,
2460 4.f, 5.f, false },
2461 { 0.f, 3.f,
2462 4.f, 5.f, false },
2463 { 2.f, 3.f,
2464 4.f, 5.f, false },
2467 Transform transform;
2468 for (size_t i = 0; i < arraysize(test_cases); ++i) {
2469 const TestCase& value = test_cases[i];
2470 transform.MakeIdentity();
2471 transform.matrix().set(0, 0, value.a);
2472 transform.matrix().set(0, 1, value.b);
2473 transform.matrix().set(1, 0, value.c);
2474 transform.matrix().set(1, 1, value.d);
2476 if (value.expected) {
2477 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2478 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2479 } else {
2480 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2481 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2485 // Try the same test cases again, but this time make sure that other matrix
2486 // elements (except perspective) have entries, to test that they are ignored.
2487 for (size_t i = 0; i < arraysize(test_cases); ++i) {
2488 const TestCase& value = test_cases[i];
2489 transform.MakeIdentity();
2490 transform.matrix().set(0, 0, value.a);
2491 transform.matrix().set(0, 1, value.b);
2492 transform.matrix().set(1, 0, value.c);
2493 transform.matrix().set(1, 1, value.d);
2495 transform.matrix().set(0, 2, 1.f);
2496 transform.matrix().set(0, 3, 2.f);
2497 transform.matrix().set(1, 2, 3.f);
2498 transform.matrix().set(1, 3, 4.f);
2499 transform.matrix().set(2, 0, 5.f);
2500 transform.matrix().set(2, 1, 6.f);
2501 transform.matrix().set(2, 2, 7.f);
2502 transform.matrix().set(2, 3, 8.f);
2504 if (value.expected) {
2505 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2506 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2507 } else {
2508 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2509 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2513 // Try the same test cases again, but this time add perspective which is
2514 // always assumed to not-preserve axis alignment.
2515 for (size_t i = 0; i < arraysize(test_cases); ++i) {
2516 const TestCase& value = test_cases[i];
2517 transform.MakeIdentity();
2518 transform.matrix().set(0, 0, value.a);
2519 transform.matrix().set(0, 1, value.b);
2520 transform.matrix().set(1, 0, value.c);
2521 transform.matrix().set(1, 1, value.d);
2523 transform.matrix().set(0, 2, 1.f);
2524 transform.matrix().set(0, 3, 2.f);
2525 transform.matrix().set(1, 2, 3.f);
2526 transform.matrix().set(1, 3, 4.f);
2527 transform.matrix().set(2, 0, 5.f);
2528 transform.matrix().set(2, 1, 6.f);
2529 transform.matrix().set(2, 2, 7.f);
2530 transform.matrix().set(2, 3, 8.f);
2531 transform.matrix().set(3, 0, 9.f);
2532 transform.matrix().set(3, 1, 10.f);
2533 transform.matrix().set(3, 2, 11.f);
2534 transform.matrix().set(3, 3, 12.f);
2536 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2537 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2540 // Try a few more practical situations to check precision
2541 transform.MakeIdentity();
2542 transform.RotateAboutZAxis(90.0);
2543 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2544 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2546 transform.MakeIdentity();
2547 transform.RotateAboutZAxis(180.0);
2548 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2549 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2551 transform.MakeIdentity();
2552 transform.RotateAboutZAxis(270.0);
2553 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2554 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2556 transform.MakeIdentity();
2557 transform.RotateAboutYAxis(90.0);
2558 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2559 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2561 transform.MakeIdentity();
2562 transform.RotateAboutXAxis(90.0);
2563 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2564 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2566 transform.MakeIdentity();
2567 transform.RotateAboutZAxis(90.0);
2568 transform.RotateAboutYAxis(90.0);
2569 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2570 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2572 transform.MakeIdentity();
2573 transform.RotateAboutZAxis(90.0);
2574 transform.RotateAboutXAxis(90.0);
2575 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2576 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2578 transform.MakeIdentity();
2579 transform.RotateAboutYAxis(90.0);
2580 transform.RotateAboutZAxis(90.0);
2581 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2582 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2584 transform.MakeIdentity();
2585 transform.RotateAboutZAxis(45.0);
2586 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2587 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2589 // 3-d case; In 2d after an orthographic projection, this case does
2590 // preserve 2d axis alignment. But in 3d, it does not preserve axis
2591 // alignment.
2592 transform.MakeIdentity();
2593 transform.RotateAboutYAxis(45.0);
2594 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2595 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2597 transform.MakeIdentity();
2598 transform.RotateAboutXAxis(45.0);
2599 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2600 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2602 // Perspective cases.
2603 transform.MakeIdentity();
2604 transform.ApplyPerspectiveDepth(10.0);
2605 transform.RotateAboutYAxis(45.0);
2606 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2607 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2609 transform.MakeIdentity();
2610 transform.ApplyPerspectiveDepth(10.0);
2611 transform.RotateAboutZAxis(90.0);
2612 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2613 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2616 TEST(XFormTest, To2dTranslation) {
2617 Vector2dF translation(3.f, 7.f);
2618 Transform transform;
2619 transform.Translate(translation.x(), translation.y() + 1);
2620 EXPECT_NE(translation.ToString(), transform.To2dTranslation().ToString());
2621 transform.MakeIdentity();
2622 transform.Translate(translation.x(), translation.y());
2623 EXPECT_EQ(translation.ToString(), transform.To2dTranslation().ToString());
2626 TEST(XFormTest, TransformRect) {
2627 Transform translation;
2628 translation.Translate(3.f, 7.f);
2629 RectF rect(1.f, 2.f, 3.f, 4.f);
2630 RectF expected(4.f, 9.f, 3.f, 4.f);
2631 translation.TransformRect(&rect);
2632 EXPECT_EQ(expected.ToString(), rect.ToString());
2635 TEST(XFormTest, TransformRectReverse) {
2636 Transform translation;
2637 translation.Translate(3.f, 7.f);
2638 RectF rect(1.f, 2.f, 3.f, 4.f);
2639 RectF expected(-2.f, -5.f, 3.f, 4.f);
2640 EXPECT_TRUE(translation.TransformRectReverse(&rect));
2641 EXPECT_EQ(expected.ToString(), rect.ToString());
2643 Transform singular;
2644 singular.Scale3d(0.f, 0.f, 0.f);
2645 EXPECT_FALSE(singular.TransformRectReverse(&rect));
2648 TEST(XFormTest, TransformBox) {
2649 Transform translation;
2650 translation.Translate3d(3.f, 7.f, 6.f);
2651 BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f);
2652 BoxF expected(4.f, 9.f, 9.f, 4.f, 5.f, 6.f);
2653 translation.TransformBox(&box);
2654 EXPECT_EQ(expected.ToString(), box.ToString());
2657 TEST(XFormTest, TransformBoxReverse) {
2658 Transform translation;
2659 translation.Translate3d(3.f, 7.f, 6.f);
2660 BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f);
2661 BoxF expected(-2.f, -5.f, -3.f, 4.f, 5.f, 6.f);
2662 EXPECT_TRUE(translation.TransformBoxReverse(&box));
2663 EXPECT_EQ(expected.ToString(), box.ToString());
2665 Transform singular;
2666 singular.Scale3d(0.f, 0.f, 0.f);
2667 EXPECT_FALSE(singular.TransformBoxReverse(&box));
2670 TEST(XFormTest, RoundTranslationComponents) {
2671 Transform translation;
2672 Transform expected;
2674 translation.RoundTranslationComponents();
2675 EXPECT_EQ(expected.ToString(), translation.ToString());
2677 translation.Translate(1.0f, 1.0f);
2678 expected.Translate(1.0f, 1.0f);
2679 translation.RoundTranslationComponents();
2680 EXPECT_EQ(expected.ToString(), translation.ToString());
2682 translation.Translate(0.5f, 0.4f);
2683 expected.Translate(1.0f, 0.0f);
2684 translation.RoundTranslationComponents();
2685 EXPECT_EQ(expected.ToString(), translation.ToString());
2687 // Rounding should only affect 2d translation components.
2688 translation.Translate3d(0.f, 0.f, 0.5f);
2689 expected.Translate3d(0.f, 0.f, 0.5f);
2690 translation.RoundTranslationComponents();
2691 EXPECT_EQ(expected.ToString(), translation.ToString());
2694 } // namespace
2696 } // namespace gfx