mac: Add the flag "-gline-tables-only" to reduce dSYM size. (attempt #2)
[chromium-blink-merge.git] / ui / gfx / transform_unittest.cc
blob19441425e4b8b99b03e8e2bd05b99e38a06ef247
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},
451 { 0, 0,
452 std::numeric_limits<float>::quiet_NaN(),
453 std::numeric_limits<float>::quiet_NaN(),
454 10, 20},
457 Transform xform;
458 for (size_t i = 0; i < arraysize(test_cases); ++i) {
459 const TestCase& value = test_cases[i];
460 Transform translation;
461 translation.Translate(value.tx, value.ty);
462 xform = translation * xform;
463 Point p1(value.x1, value.y1);
464 Point p2(value.x2, value.y2);
465 xform.TransformPoint(&p1);
466 if (value.tx == value.tx &&
467 value.ty == value.ty) {
468 EXPECT_EQ(p1.x(), p2.x());
469 EXPECT_EQ(p1.y(), p2.y());
474 TEST(XFormTest, ConcatScale2D) {
475 static const struct TestCase {
476 int before;
477 float scale;
478 int after;
479 } test_cases[] = {
480 { 1, 10.0f, 10},
481 { 1, .1f, 1},
482 { 1, 100.0f, 100},
483 { 1, -1.0f, -100},
484 { 1, std::numeric_limits<float>::quiet_NaN(), 1}
487 Transform xform;
488 for (size_t i = 0; i < arraysize(test_cases); ++i) {
489 const TestCase& value = test_cases[i];
490 Transform scale;
491 scale.Scale(value.scale, value.scale);
492 xform = scale * xform;
493 Point p1(value.before, value.before);
494 Point p2(value.after, value.after);
495 xform.TransformPoint(&p1);
496 if (value.scale == value.scale) {
497 EXPECT_EQ(p1.x(), p2.x());
498 EXPECT_EQ(p1.y(), p2.y());
503 TEST(XFormTest, ConcatRotate2D) {
504 static const struct TestCase {
505 int x1;
506 int y1;
507 float degrees;
508 int x2;
509 int y2;
510 } test_cases[] = {
511 { 1, 0, 90.0f, 0, 1},
512 { 1, 0, -90.0f, 1, 0},
513 { 1, 0, 90.0f, 0, 1},
514 { 1, 0, 360.0f, 0, 1},
515 { 1, 0, 0.0f, 0, 1},
516 { 1, 0, std::numeric_limits<float>::quiet_NaN(), 1, 0}
519 Transform xform;
520 for (size_t i = 0; i < arraysize(test_cases); ++i) {
521 const TestCase& value = test_cases[i];
522 Transform rotation;
523 rotation.Rotate(value.degrees);
524 xform = rotation * xform;
525 Point p1(value.x1, value.y1);
526 Point p2(value.x2, value.y2);
527 xform.TransformPoint(&p1);
528 if (value.degrees == value.degrees) {
529 EXPECT_EQ(p1.x(), p2.x());
530 EXPECT_EQ(p1.y(), p2.y());
535 TEST(XFormTest, SetTranslate2D) {
536 static const struct TestCase {
537 int x1; int y1;
538 float tx; float ty;
539 int x2; int y2;
540 } test_cases[] = {
541 { 0, 0, 10.0f, 20.0f, 10, 20},
542 { 10, 20, 10.0f, 20.0f, 20, 40},
543 { 10, 20, 0.0f, 0.0f, 10, 20},
544 { 0, 0,
545 std::numeric_limits<float>::quiet_NaN(),
546 std::numeric_limits<float>::quiet_NaN(),
547 0, 0}
550 for (size_t i = 0; i < arraysize(test_cases); ++i) {
551 const TestCase& value = test_cases[i];
552 for (int j = -1; j < 2; ++j) {
553 for (int k = 0; k < 3; ++k) {
554 float epsilon = 0.0001f;
555 Point p0, p1, p2;
556 Transform xform;
557 switch (k) {
558 case 0:
559 p1.SetPoint(value.x1, 0);
560 p2.SetPoint(value.x2, 0);
561 xform.Translate(value.tx + j * epsilon, 0.0);
562 break;
563 case 1:
564 p1.SetPoint(0, value.y1);
565 p2.SetPoint(0, value.y2);
566 xform.Translate(0.0, value.ty + j * epsilon);
567 break;
568 case 2:
569 p1.SetPoint(value.x1, value.y1);
570 p2.SetPoint(value.x2, value.y2);
571 xform.Translate(value.tx + j * epsilon,
572 value.ty + j * epsilon);
573 break;
575 p0 = p1;
576 xform.TransformPoint(&p1);
577 if (value.tx == value.tx &&
578 value.ty == value.ty) {
579 EXPECT_EQ(p1.x(), p2.x());
580 EXPECT_EQ(p1.y(), p2.y());
581 xform.TransformPointReverse(&p1);
582 EXPECT_EQ(p1.x(), p0.x());
583 EXPECT_EQ(p1.y(), p0.y());
590 TEST(XFormTest, SetScale2D) {
591 static const struct TestCase {
592 int before;
593 float s;
594 int after;
595 } test_cases[] = {
596 { 1, 10.0f, 10},
597 { 1, 1.0f, 1},
598 { 1, 0.0f, 0},
599 { 0, 10.0f, 0},
600 { 1, std::numeric_limits<float>::quiet_NaN(), 0},
603 for (size_t i = 0; i < arraysize(test_cases); ++i) {
604 const TestCase& value = test_cases[i];
605 for (int j = -1; j < 2; ++j) {
606 for (int k = 0; k < 3; ++k) {
607 float epsilon = 0.0001f;
608 Point p0, p1, p2;
609 Transform xform;
610 switch (k) {
611 case 0:
612 p1.SetPoint(value.before, 0);
613 p2.SetPoint(value.after, 0);
614 xform.Scale(value.s + j * epsilon, 1.0);
615 break;
616 case 1:
617 p1.SetPoint(0, value.before);
618 p2.SetPoint(0, value.after);
619 xform.Scale(1.0, value.s + j * epsilon);
620 break;
621 case 2:
622 p1.SetPoint(value.before,
623 value.before);
624 p2.SetPoint(value.after,
625 value.after);
626 xform.Scale(value.s + j * epsilon,
627 value.s + j * epsilon);
628 break;
630 p0 = p1;
631 xform.TransformPoint(&p1);
632 if (value.s == value.s) {
633 EXPECT_EQ(p1.x(), p2.x());
634 EXPECT_EQ(p1.y(), p2.y());
635 if (value.s != 0.0f) {
636 xform.TransformPointReverse(&p1);
637 EXPECT_EQ(p1.x(), p0.x());
638 EXPECT_EQ(p1.y(), p0.y());
646 TEST(XFormTest, SetRotate2D) {
647 static const struct SetRotateCase {
648 int x;
649 int y;
650 float degree;
651 int xprime;
652 int yprime;
653 } set_rotate_cases[] = {
654 { 100, 0, 90.0f, 0, 100},
655 { 0, 0, 90.0f, 0, 0},
656 { 0, 100, 90.0f, -100, 0},
657 { 0, 1, -90.0f, 1, 0},
658 { 100, 0, 0.0f, 100, 0},
659 { 0, 0, 0.0f, 0, 0},
660 { 0, 0, std::numeric_limits<float>::quiet_NaN(), 0, 0},
661 { 100, 0, 360.0f, 100, 0}
664 for (size_t i = 0; i < arraysize(set_rotate_cases); ++i) {
665 const SetRotateCase& value = set_rotate_cases[i];
666 for (int j = 1; j >= -1; --j) {
667 float epsilon = 0.1f;
668 Point pt(value.x, value.y);
669 Transform xform;
670 // should be invariant to small floating point errors.
671 xform.Rotate(value.degree + j * epsilon);
672 // just want to make sure that we don't crash in the case of NaN.
673 if (value.degree == value.degree) {
674 xform.TransformPoint(&pt);
675 EXPECT_EQ(value.xprime, pt.x());
676 EXPECT_EQ(value.yprime, pt.y());
677 xform.TransformPointReverse(&pt);
678 EXPECT_EQ(pt.x(), value.x);
679 EXPECT_EQ(pt.y(), value.y);
685 TEST(XFormTest, TransformPointWithExtremePerspective) {
686 Point3F point(1.f, 1.f, 1.f);
687 Transform perspective;
688 perspective.ApplyPerspectiveDepth(1.f);
689 Point3F transformed = point;
690 perspective.TransformPoint(&transformed);
691 EXPECT_EQ(point.ToString(), transformed.ToString());
693 transformed = point;
694 perspective.MakeIdentity();
695 perspective.ApplyPerspectiveDepth(1.1f);
696 perspective.TransformPoint(&transformed);
697 EXPECT_FLOAT_EQ(11.f, transformed.x());
698 EXPECT_FLOAT_EQ(11.f, transformed.y());
699 EXPECT_FLOAT_EQ(11.f, transformed.z());
702 TEST(XFormTest, BlendTranslate) {
703 Transform from;
704 for (int i = -5; i < 15; ++i) {
705 Transform to;
706 to.Translate3d(1, 1, 1);
707 double t = i / 9.0;
708 EXPECT_TRUE(to.Blend(from, t));
709 EXPECT_FLOAT_EQ(t, to.matrix().get(0, 3));
710 EXPECT_FLOAT_EQ(t, to.matrix().get(1, 3));
711 EXPECT_FLOAT_EQ(t, to.matrix().get(2, 3));
715 TEST(XFormTest, BlendRotate) {
716 Vector3dF axes[] = {
717 Vector3dF(1, 0, 0),
718 Vector3dF(0, 1, 0),
719 Vector3dF(0, 0, 1),
720 Vector3dF(1, 1, 1)
722 Transform from;
723 for (size_t index = 0; index < arraysize(axes); ++index) {
724 for (int i = -5; i < 15; ++i) {
725 Transform to;
726 to.RotateAbout(axes[index], 90);
727 double t = i / 9.0;
728 EXPECT_TRUE(to.Blend(from, t));
730 Transform expected;
731 expected.RotateAbout(axes[index], 90 * t);
733 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
738 TEST(XFormTest, CanBlend180DegreeRotation) {
739 Vector3dF axes[] = {
740 Vector3dF(1, 0, 0),
741 Vector3dF(0, 1, 0),
742 Vector3dF(0, 0, 1),
743 Vector3dF(1, 1, 1)
745 Transform from;
746 for (size_t index = 0; index < arraysize(axes); ++index) {
747 for (int i = -5; i < 15; ++i) {
748 Transform to;
749 to.RotateAbout(axes[index], 180.0);
750 double t = i / 9.0;
751 EXPECT_TRUE(to.Blend(from, t));
753 // A 180 degree rotation is exactly opposite on the sphere, therefore
754 // either great circle arc to it is equivalent (and numerical precision
755 // will determine which is closer). Test both directions.
756 Transform expected1;
757 expected1.RotateAbout(axes[index], 180.0 * t);
758 Transform expected2;
759 expected2.RotateAbout(axes[index], -180.0 * t);
761 EXPECT_TRUE(MatricesAreNearlyEqual(expected1, to) ||
762 MatricesAreNearlyEqual(expected2, to))
763 << "axis: " << index << ", i: " << i;
768 #if defined(_WIN64)
769 // http://crbug.com/406574
770 #define MAYBE_BlendScale DISABLED_BlendScale
771 #else
772 #define MAYBE_BlendScale BlendScale
773 #endif
774 TEST(XFormTest, MAYBE_BlendScale) {
775 Transform from;
776 for (int i = -5; i < 15; ++i) {
777 Transform to;
778 to.Scale3d(5, 4, 3);
779 double t = i / 9.0;
780 EXPECT_TRUE(to.Blend(from, t));
781 EXPECT_FLOAT_EQ(t * 4 + 1, to.matrix().get(0, 0)) << "i: " << i;
782 EXPECT_FLOAT_EQ(t * 3 + 1, to.matrix().get(1, 1)) << "i: " << i;
783 EXPECT_FLOAT_EQ(t * 2 + 1, to.matrix().get(2, 2)) << "i: " << i;
787 TEST(XFormTest, BlendSkew) {
788 Transform from;
789 for (int i = 0; i < 2; ++i) {
790 Transform to;
791 to.SkewX(10);
792 to.SkewY(5);
793 double t = i;
794 Transform expected;
795 expected.SkewX(t * 10);
796 expected.SkewY(t * 5);
797 EXPECT_TRUE(to.Blend(from, t));
798 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
802 TEST(XFormTest, ExtrapolateSkew) {
803 Transform from;
804 for (int i = -1; i < 2; ++i) {
805 Transform to;
806 to.SkewX(20);
807 double t = i;
808 Transform expected;
809 expected.SkewX(t * 20);
810 EXPECT_TRUE(to.Blend(from, t));
811 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
815 #if defined(_WIN64)
816 // http://crbug.com/406574
817 #define MAYBE_BlendPerspective DISABLED_BlendPerspective
818 #else
819 #define MAYBE_BlendPerspective BlendPerspective
820 #endif
821 TEST(XFormTest, MAYBE_BlendPerspective) {
822 Transform from;
823 from.ApplyPerspectiveDepth(200);
824 for (int i = -1; i < 3; ++i) {
825 Transform to;
826 to.ApplyPerspectiveDepth(800);
827 double t = i;
828 double depth = 1.0 / ((1.0 / 200) * (1.0 - t) + (1.0 / 800) * t);
829 Transform expected;
830 expected.ApplyPerspectiveDepth(depth);
831 EXPECT_TRUE(to.Blend(from, t));
832 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
836 TEST(XFormTest, BlendIdentity) {
837 Transform from;
838 Transform to;
839 EXPECT_TRUE(to.Blend(from, 0.5));
840 EXPECT_EQ(to, from);
843 TEST(XFormTest, CannotBlendSingularMatrix) {
844 Transform from;
845 Transform to;
846 to.matrix().set(1, 1, SkDoubleToMScalar(0));
847 EXPECT_FALSE(to.Blend(from, 0.5));
850 TEST(XFormTest, VerifyBlendForTranslation) {
851 Transform from;
852 from.Translate3d(100.0, 200.0, 100.0);
854 Transform to;
856 to.Translate3d(200.0, 100.0, 300.0);
857 to.Blend(from, 0.0);
858 EXPECT_EQ(from, to);
860 to = Transform();
861 to.Translate3d(200.0, 100.0, 300.0);
862 to.Blend(from, 0.25);
863 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 125.0f, to);
864 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 175.0f, to);
865 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 150.0f, to);
866 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
868 to = Transform();
869 to.Translate3d(200.0, 100.0, 300.0);
870 to.Blend(from, 0.5);
871 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 150.0f, to);
872 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 150.0f, to);
873 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 200.0f, to);
874 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
876 to = Transform();
877 to.Translate3d(200.0, 100.0, 300.0);
878 to.Blend(from, 1.0);
879 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 200.0f, to);
880 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 100.0f, to);
881 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 300.0f, to);
882 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
885 TEST(XFormTest, VerifyBlendForScale) {
886 Transform from;
887 from.Scale3d(100.0, 200.0, 100.0);
889 Transform to;
891 to.Scale3d(200.0, 100.0, 300.0);
892 to.Blend(from, 0.0);
893 EXPECT_EQ(from, to);
895 to = Transform();
896 to.Scale3d(200.0, 100.0, 300.0);
897 to.Blend(from, 0.25);
898 EXPECT_ROW1_EQ(125.0f, 0.0f, 0.0f, 0.0f, to);
899 EXPECT_ROW2_EQ(0.0f, 175.0f, 0.0f, 0.0f, to);
900 EXPECT_ROW3_EQ(0.0f, 0.0f, 150.0f, 0.0f, to);
901 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
903 to = Transform();
904 to.Scale3d(200.0, 100.0, 300.0);
905 to.Blend(from, 0.5);
906 EXPECT_ROW1_EQ(150.0f, 0.0f, 0.0f, 0.0f, to);
907 EXPECT_ROW2_EQ(0.0f, 150.0f, 0.0f, 0.0f, to);
908 EXPECT_ROW3_EQ(0.0f, 0.0f, 200.0f, 0.0f, to);
909 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
911 to = Transform();
912 to.Scale3d(200.0, 100.0, 300.0);
913 to.Blend(from, 1.0);
914 EXPECT_ROW1_EQ(200.0f, 0.0f, 0.0f, 0.0f, to);
915 EXPECT_ROW2_EQ(0.0f, 100.0f, 0.0f, 0.0f, to);
916 EXPECT_ROW3_EQ(0.0f, 0.0f, 300.0f, 0.0f, to);
917 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
920 TEST(XFormTest, VerifyBlendForSkewX) {
921 Transform from;
922 from.SkewX(0.0);
924 Transform to;
926 to.SkewX(45.0);
927 to.Blend(from, 0.0);
928 EXPECT_EQ(from, to);
930 to = Transform();
931 to.SkewX(45.0);
932 to.Blend(from, 0.5);
933 EXPECT_ROW1_EQ(1.0f, 0.5f, 0.0f, 0.0f, to);
934 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
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);
938 to = Transform();
939 to.SkewX(45.0);
940 to.Blend(from, 0.25);
941 EXPECT_ROW1_EQ(1.0f, 0.25f, 0.0f, 0.0f, to);
942 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
943 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
944 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
946 to = Transform();
947 to.SkewX(45.0);
948 to.Blend(from, 1.0);
949 EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, to);
950 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
951 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
952 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
955 TEST(XFormTest, VerifyBlendForSkewY) {
956 // NOTE CAREFULLY: Decomposition of skew and rotation terms of the matrix
957 // is inherently underconstrained, and so it does not always compute the
958 // originally intended skew parameters. The current implementation uses QR
959 // decomposition, which decomposes the shear into a rotation + non-uniform
960 // scale.
962 // It is unlikely that the decomposition implementation will need to change
963 // very often, so to get any test coverage, the compromise is to verify the
964 // exact matrix that the.Blend() operation produces.
966 // This problem also potentially exists for skewX, but the current QR
967 // decomposition implementation just happens to decompose those test
968 // matrices intuitively.
970 // Unfortunately, this case suffers from uncomfortably large precision
971 // error.
973 Transform from;
974 from.SkewY(0.0);
976 Transform to;
978 to.SkewY(45.0);
979 to.Blend(from, 0.0);
980 EXPECT_EQ(from, to);
982 to = Transform();
983 to.SkewY(45.0);
984 to.Blend(from, 0.25);
985 EXPECT_ROW1_NEAR(1.0823489449280947471976333,
986 0.0464370719145053845178239,
987 0.0,
988 0.0,
990 LOOSE_ERROR_THRESHOLD);
991 EXPECT_ROW2_NEAR(0.2152925909665224513123150,
992 0.9541702441750861130032035,
993 0.0,
994 0.0,
996 LOOSE_ERROR_THRESHOLD);
997 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
998 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1000 to = Transform();
1001 to.SkewY(45.0);
1002 to.Blend(from, 0.5);
1003 EXPECT_ROW1_NEAR(1.1152212925809066312865525,
1004 0.0676495144007326631996335,
1005 0.0,
1006 0.0,
1008 LOOSE_ERROR_THRESHOLD);
1009 EXPECT_ROW2_NEAR(0.4619397844342648662419037,
1010 0.9519009045724774464858342,
1011 0.0,
1012 0.0,
1014 LOOSE_ERROR_THRESHOLD);
1015 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
1016 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1018 to = Transform();
1019 to.SkewY(45.0);
1020 to.Blend(from, 1.0);
1021 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD);
1022 EXPECT_ROW2_NEAR(1.0, 1.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD);
1023 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
1024 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1027 #if defined(_WIN64)
1028 // http://crbug.com/406574
1029 #define MAYBE_VerifyBlendForRotationAboutX DISABLED_VerifyBlendForRotationAboutX
1030 #else
1031 #define MAYBE_VerifyBlendForRotationAboutX VerifyBlendForRotationAboutX
1032 #endif
1033 TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutX) {
1034 // Even though.Blending uses quaternions, axis-aligned rotations should.
1035 // Blend the same with quaternions or Euler angles. So we can test
1036 // rotation.Blending by comparing against manually specified matrices from
1037 // Euler angles.
1039 Transform from;
1040 from.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 0.0);
1042 Transform to;
1044 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1045 to.Blend(from, 0.0);
1046 EXPECT_EQ(from, to);
1048 double expectedRotationAngle = 22.5 * M_PI / 180.0;
1049 to = Transform();
1050 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1051 to.Blend(from, 0.25);
1052 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1053 EXPECT_ROW2_NEAR(0.0,
1054 std::cos(expectedRotationAngle),
1055 -std::sin(expectedRotationAngle),
1056 0.0,
1058 ERROR_THRESHOLD);
1059 EXPECT_ROW3_NEAR(0.0,
1060 std::sin(expectedRotationAngle),
1061 std::cos(expectedRotationAngle),
1062 0.0,
1064 ERROR_THRESHOLD);
1065 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1067 expectedRotationAngle = 45.0 * M_PI / 180.0;
1068 to = Transform();
1069 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1070 to.Blend(from, 0.5);
1071 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1072 EXPECT_ROW2_NEAR(0.0,
1073 std::cos(expectedRotationAngle),
1074 -std::sin(expectedRotationAngle),
1075 0.0,
1077 ERROR_THRESHOLD);
1078 EXPECT_ROW3_NEAR(0.0,
1079 std::sin(expectedRotationAngle),
1080 std::cos(expectedRotationAngle),
1081 0.0,
1083 ERROR_THRESHOLD);
1084 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1086 to = Transform();
1087 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1088 to.Blend(from, 1.0);
1089 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1090 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, to, ERROR_THRESHOLD);
1091 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1092 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1095 #if defined(_WIN64)
1096 // http://crbug.com/406574
1097 #define MAYBE_VerifyBlendForRotationAboutY DISABLED_VerifyBlendForRotationAboutY
1098 #else
1099 #define MAYBE_VerifyBlendForRotationAboutY VerifyBlendForRotationAboutY
1100 #endif
1101 TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutY) {
1102 Transform from;
1103 from.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 0.0);
1105 Transform to;
1107 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1108 to.Blend(from, 0.0);
1109 EXPECT_EQ(from, to);
1111 double expectedRotationAngle = 22.5 * M_PI / 180.0;
1112 to = Transform();
1113 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1114 to.Blend(from, 0.25);
1115 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1116 0.0,
1117 std::sin(expectedRotationAngle),
1118 0.0,
1120 ERROR_THRESHOLD);
1121 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1122 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle),
1123 0.0,
1124 std::cos(expectedRotationAngle),
1125 0.0,
1127 ERROR_THRESHOLD);
1128 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1130 expectedRotationAngle = 45.0 * M_PI / 180.0;
1131 to = Transform();
1132 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1133 to.Blend(from, 0.5);
1134 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1135 0.0,
1136 std::sin(expectedRotationAngle),
1137 0.0,
1139 ERROR_THRESHOLD);
1140 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1141 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle),
1142 0.0,
1143 std::cos(expectedRotationAngle),
1144 0.0,
1146 ERROR_THRESHOLD);
1147 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1149 to = Transform();
1150 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1151 to.Blend(from, 1.0);
1152 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1153 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1154 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1155 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1158 #if defined(_WIN64)
1159 // http://crbug.com/406574
1160 #define MAYBE_VerifyBlendForRotationAboutZ DISABLED_VerifyBlendForRotationAboutZ
1161 #else
1162 #define MAYBE_VerifyBlendForRotationAboutZ VerifyBlendForRotationAboutZ
1163 #endif
1164 TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutZ) {
1165 Transform from;
1166 from.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 0.0);
1168 Transform to;
1170 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1171 to.Blend(from, 0.0);
1172 EXPECT_EQ(from, to);
1174 double expectedRotationAngle = 22.5 * M_PI / 180.0;
1175 to = Transform();
1176 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1177 to.Blend(from, 0.25);
1178 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1179 -std::sin(expectedRotationAngle),
1180 0.0,
1181 0.0,
1183 ERROR_THRESHOLD);
1184 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle),
1185 std::cos(expectedRotationAngle),
1186 0.0,
1187 0.0,
1189 ERROR_THRESHOLD);
1190 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1191 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1193 expectedRotationAngle = 45.0 * M_PI / 180.0;
1194 to = Transform();
1195 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1196 to.Blend(from, 0.5);
1197 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1198 -std::sin(expectedRotationAngle),
1199 0.0,
1200 0.0,
1202 ERROR_THRESHOLD);
1203 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle),
1204 std::cos(expectedRotationAngle),
1205 0.0,
1206 0.0,
1208 ERROR_THRESHOLD);
1209 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1210 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1212 to = Transform();
1213 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1214 to.Blend(from, 1.0);
1215 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1216 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1217 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1218 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1221 TEST(XFormTest, VerifyBlendForCompositeTransform) {
1222 // Verify that the.Blending was done with a decomposition in correct order
1223 // by blending a composite transform. Using matrix x vector notation
1224 // (Ax = b, where x is column vector), the ordering should be:
1225 // perspective * translation * rotation * skew * scale
1227 // It is not as important (or meaningful) to check intermediate
1228 // interpolations; order of operations will be tested well enough by the
1229 // end cases that are easier to specify.
1231 Transform from;
1232 Transform to;
1234 Transform expectedEndOfAnimation;
1235 expectedEndOfAnimation.ApplyPerspectiveDepth(1.0);
1236 expectedEndOfAnimation.Translate3d(10.0, 20.0, 30.0);
1237 expectedEndOfAnimation.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 25.0);
1238 expectedEndOfAnimation.SkewY(45.0);
1239 expectedEndOfAnimation.Scale3d(6.0, 7.0, 8.0);
1241 to = expectedEndOfAnimation;
1242 to.Blend(from, 0.0);
1243 EXPECT_EQ(from, to);
1245 to = expectedEndOfAnimation;
1246 // We short circuit if blend is >= 1, so to check the numerics, we will
1247 // check that we get close to what we expect when we're nearly done
1248 // interpolating.
1249 to.Blend(from, .99999f);
1251 // Recomposing the matrix results in a normalized matrix, so to verify we
1252 // need to normalize the expectedEndOfAnimation before comparing elements.
1253 // Normalizing means dividing everything by expectedEndOfAnimation.m44().
1254 Transform normalizedExpectedEndOfAnimation = expectedEndOfAnimation;
1255 Transform normalizationMatrix;
1256 normalizationMatrix.matrix().set(
1257 0.0,
1258 0.0,
1259 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1260 normalizationMatrix.matrix().set(
1261 1.0,
1262 1.0,
1263 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1264 normalizationMatrix.matrix().set(
1265 2.0,
1266 2.0,
1267 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1268 normalizationMatrix.matrix().set(
1269 3.0,
1270 3.0,
1271 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1272 normalizedExpectedEndOfAnimation.PreconcatTransform(normalizationMatrix);
1274 EXPECT_TRUE(MatricesAreNearlyEqual(normalizedExpectedEndOfAnimation, to));
1277 TEST(XFormTest, DecomposedTransformCtor) {
1278 DecomposedTransform decomp;
1279 for (int i = 0; i < 3; ++i) {
1280 EXPECT_EQ(0.0, decomp.translate[i]);
1281 EXPECT_EQ(1.0, decomp.scale[i]);
1282 EXPECT_EQ(0.0, decomp.skew[i]);
1283 EXPECT_EQ(0.0, decomp.quaternion[i]);
1284 EXPECT_EQ(0.0, decomp.perspective[i]);
1286 EXPECT_EQ(1.0, decomp.quaternion[3]);
1287 EXPECT_EQ(1.0, decomp.perspective[3]);
1288 Transform identity;
1289 Transform composed = ComposeTransform(decomp);
1290 EXPECT_TRUE(MatricesAreNearlyEqual(identity, composed));
1293 TEST(XFormTest, FactorTRS) {
1294 for (int degrees = 0; degrees < 180; ++degrees) {
1295 // build a transformation matrix.
1296 gfx::Transform transform;
1297 transform.Translate(degrees * 2, -degrees * 3);
1298 transform.Rotate(degrees);
1299 transform.Scale(degrees + 1, 2 * degrees + 1);
1301 // factor the matrix
1302 DecomposedTransform decomp;
1303 bool success = DecomposeTransform(&decomp, transform);
1304 EXPECT_TRUE(success);
1305 EXPECT_FLOAT_EQ(decomp.translate[0], degrees * 2);
1306 EXPECT_FLOAT_EQ(decomp.translate[1], -degrees * 3);
1307 double rotation =
1308 std::acos(SkMScalarToDouble(decomp.quaternion[3])) * 360.0 / M_PI;
1309 while (rotation < 0.0)
1310 rotation += 360.0;
1311 while (rotation > 360.0)
1312 rotation -= 360.0;
1314 const float epsilon = 0.00015f;
1315 EXPECT_NEAR(rotation, degrees, epsilon);
1316 EXPECT_NEAR(decomp.scale[0], degrees + 1, epsilon);
1317 EXPECT_NEAR(decomp.scale[1], 2 * degrees + 1, epsilon);
1321 TEST(XFormTest, DecomposeTransform) {
1322 for (float scale = 0.001f; scale < 2.0f; scale += 0.001f) {
1323 gfx::Transform transform;
1324 transform.Scale(scale, scale);
1325 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
1327 DecomposedTransform decomp;
1328 bool success = DecomposeTransform(&decomp, transform);
1329 EXPECT_TRUE(success);
1331 gfx::Transform compose_transform = ComposeTransform(decomp);
1332 EXPECT_TRUE(compose_transform.Preserves2dAxisAlignment());
1336 TEST(XFormTest, IntegerTranslation) {
1337 gfx::Transform transform;
1338 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1340 transform.Translate3d(1, 2, 3);
1341 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1343 transform.MakeIdentity();
1344 transform.Translate3d(-1, -2, -3);
1345 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1347 transform.MakeIdentity();
1348 transform.Translate3d(4.5f, 0, 0);
1349 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1351 transform.MakeIdentity();
1352 transform.Translate3d(0, -6.7f, 0);
1353 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1355 transform.MakeIdentity();
1356 transform.Translate3d(0, 0, 8.9f);
1357 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1360 TEST(XFormTest, verifyMatrixInversion) {
1362 // Invert a translation
1363 gfx::Transform translation;
1364 translation.Translate3d(2.0, 3.0, 4.0);
1365 EXPECT_TRUE(translation.IsInvertible());
1367 gfx::Transform inverse_translation;
1368 bool is_invertible = translation.GetInverse(&inverse_translation);
1369 EXPECT_TRUE(is_invertible);
1370 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, -2.0f, inverse_translation);
1371 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, -3.0f, inverse_translation);
1372 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, -4.0f, inverse_translation);
1373 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_translation);
1377 // Invert a non-uniform scale
1378 gfx::Transform scale;
1379 scale.Scale3d(4.0, 10.0, 100.0);
1380 EXPECT_TRUE(scale.IsInvertible());
1382 gfx::Transform inverse_scale;
1383 bool is_invertible = scale.GetInverse(&inverse_scale);
1384 EXPECT_TRUE(is_invertible);
1385 EXPECT_ROW1_EQ(0.25f, 0.0f, 0.0f, 0.0f, inverse_scale);
1386 EXPECT_ROW2_EQ(0.0f, 0.1f, 0.0f, 0.0f, inverse_scale);
1387 EXPECT_ROW3_EQ(0.0f, 0.0f, 0.01f, 0.0f, inverse_scale);
1388 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_scale);
1392 // Try to invert a matrix that is not invertible.
1393 // The inverse() function should reset the output matrix to identity.
1394 gfx::Transform uninvertible;
1395 uninvertible.matrix().set(0, 0, 0.f);
1396 uninvertible.matrix().set(1, 1, 0.f);
1397 uninvertible.matrix().set(2, 2, 0.f);
1398 uninvertible.matrix().set(3, 3, 0.f);
1399 EXPECT_FALSE(uninvertible.IsInvertible());
1401 gfx::Transform inverse_of_uninvertible;
1403 // Add a scale just to more easily ensure that inverse_of_uninvertible is
1404 // reset to identity.
1405 inverse_of_uninvertible.Scale3d(4.0, 10.0, 100.0);
1407 bool is_invertible = uninvertible.GetInverse(&inverse_of_uninvertible);
1408 EXPECT_FALSE(is_invertible);
1409 EXPECT_TRUE(inverse_of_uninvertible.IsIdentity());
1410 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, inverse_of_uninvertible);
1411 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, inverse_of_uninvertible);
1412 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, inverse_of_uninvertible);
1413 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_of_uninvertible);
1417 TEST(XFormTest, verifyBackfaceVisibilityBasicCases) {
1418 Transform transform;
1420 transform.MakeIdentity();
1421 EXPECT_FALSE(transform.IsBackFaceVisible());
1423 transform.MakeIdentity();
1424 transform.RotateAboutYAxis(80.0);
1425 EXPECT_FALSE(transform.IsBackFaceVisible());
1427 transform.MakeIdentity();
1428 transform.RotateAboutYAxis(100.0);
1429 EXPECT_TRUE(transform.IsBackFaceVisible());
1431 // Edge case, 90 degree rotation should return false.
1432 transform.MakeIdentity();
1433 transform.RotateAboutYAxis(90.0);
1434 EXPECT_FALSE(transform.IsBackFaceVisible());
1437 TEST(XFormTest, verifyBackfaceVisibilityForPerspective) {
1438 Transform layer_space_to_projection_plane;
1440 // This tests if IsBackFaceVisible works properly under perspective
1441 // transforms. Specifically, layers that may have their back face visible in
1442 // orthographic projection, may not actually have back face visible under
1443 // perspective projection.
1445 // Case 1: Layer is rotated by slightly more than 90 degrees, at the center
1446 // of the prespective projection. In this case, the layer's back-side
1447 // is visible to the camera.
1448 layer_space_to_projection_plane.MakeIdentity();
1449 layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0);
1450 layer_space_to_projection_plane.Translate3d(0.0, 0.0, 0.0);
1451 layer_space_to_projection_plane.RotateAboutYAxis(100.0);
1452 EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible());
1454 // Case 2: Layer is rotated by slightly more than 90 degrees, but shifted off
1455 // to the side of the camera. Because of the wide field-of-view, the
1456 // layer's front side is still visible.
1458 // |<-- front side of layer is visible to camera
1459 // \ | /
1460 // \ | /
1461 // \| /
1462 // | /
1463 // |\ /<-- camera field of view
1464 // | \ /
1465 // back side of layer -->| \ /
1466 // \./ <-- camera origin
1468 layer_space_to_projection_plane.MakeIdentity();
1469 layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0);
1470 layer_space_to_projection_plane.Translate3d(-10.0, 0.0, 0.0);
1471 layer_space_to_projection_plane.RotateAboutYAxis(100.0);
1472 EXPECT_FALSE(layer_space_to_projection_plane.IsBackFaceVisible());
1474 // Case 3: Additionally rotating the layer by 180 degrees should of course
1475 // show the opposite result of case 2.
1476 layer_space_to_projection_plane.RotateAboutYAxis(180.0);
1477 EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible());
1480 TEST(XFormTest, verifyDefaultConstructorCreatesIdentityMatrix) {
1481 Transform A;
1482 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1483 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1484 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1485 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1486 EXPECT_TRUE(A.IsIdentity());
1489 TEST(XFormTest, verifyCopyConstructor) {
1490 Transform A;
1491 InitializeTestMatrix(&A);
1493 // Copy constructor should produce exact same elements as matrix A.
1494 Transform B(A);
1495 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B);
1496 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B);
1497 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B);
1498 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B);
1501 TEST(XFormTest, verifyConstructorFor16Elements) {
1502 Transform transform(1.0, 2.0, 3.0, 4.0,
1503 5.0, 6.0, 7.0, 8.0,
1504 9.0, 10.0, 11.0, 12.0,
1505 13.0, 14.0, 15.0, 16.0);
1507 EXPECT_ROW1_EQ(1.0f, 2.0f, 3.0f, 4.0f, transform);
1508 EXPECT_ROW2_EQ(5.0f, 6.0f, 7.0f, 8.0f, transform);
1509 EXPECT_ROW3_EQ(9.0f, 10.0f, 11.0f, 12.0f, transform);
1510 EXPECT_ROW4_EQ(13.0f, 14.0f, 15.0f, 16.0f, transform);
1513 TEST(XFormTest, verifyConstructorFor2dElements) {
1514 Transform transform(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
1516 EXPECT_ROW1_EQ(1.0f, 2.0f, 0.0f, 5.0f, transform);
1517 EXPECT_ROW2_EQ(3.0f, 4.0f, 0.0f, 6.0f, transform);
1518 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, transform);
1519 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, transform);
1523 TEST(XFormTest, verifyAssignmentOperator) {
1524 Transform A;
1525 InitializeTestMatrix(&A);
1526 Transform B;
1527 InitializeTestMatrix2(&B);
1528 Transform C;
1529 InitializeTestMatrix2(&C);
1530 C = B = A;
1532 // Both B and C should now have been re-assigned to the value of A.
1533 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B);
1534 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B);
1535 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B);
1536 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B);
1538 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, C);
1539 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, C);
1540 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, C);
1541 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, C);
1544 TEST(XFormTest, verifyEqualsBooleanOperator) {
1545 Transform A;
1546 InitializeTestMatrix(&A);
1548 Transform B;
1549 InitializeTestMatrix(&B);
1550 EXPECT_TRUE(A == B);
1552 // Modifying multiple elements should cause equals operator to return false.
1553 Transform C;
1554 InitializeTestMatrix2(&C);
1555 EXPECT_FALSE(A == C);
1557 // Modifying any one individual element should cause equals operator to
1558 // return false.
1559 Transform D;
1560 D = A;
1561 D.matrix().set(0, 0, 0.f);
1562 EXPECT_FALSE(A == D);
1564 D = A;
1565 D.matrix().set(1, 0, 0.f);
1566 EXPECT_FALSE(A == D);
1568 D = A;
1569 D.matrix().set(2, 0, 0.f);
1570 EXPECT_FALSE(A == D);
1572 D = A;
1573 D.matrix().set(3, 0, 0.f);
1574 EXPECT_FALSE(A == D);
1576 D = A;
1577 D.matrix().set(0, 1, 0.f);
1578 EXPECT_FALSE(A == D);
1580 D = A;
1581 D.matrix().set(1, 1, 0.f);
1582 EXPECT_FALSE(A == D);
1584 D = A;
1585 D.matrix().set(2, 1, 0.f);
1586 EXPECT_FALSE(A == D);
1588 D = A;
1589 D.matrix().set(3, 1, 0.f);
1590 EXPECT_FALSE(A == D);
1592 D = A;
1593 D.matrix().set(0, 2, 0.f);
1594 EXPECT_FALSE(A == D);
1596 D = A;
1597 D.matrix().set(1, 2, 0.f);
1598 EXPECT_FALSE(A == D);
1600 D = A;
1601 D.matrix().set(2, 2, 0.f);
1602 EXPECT_FALSE(A == D);
1604 D = A;
1605 D.matrix().set(3, 2, 0.f);
1606 EXPECT_FALSE(A == D);
1608 D = A;
1609 D.matrix().set(0, 3, 0.f);
1610 EXPECT_FALSE(A == D);
1612 D = A;
1613 D.matrix().set(1, 3, 0.f);
1614 EXPECT_FALSE(A == D);
1616 D = A;
1617 D.matrix().set(2, 3, 0.f);
1618 EXPECT_FALSE(A == D);
1620 D = A;
1621 D.matrix().set(3, 3, 0.f);
1622 EXPECT_FALSE(A == D);
1625 TEST(XFormTest, verifyMultiplyOperator) {
1626 Transform A;
1627 InitializeTestMatrix(&A);
1629 Transform B;
1630 InitializeTestMatrix2(&B);
1632 Transform C = A * B;
1633 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, C);
1634 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, C);
1635 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, C);
1636 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, C);
1638 // Just an additional sanity check; matrix multiplication is not commutative.
1639 EXPECT_FALSE(A * B == B * A);
1642 TEST(XFormTest, verifyMultiplyAndAssignOperator) {
1643 Transform A;
1644 InitializeTestMatrix(&A);
1646 Transform B;
1647 InitializeTestMatrix2(&B);
1649 A *= B;
1650 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
1651 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
1652 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
1653 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
1655 // Just an additional sanity check; matrix multiplication is not commutative.
1656 Transform C = A;
1657 C *= B;
1658 Transform D = B;
1659 D *= A;
1660 EXPECT_FALSE(C == D);
1663 TEST(XFormTest, verifyMatrixMultiplication) {
1664 Transform A;
1665 InitializeTestMatrix(&A);
1667 Transform B;
1668 InitializeTestMatrix2(&B);
1670 A.PreconcatTransform(B);
1671 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
1672 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
1673 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
1674 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
1677 TEST(XFormTest, verifyMakeIdentiy) {
1678 Transform A;
1679 InitializeTestMatrix(&A);
1680 A.MakeIdentity();
1681 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1682 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1683 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1684 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1685 EXPECT_TRUE(A.IsIdentity());
1688 TEST(XFormTest, verifyTranslate) {
1689 Transform A;
1690 A.Translate(2.0, 3.0);
1691 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
1692 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
1693 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1694 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1696 // Verify that Translate() post-multiplies the existing matrix.
1697 A.MakeIdentity();
1698 A.Scale(5.0, 5.0);
1699 A.Translate(2.0, 3.0);
1700 EXPECT_ROW1_EQ(5.0f, 0.0f, 0.0f, 10.0f, A);
1701 EXPECT_ROW2_EQ(0.0f, 5.0f, 0.0f, 15.0f, A);
1702 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1703 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1706 TEST(XFormTest, verifyTranslate3d) {
1707 Transform A;
1708 A.Translate3d(2.0, 3.0, 4.0);
1709 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
1710 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
1711 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
1712 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1714 // Verify that Translate3d() post-multiplies the existing matrix.
1715 A.MakeIdentity();
1716 A.Scale3d(6.0, 7.0, 8.0);
1717 A.Translate3d(2.0, 3.0, 4.0);
1718 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 12.0f, A);
1719 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 21.0f, A);
1720 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 32.0f, A);
1721 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1724 TEST(XFormTest, verifyScale) {
1725 Transform A;
1726 A.Scale(6.0, 7.0);
1727 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
1728 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
1729 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1730 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1732 // Verify that Scale() post-multiplies the existing matrix.
1733 A.MakeIdentity();
1734 A.Translate3d(2.0, 3.0, 4.0);
1735 A.Scale(6.0, 7.0);
1736 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
1737 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
1738 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
1739 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1742 TEST(XFormTest, verifyScale3d) {
1743 Transform A;
1744 A.Scale3d(6.0, 7.0, 8.0);
1745 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
1746 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
1747 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1748 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1750 // Verify that scale3d() post-multiplies the existing matrix.
1751 A.MakeIdentity();
1752 A.Translate3d(2.0, 3.0, 4.0);
1753 A.Scale3d(6.0, 7.0, 8.0);
1754 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
1755 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
1756 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 4.0f, A);
1757 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1760 TEST(XFormTest, verifyRotate) {
1761 Transform A;
1762 A.Rotate(90.0);
1763 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1764 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1765 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1766 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1768 // Verify that Rotate() post-multiplies the existing matrix.
1769 A.MakeIdentity();
1770 A.Scale3d(6.0, 7.0, 8.0);
1771 A.Rotate(90.0);
1772 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1773 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1774 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1775 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1778 TEST(XFormTest, verifyRotateAboutXAxis) {
1779 Transform A;
1780 double sin45 = 0.5 * sqrt(2.0);
1781 double cos45 = sin45;
1783 A.MakeIdentity();
1784 A.RotateAboutXAxis(90.0);
1785 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1786 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD);
1787 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1788 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1790 A.MakeIdentity();
1791 A.RotateAboutXAxis(45.0);
1792 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1793 EXPECT_ROW2_NEAR(0.0, cos45, -sin45, 0.0, A, ERROR_THRESHOLD);
1794 EXPECT_ROW3_NEAR(0.0, sin45, cos45, 0.0, A, ERROR_THRESHOLD);
1795 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1797 // Verify that RotateAboutXAxis(angle) post-multiplies the existing matrix.
1798 A.MakeIdentity();
1799 A.Scale3d(6.0, 7.0, 8.0);
1800 A.RotateAboutXAxis(90.0);
1801 EXPECT_ROW1_NEAR(6.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1802 EXPECT_ROW2_NEAR(0.0, 0.0, -7.0, 0.0, A, ERROR_THRESHOLD);
1803 EXPECT_ROW3_NEAR(0.0, 8.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1804 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1807 TEST(XFormTest, verifyRotateAboutYAxis) {
1808 Transform A;
1809 double sin45 = 0.5 * sqrt(2.0);
1810 double cos45 = sin45;
1812 // Note carefully, the expected pattern is inverted compared to rotating
1813 // about x axis or z axis.
1814 A.MakeIdentity();
1815 A.RotateAboutYAxis(90.0);
1816 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD);
1817 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1818 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1819 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1821 A.MakeIdentity();
1822 A.RotateAboutYAxis(45.0);
1823 EXPECT_ROW1_NEAR(cos45, 0.0, sin45, 0.0, A, ERROR_THRESHOLD);
1824 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1825 EXPECT_ROW3_NEAR(-sin45, 0.0, cos45, 0.0, A, ERROR_THRESHOLD);
1826 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1828 // Verify that RotateAboutYAxis(angle) post-multiplies the existing matrix.
1829 A.MakeIdentity();
1830 A.Scale3d(6.0, 7.0, 8.0);
1831 A.RotateAboutYAxis(90.0);
1832 EXPECT_ROW1_NEAR(0.0, 0.0, 6.0, 0.0, A, ERROR_THRESHOLD);
1833 EXPECT_ROW2_NEAR(0.0, 7.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1834 EXPECT_ROW3_NEAR(-8.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1835 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1838 TEST(XFormTest, verifyRotateAboutZAxis) {
1839 Transform A;
1840 double sin45 = 0.5 * sqrt(2.0);
1841 double cos45 = sin45;
1843 A.MakeIdentity();
1844 A.RotateAboutZAxis(90.0);
1845 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1846 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1847 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1848 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1850 A.MakeIdentity();
1851 A.RotateAboutZAxis(45.0);
1852 EXPECT_ROW1_NEAR(cos45, -sin45, 0.0, 0.0, A, ERROR_THRESHOLD);
1853 EXPECT_ROW2_NEAR(sin45, cos45, 0.0, 0.0, A, ERROR_THRESHOLD);
1854 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1855 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1857 // Verify that RotateAboutZAxis(angle) post-multiplies the existing matrix.
1858 A.MakeIdentity();
1859 A.Scale3d(6.0, 7.0, 8.0);
1860 A.RotateAboutZAxis(90.0);
1861 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1862 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1863 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1864 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1867 TEST(XFormTest, verifyRotateAboutForAlignedAxes) {
1868 Transform A;
1870 // Check rotation about z-axis
1871 A.MakeIdentity();
1872 A.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1873 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1874 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1875 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1876 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1878 // Check rotation about x-axis
1879 A.MakeIdentity();
1880 A.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1881 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1882 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD);
1883 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1884 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1886 // Check rotation about y-axis. Note carefully, the expected pattern is
1887 // inverted compared to rotating about x axis or z axis.
1888 A.MakeIdentity();
1889 A.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1890 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD);
1891 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1892 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1893 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1895 // Verify that rotate3d(axis, angle) post-multiplies the existing matrix.
1896 A.MakeIdentity();
1897 A.Scale3d(6.0, 7.0, 8.0);
1898 A.RotateAboutZAxis(90.0);
1899 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1900 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1901 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1902 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1905 TEST(XFormTest, verifyRotateAboutForArbitraryAxis) {
1906 // Check rotation about an arbitrary non-axis-aligned vector.
1907 Transform A;
1908 A.RotateAbout(Vector3dF(1.0, 1.0, 1.0), 90.0);
1909 EXPECT_ROW1_NEAR(0.3333333333333334258519187,
1910 -0.2440169358562924717404030,
1911 0.9106836025229592124219380,
1912 0.0, A, ERROR_THRESHOLD);
1913 EXPECT_ROW2_NEAR(0.9106836025229592124219380,
1914 0.3333333333333334258519187,
1915 -0.2440169358562924717404030,
1916 0.0, A, ERROR_THRESHOLD);
1917 EXPECT_ROW3_NEAR(-0.2440169358562924717404030,
1918 0.9106836025229592124219380,
1919 0.3333333333333334258519187,
1920 0.0, A, ERROR_THRESHOLD);
1921 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1924 TEST(XFormTest, verifyRotateAboutForDegenerateAxis) {
1925 // Check rotation about a degenerate zero vector.
1926 // It is expected to skip applying the rotation.
1927 Transform A;
1929 A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 45.0);
1930 // Verify that A remains unchanged.
1931 EXPECT_TRUE(A.IsIdentity());
1933 InitializeTestMatrix(&A);
1934 A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 35.0);
1936 // Verify that A remains unchanged.
1937 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, A);
1938 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, A);
1939 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, A);
1940 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, A);
1943 TEST(XFormTest, verifySkewX) {
1944 Transform A;
1945 A.SkewX(45.0);
1946 EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
1947 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1948 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1949 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1951 // Verify that skewX() post-multiplies the existing matrix. Row 1, column 2,
1952 // would incorrectly have value "7" if the matrix is pre-multiplied instead
1953 // of post-multiplied.
1954 A.MakeIdentity();
1955 A.Scale3d(6.0, 7.0, 8.0);
1956 A.SkewX(45.0);
1957 EXPECT_ROW1_EQ(6.0f, 6.0f, 0.0f, 0.0f, A);
1958 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
1959 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1960 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1963 TEST(XFormTest, verifySkewY) {
1964 Transform A;
1965 A.SkewY(45.0);
1966 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1967 EXPECT_ROW2_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
1968 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1969 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1971 // Verify that skewY() post-multiplies the existing matrix. Row 2, column 1 ,
1972 // would incorrectly have value "6" if the matrix is pre-multiplied instead
1973 // of post-multiplied.
1974 A.MakeIdentity();
1975 A.Scale3d(6.0, 7.0, 8.0);
1976 A.SkewY(45.0);
1977 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
1978 EXPECT_ROW2_EQ(7.0f, 7.0f, 0.0f, 0.0f, A);
1979 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1980 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1983 TEST(XFormTest, verifyPerspectiveDepth) {
1984 Transform A;
1985 A.ApplyPerspectiveDepth(1.0);
1986 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1987 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1988 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1989 EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
1991 // Verify that PerspectiveDepth() post-multiplies the existing matrix.
1992 A.MakeIdentity();
1993 A.Translate3d(2.0, 3.0, 4.0);
1994 A.ApplyPerspectiveDepth(1.0);
1995 EXPECT_ROW1_EQ(1.0f, 0.0f, -2.0f, 2.0f, A);
1996 EXPECT_ROW2_EQ(0.0f, 1.0f, -3.0f, 3.0f, A);
1997 EXPECT_ROW3_EQ(0.0f, 0.0f, -3.0f, 4.0f, A);
1998 EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
2001 TEST(XFormTest, verifyHasPerspective) {
2002 Transform A;
2003 A.ApplyPerspectiveDepth(1.0);
2004 EXPECT_TRUE(A.HasPerspective());
2006 A.MakeIdentity();
2007 A.ApplyPerspectiveDepth(0.0);
2008 EXPECT_FALSE(A.HasPerspective());
2010 A.MakeIdentity();
2011 A.matrix().set(3, 0, -1.f);
2012 EXPECT_TRUE(A.HasPerspective());
2014 A.MakeIdentity();
2015 A.matrix().set(3, 1, -1.f);
2016 EXPECT_TRUE(A.HasPerspective());
2018 A.MakeIdentity();
2019 A.matrix().set(3, 2, -0.3f);
2020 EXPECT_TRUE(A.HasPerspective());
2022 A.MakeIdentity();
2023 A.matrix().set(3, 3, 0.5f);
2024 EXPECT_TRUE(A.HasPerspective());
2026 A.MakeIdentity();
2027 A.matrix().set(3, 3, 0.f);
2028 EXPECT_TRUE(A.HasPerspective());
2031 TEST(XFormTest, verifyIsInvertible) {
2032 Transform A;
2034 // Translations, rotations, scales, skews and arbitrary combinations of them
2035 // are invertible.
2036 A.MakeIdentity();
2037 EXPECT_TRUE(A.IsInvertible());
2039 A.MakeIdentity();
2040 A.Translate3d(2.0, 3.0, 4.0);
2041 EXPECT_TRUE(A.IsInvertible());
2043 A.MakeIdentity();
2044 A.Scale3d(6.0, 7.0, 8.0);
2045 EXPECT_TRUE(A.IsInvertible());
2047 A.MakeIdentity();
2048 A.RotateAboutXAxis(10.0);
2049 A.RotateAboutYAxis(20.0);
2050 A.RotateAboutZAxis(30.0);
2051 EXPECT_TRUE(A.IsInvertible());
2053 A.MakeIdentity();
2054 A.SkewX(45.0);
2055 EXPECT_TRUE(A.IsInvertible());
2057 // A perspective matrix (projection plane at z=0) is invertible. The
2058 // intuitive explanation is that perspective is eqivalent to a skew of the
2059 // w-axis; skews are invertible.
2060 A.MakeIdentity();
2061 A.ApplyPerspectiveDepth(1.0);
2062 EXPECT_TRUE(A.IsInvertible());
2064 // A "pure" perspective matrix derived by similar triangles, with m44() set
2065 // to zero (i.e. camera positioned at the origin), is not invertible.
2066 A.MakeIdentity();
2067 A.ApplyPerspectiveDepth(1.0);
2068 A.matrix().set(3, 3, 0.f);
2069 EXPECT_FALSE(A.IsInvertible());
2071 // Adding more to a non-invertible matrix will not make it invertible in the
2072 // general case.
2073 A.MakeIdentity();
2074 A.ApplyPerspectiveDepth(1.0);
2075 A.matrix().set(3, 3, 0.f);
2076 A.Scale3d(6.0, 7.0, 8.0);
2077 A.RotateAboutXAxis(10.0);
2078 A.RotateAboutYAxis(20.0);
2079 A.RotateAboutZAxis(30.0);
2080 A.Translate3d(6.0, 7.0, 8.0);
2081 EXPECT_FALSE(A.IsInvertible());
2083 // A degenerate matrix of all zeros is not invertible.
2084 A.MakeIdentity();
2085 A.matrix().set(0, 0, 0.f);
2086 A.matrix().set(1, 1, 0.f);
2087 A.matrix().set(2, 2, 0.f);
2088 A.matrix().set(3, 3, 0.f);
2089 EXPECT_FALSE(A.IsInvertible());
2092 TEST(XFormTest, verifyIsIdentity) {
2093 Transform A;
2095 InitializeTestMatrix(&A);
2096 EXPECT_FALSE(A.IsIdentity());
2098 A.MakeIdentity();
2099 EXPECT_TRUE(A.IsIdentity());
2101 // Modifying any one individual element should cause the matrix to no longer
2102 // be identity.
2103 A.MakeIdentity();
2104 A.matrix().set(0, 0, 2.f);
2105 EXPECT_FALSE(A.IsIdentity());
2107 A.MakeIdentity();
2108 A.matrix().set(1, 0, 2.f);
2109 EXPECT_FALSE(A.IsIdentity());
2111 A.MakeIdentity();
2112 A.matrix().set(2, 0, 2.f);
2113 EXPECT_FALSE(A.IsIdentity());
2115 A.MakeIdentity();
2116 A.matrix().set(3, 0, 2.f);
2117 EXPECT_FALSE(A.IsIdentity());
2119 A.MakeIdentity();
2120 A.matrix().set(0, 1, 2.f);
2121 EXPECT_FALSE(A.IsIdentity());
2123 A.MakeIdentity();
2124 A.matrix().set(1, 1, 2.f);
2125 EXPECT_FALSE(A.IsIdentity());
2127 A.MakeIdentity();
2128 A.matrix().set(2, 1, 2.f);
2129 EXPECT_FALSE(A.IsIdentity());
2131 A.MakeIdentity();
2132 A.matrix().set(3, 1, 2.f);
2133 EXPECT_FALSE(A.IsIdentity());
2135 A.MakeIdentity();
2136 A.matrix().set(0, 2, 2.f);
2137 EXPECT_FALSE(A.IsIdentity());
2139 A.MakeIdentity();
2140 A.matrix().set(1, 2, 2.f);
2141 EXPECT_FALSE(A.IsIdentity());
2143 A.MakeIdentity();
2144 A.matrix().set(2, 2, 2.f);
2145 EXPECT_FALSE(A.IsIdentity());
2147 A.MakeIdentity();
2148 A.matrix().set(3, 2, 2.f);
2149 EXPECT_FALSE(A.IsIdentity());
2151 A.MakeIdentity();
2152 A.matrix().set(0, 3, 2.f);
2153 EXPECT_FALSE(A.IsIdentity());
2155 A.MakeIdentity();
2156 A.matrix().set(1, 3, 2.f);
2157 EXPECT_FALSE(A.IsIdentity());
2159 A.MakeIdentity();
2160 A.matrix().set(2, 3, 2.f);
2161 EXPECT_FALSE(A.IsIdentity());
2163 A.MakeIdentity();
2164 A.matrix().set(3, 3, 2.f);
2165 EXPECT_FALSE(A.IsIdentity());
2168 TEST(XFormTest, verifyIsIdentityOrTranslation) {
2169 Transform A;
2171 InitializeTestMatrix(&A);
2172 EXPECT_FALSE(A.IsIdentityOrTranslation());
2174 A.MakeIdentity();
2175 EXPECT_TRUE(A.IsIdentityOrTranslation());
2177 // Modifying any non-translation components should cause
2178 // IsIdentityOrTranslation() to return false. NOTE: (0, 3), (1, 3), and
2179 // (2, 3) are the translation components, so modifying them should still
2180 // return true.
2181 A.MakeIdentity();
2182 A.matrix().set(0, 0, 2.f);
2183 EXPECT_FALSE(A.IsIdentityOrTranslation());
2185 A.MakeIdentity();
2186 A.matrix().set(1, 0, 2.f);
2187 EXPECT_FALSE(A.IsIdentityOrTranslation());
2189 A.MakeIdentity();
2190 A.matrix().set(2, 0, 2.f);
2191 EXPECT_FALSE(A.IsIdentityOrTranslation());
2193 A.MakeIdentity();
2194 A.matrix().set(3, 0, 2.f);
2195 EXPECT_FALSE(A.IsIdentityOrTranslation());
2197 A.MakeIdentity();
2198 A.matrix().set(0, 1, 2.f);
2199 EXPECT_FALSE(A.IsIdentityOrTranslation());
2201 A.MakeIdentity();
2202 A.matrix().set(1, 1, 2.f);
2203 EXPECT_FALSE(A.IsIdentityOrTranslation());
2205 A.MakeIdentity();
2206 A.matrix().set(2, 1, 2.f);
2207 EXPECT_FALSE(A.IsIdentityOrTranslation());
2209 A.MakeIdentity();
2210 A.matrix().set(3, 1, 2.f);
2211 EXPECT_FALSE(A.IsIdentityOrTranslation());
2213 A.MakeIdentity();
2214 A.matrix().set(0, 2, 2.f);
2215 EXPECT_FALSE(A.IsIdentityOrTranslation());
2217 A.MakeIdentity();
2218 A.matrix().set(1, 2, 2.f);
2219 EXPECT_FALSE(A.IsIdentityOrTranslation());
2221 A.MakeIdentity();
2222 A.matrix().set(2, 2, 2.f);
2223 EXPECT_FALSE(A.IsIdentityOrTranslation());
2225 A.MakeIdentity();
2226 A.matrix().set(3, 2, 2.f);
2227 EXPECT_FALSE(A.IsIdentityOrTranslation());
2229 // Note carefully - expecting true here.
2230 A.MakeIdentity();
2231 A.matrix().set(0, 3, 2.f);
2232 EXPECT_TRUE(A.IsIdentityOrTranslation());
2234 // Note carefully - expecting true here.
2235 A.MakeIdentity();
2236 A.matrix().set(1, 3, 2.f);
2237 EXPECT_TRUE(A.IsIdentityOrTranslation());
2239 // Note carefully - expecting true here.
2240 A.MakeIdentity();
2241 A.matrix().set(2, 3, 2.f);
2242 EXPECT_TRUE(A.IsIdentityOrTranslation());
2244 A.MakeIdentity();
2245 A.matrix().set(3, 3, 2.f);
2246 EXPECT_FALSE(A.IsIdentityOrTranslation());
2249 TEST(XFormTest, verifyIsApproximatelyIdentityOrTranslation) {
2250 Transform A;
2251 SkMatrix44& matrix = A.matrix();
2253 // Exact pure translation.
2254 A.MakeIdentity();
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_TRUE(A.IsApproximatelyIdentityOrTranslation(0));
2262 EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2264 // 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 translate values to values other than 0 or 1.
2274 matrix.set(0, 3, 3.4f);
2275 matrix.set(1, 3, 4.4f);
2276 matrix.set(2, 3, 5.6f);
2278 EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
2279 EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2281 // Not approximately pure translation.
2282 InitializeApproxIdentityMatrix(&A);
2284 // Some values must be exact.
2285 matrix.set(3, 0, 0);
2286 matrix.set(3, 1, 0);
2287 matrix.set(3, 2, 0);
2288 matrix.set(3, 3, 1);
2290 // Set some values (not translate values) to values other than 0 or 1.
2291 matrix.set(0, 1, 3.4f);
2292 matrix.set(3, 2, 4.4f);
2293 matrix.set(2, 0, 5.6f);
2295 EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
2296 EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2299 TEST(XFormTest, verifyIsScaleOrTranslation) {
2300 Transform A;
2302 InitializeTestMatrix(&A);
2303 EXPECT_FALSE(A.IsScaleOrTranslation());
2305 A.MakeIdentity();
2306 EXPECT_TRUE(A.IsScaleOrTranslation());
2308 // Modifying any non-scale or non-translation components should cause
2309 // IsScaleOrTranslation() to return false. (0, 0), (1, 1), (2, 2), (0, 3),
2310 // (1, 3), and (2, 3) are the scale and translation components, so
2311 // modifying them should still return true.
2313 // Note carefully - expecting true here.
2314 A.MakeIdentity();
2315 A.matrix().set(0, 0, 2.f);
2316 EXPECT_TRUE(A.IsScaleOrTranslation());
2318 A.MakeIdentity();
2319 A.matrix().set(1, 0, 2.f);
2320 EXPECT_FALSE(A.IsScaleOrTranslation());
2322 A.MakeIdentity();
2323 A.matrix().set(2, 0, 2.f);
2324 EXPECT_FALSE(A.IsScaleOrTranslation());
2326 A.MakeIdentity();
2327 A.matrix().set(3, 0, 2.f);
2328 EXPECT_FALSE(A.IsScaleOrTranslation());
2330 A.MakeIdentity();
2331 A.matrix().set(0, 1, 2.f);
2332 EXPECT_FALSE(A.IsScaleOrTranslation());
2334 // Note carefully - expecting true here.
2335 A.MakeIdentity();
2336 A.matrix().set(1, 1, 2.f);
2337 EXPECT_TRUE(A.IsScaleOrTranslation());
2339 A.MakeIdentity();
2340 A.matrix().set(2, 1, 2.f);
2341 EXPECT_FALSE(A.IsScaleOrTranslation());
2343 A.MakeIdentity();
2344 A.matrix().set(3, 1, 2.f);
2345 EXPECT_FALSE(A.IsScaleOrTranslation());
2347 A.MakeIdentity();
2348 A.matrix().set(0, 2, 2.f);
2349 EXPECT_FALSE(A.IsScaleOrTranslation());
2351 A.MakeIdentity();
2352 A.matrix().set(1, 2, 2.f);
2353 EXPECT_FALSE(A.IsScaleOrTranslation());
2355 // Note carefully - expecting true here.
2356 A.MakeIdentity();
2357 A.matrix().set(2, 2, 2.f);
2358 EXPECT_TRUE(A.IsScaleOrTranslation());
2360 A.MakeIdentity();
2361 A.matrix().set(3, 2, 2.f);
2362 EXPECT_FALSE(A.IsScaleOrTranslation());
2364 // Note carefully - expecting true here.
2365 A.MakeIdentity();
2366 A.matrix().set(0, 3, 2.f);
2367 EXPECT_TRUE(A.IsScaleOrTranslation());
2369 // Note carefully - expecting true here.
2370 A.MakeIdentity();
2371 A.matrix().set(1, 3, 2.f);
2372 EXPECT_TRUE(A.IsScaleOrTranslation());
2374 // Note carefully - expecting true here.
2375 A.MakeIdentity();
2376 A.matrix().set(2, 3, 2.f);
2377 EXPECT_TRUE(A.IsScaleOrTranslation());
2379 A.MakeIdentity();
2380 A.matrix().set(3, 3, 2.f);
2381 EXPECT_FALSE(A.IsScaleOrTranslation());
2384 TEST(XFormTest, verifyFlattenTo2d) {
2385 Transform A;
2386 InitializeTestMatrix(&A);
2388 A.FlattenTo2d();
2389 EXPECT_ROW1_EQ(10.0f, 14.0f, 0.0f, 22.0f, A);
2390 EXPECT_ROW2_EQ(11.0f, 15.0f, 0.0f, 23.0f, A);
2391 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
2392 EXPECT_ROW4_EQ(13.0f, 17.0f, 0.0f, 25.0f, A);
2395 TEST(XFormTest, IsFlat) {
2396 Transform transform;
2397 InitializeTestMatrix(&transform);
2399 // A transform with all entries non-zero isn't flat.
2400 EXPECT_FALSE(transform.IsFlat());
2402 transform.matrix().set(0, 2, 0.f);
2403 transform.matrix().set(1, 2, 0.f);
2404 transform.matrix().set(2, 2, 1.f);
2405 transform.matrix().set(3, 2, 0.f);
2407 EXPECT_FALSE(transform.IsFlat());
2409 transform.matrix().set(2, 0, 0.f);
2410 transform.matrix().set(2, 1, 0.f);
2411 transform.matrix().set(2, 3, 0.f);
2413 // Since the third column and row are both (0, 0, 1, 0), the transform is
2414 // flat.
2415 EXPECT_TRUE(transform.IsFlat());
2418 // Another implementation of Preserves2dAxisAlignment that isn't as fast,
2419 // good for testing the faster implementation.
2420 static bool EmpiricallyPreserves2dAxisAlignment(const Transform& transform) {
2421 Point3F p1(5.0f, 5.0f, 0.0f);
2422 Point3F p2(10.0f, 5.0f, 0.0f);
2423 Point3F p3(10.0f, 20.0f, 0.0f);
2424 Point3F p4(5.0f, 20.0f, 0.0f);
2426 QuadF test_quad(PointF(p1.x(), p1.y()),
2427 PointF(p2.x(), p2.y()),
2428 PointF(p3.x(), p3.y()),
2429 PointF(p4.x(), p4.y()));
2430 EXPECT_TRUE(test_quad.IsRectilinear());
2432 transform.TransformPoint(&p1);
2433 transform.TransformPoint(&p2);
2434 transform.TransformPoint(&p3);
2435 transform.TransformPoint(&p4);
2437 QuadF transformedQuad(PointF(p1.x(), p1.y()),
2438 PointF(p2.x(), p2.y()),
2439 PointF(p3.x(), p3.y()),
2440 PointF(p4.x(), p4.y()));
2441 return transformedQuad.IsRectilinear();
2444 TEST(XFormTest, Preserves2dAxisAlignment) {
2445 static const struct TestCase {
2446 SkMScalar a; // row 1, column 1
2447 SkMScalar b; // row 1, column 2
2448 SkMScalar c; // row 2, column 1
2449 SkMScalar d; // row 2, column 2
2450 bool expected;
2451 } test_cases[] = {
2452 { 3.f, 0.f,
2453 0.f, 4.f, true }, // basic case
2454 { 0.f, 4.f,
2455 3.f, 0.f, true }, // rotate by 90
2456 { 0.f, 0.f,
2457 0.f, 4.f, true }, // degenerate x
2458 { 3.f, 0.f,
2459 0.f, 0.f, true }, // degenerate y
2460 { 0.f, 0.f,
2461 3.f, 0.f, true }, // degenerate x + rotate by 90
2462 { 0.f, 4.f,
2463 0.f, 0.f, true }, // degenerate y + rotate by 90
2464 { 3.f, 4.f,
2465 0.f, 0.f, false },
2466 { 0.f, 0.f,
2467 3.f, 4.f, false },
2468 { 0.f, 3.f,
2469 0.f, 4.f, false },
2470 { 3.f, 0.f,
2471 4.f, 0.f, false },
2472 { 3.f, 4.f,
2473 5.f, 0.f, false },
2474 { 3.f, 4.f,
2475 0.f, 5.f, false },
2476 { 3.f, 0.f,
2477 4.f, 5.f, false },
2478 { 0.f, 3.f,
2479 4.f, 5.f, false },
2480 { 2.f, 3.f,
2481 4.f, 5.f, false },
2484 Transform transform;
2485 for (size_t i = 0; i < arraysize(test_cases); ++i) {
2486 const TestCase& value = test_cases[i];
2487 transform.MakeIdentity();
2488 transform.matrix().set(0, 0, value.a);
2489 transform.matrix().set(0, 1, value.b);
2490 transform.matrix().set(1, 0, value.c);
2491 transform.matrix().set(1, 1, value.d);
2493 if (value.expected) {
2494 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2495 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2496 } else {
2497 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2498 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2502 // Try the same test cases again, but this time make sure that other matrix
2503 // elements (except perspective) have entries, to test that they are ignored.
2504 for (size_t i = 0; i < arraysize(test_cases); ++i) {
2505 const TestCase& value = test_cases[i];
2506 transform.MakeIdentity();
2507 transform.matrix().set(0, 0, value.a);
2508 transform.matrix().set(0, 1, value.b);
2509 transform.matrix().set(1, 0, value.c);
2510 transform.matrix().set(1, 1, value.d);
2512 transform.matrix().set(0, 2, 1.f);
2513 transform.matrix().set(0, 3, 2.f);
2514 transform.matrix().set(1, 2, 3.f);
2515 transform.matrix().set(1, 3, 4.f);
2516 transform.matrix().set(2, 0, 5.f);
2517 transform.matrix().set(2, 1, 6.f);
2518 transform.matrix().set(2, 2, 7.f);
2519 transform.matrix().set(2, 3, 8.f);
2521 if (value.expected) {
2522 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2523 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2524 } else {
2525 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2526 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2530 // Try the same test cases again, but this time add perspective which is
2531 // always assumed to not-preserve axis alignment.
2532 for (size_t i = 0; i < arraysize(test_cases); ++i) {
2533 const TestCase& value = test_cases[i];
2534 transform.MakeIdentity();
2535 transform.matrix().set(0, 0, value.a);
2536 transform.matrix().set(0, 1, value.b);
2537 transform.matrix().set(1, 0, value.c);
2538 transform.matrix().set(1, 1, value.d);
2540 transform.matrix().set(0, 2, 1.f);
2541 transform.matrix().set(0, 3, 2.f);
2542 transform.matrix().set(1, 2, 3.f);
2543 transform.matrix().set(1, 3, 4.f);
2544 transform.matrix().set(2, 0, 5.f);
2545 transform.matrix().set(2, 1, 6.f);
2546 transform.matrix().set(2, 2, 7.f);
2547 transform.matrix().set(2, 3, 8.f);
2548 transform.matrix().set(3, 0, 9.f);
2549 transform.matrix().set(3, 1, 10.f);
2550 transform.matrix().set(3, 2, 11.f);
2551 transform.matrix().set(3, 3, 12.f);
2553 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2554 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2557 // Try a few more practical situations to check precision
2558 transform.MakeIdentity();
2559 transform.RotateAboutZAxis(90.0);
2560 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2561 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2563 transform.MakeIdentity();
2564 transform.RotateAboutZAxis(180.0);
2565 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2566 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2568 transform.MakeIdentity();
2569 transform.RotateAboutZAxis(270.0);
2570 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2571 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2573 transform.MakeIdentity();
2574 transform.RotateAboutYAxis(90.0);
2575 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2576 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2578 transform.MakeIdentity();
2579 transform.RotateAboutXAxis(90.0);
2580 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2581 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2583 transform.MakeIdentity();
2584 transform.RotateAboutZAxis(90.0);
2585 transform.RotateAboutYAxis(90.0);
2586 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2587 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2589 transform.MakeIdentity();
2590 transform.RotateAboutZAxis(90.0);
2591 transform.RotateAboutXAxis(90.0);
2592 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2593 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2595 transform.MakeIdentity();
2596 transform.RotateAboutYAxis(90.0);
2597 transform.RotateAboutZAxis(90.0);
2598 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2599 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2601 transform.MakeIdentity();
2602 transform.RotateAboutZAxis(45.0);
2603 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2604 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2606 // 3-d case; In 2d after an orthographic projection, this case does
2607 // preserve 2d axis alignment. But in 3d, it does not preserve axis
2608 // alignment.
2609 transform.MakeIdentity();
2610 transform.RotateAboutYAxis(45.0);
2611 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2612 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2614 transform.MakeIdentity();
2615 transform.RotateAboutXAxis(45.0);
2616 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2617 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2619 // Perspective cases.
2620 transform.MakeIdentity();
2621 transform.ApplyPerspectiveDepth(10.0);
2622 transform.RotateAboutYAxis(45.0);
2623 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2624 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2626 transform.MakeIdentity();
2627 transform.ApplyPerspectiveDepth(10.0);
2628 transform.RotateAboutZAxis(90.0);
2629 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2630 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2633 TEST(XFormTest, To2dTranslation) {
2634 Vector2dF translation(3.f, 7.f);
2635 Transform transform;
2636 transform.Translate(translation.x(), translation.y() + 1);
2637 EXPECT_NE(translation.ToString(), transform.To2dTranslation().ToString());
2638 transform.MakeIdentity();
2639 transform.Translate(translation.x(), translation.y());
2640 EXPECT_EQ(translation.ToString(), transform.To2dTranslation().ToString());
2643 TEST(XFormTest, TransformRect) {
2644 Transform translation;
2645 translation.Translate(3.f, 7.f);
2646 RectF rect(1.f, 2.f, 3.f, 4.f);
2647 RectF expected(4.f, 9.f, 3.f, 4.f);
2648 translation.TransformRect(&rect);
2649 EXPECT_EQ(expected.ToString(), rect.ToString());
2652 TEST(XFormTest, TransformRectReverse) {
2653 Transform translation;
2654 translation.Translate(3.f, 7.f);
2655 RectF rect(1.f, 2.f, 3.f, 4.f);
2656 RectF expected(-2.f, -5.f, 3.f, 4.f);
2657 EXPECT_TRUE(translation.TransformRectReverse(&rect));
2658 EXPECT_EQ(expected.ToString(), rect.ToString());
2660 Transform singular;
2661 singular.Scale3d(0.f, 0.f, 0.f);
2662 EXPECT_FALSE(singular.TransformRectReverse(&rect));
2665 TEST(XFormTest, TransformBox) {
2666 Transform translation;
2667 translation.Translate3d(3.f, 7.f, 6.f);
2668 BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f);
2669 BoxF expected(4.f, 9.f, 9.f, 4.f, 5.f, 6.f);
2670 translation.TransformBox(&box);
2671 EXPECT_EQ(expected.ToString(), box.ToString());
2674 TEST(XFormTest, TransformBoxReverse) {
2675 Transform translation;
2676 translation.Translate3d(3.f, 7.f, 6.f);
2677 BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f);
2678 BoxF expected(-2.f, -5.f, -3.f, 4.f, 5.f, 6.f);
2679 EXPECT_TRUE(translation.TransformBoxReverse(&box));
2680 EXPECT_EQ(expected.ToString(), box.ToString());
2682 Transform singular;
2683 singular.Scale3d(0.f, 0.f, 0.f);
2684 EXPECT_FALSE(singular.TransformBoxReverse(&box));
2687 TEST(XFormTest, RoundTranslationComponents) {
2688 Transform translation;
2689 Transform expected;
2691 translation.RoundTranslationComponents();
2692 EXPECT_EQ(expected.ToString(), translation.ToString());
2694 translation.Translate(1.0f, 1.0f);
2695 expected.Translate(1.0f, 1.0f);
2696 translation.RoundTranslationComponents();
2697 EXPECT_EQ(expected.ToString(), translation.ToString());
2699 translation.Translate(0.5f, 0.4f);
2700 expected.Translate(1.0f, 0.0f);
2701 translation.RoundTranslationComponents();
2702 EXPECT_EQ(expected.ToString(), translation.ToString());
2704 // Rounding should only affect 2d translation components.
2705 translation.Translate3d(0.f, 0.f, 0.5f);
2706 expected.Translate3d(0.f, 0.f, 0.5f);
2707 translation.RoundTranslationComponents();
2708 EXPECT_EQ(expected.ToString(), translation.ToString());
2711 } // namespace
2713 } // namespace gfx