Add a stub __cxa_demangle to disable LLVM's demangler.
[chromium-blink-merge.git] / ui / gfx / transform_unittest.cc
blobeb0b2fdcc69980f4f704e84d3f2fc4fa1c2f3146
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.SkewX(10);
781 to.SkewY(5);
782 double t = i;
783 Transform expected;
784 expected.SkewX(t * 10);
785 expected.SkewY(t * 5);
786 EXPECT_TRUE(to.Blend(from, t));
787 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
791 TEST(XFormTest, ExtrapolateSkew) {
792 Transform from;
793 for (int i = -1; i < 2; ++i) {
794 Transform to;
795 to.SkewX(20);
796 double t = i;
797 Transform expected;
798 expected.SkewX(t * 20);
799 EXPECT_TRUE(to.Blend(from, t));
800 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
804 #if defined(_WIN64)
805 // http://crbug.com/406574
806 #define MAYBE_BlendPerspective DISABLED_BlendPerspective
807 #else
808 #define MAYBE_BlendPerspective BlendPerspective
809 #endif
810 TEST(XFormTest, MAYBE_BlendPerspective) {
811 Transform from;
812 from.ApplyPerspectiveDepth(200);
813 for (int i = -1; i < 3; ++i) {
814 Transform to;
815 to.ApplyPerspectiveDepth(800);
816 double t = i;
817 double depth = 1.0 / ((1.0 / 200) * (1.0 - t) + (1.0 / 800) * t);
818 Transform expected;
819 expected.ApplyPerspectiveDepth(depth);
820 EXPECT_TRUE(to.Blend(from, t));
821 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
825 TEST(XFormTest, BlendIdentity) {
826 Transform from;
827 Transform to;
828 EXPECT_TRUE(to.Blend(from, 0.5));
829 EXPECT_EQ(to, from);
832 TEST(XFormTest, CannotBlendSingularMatrix) {
833 Transform from;
834 Transform to;
835 to.matrix().set(1, 1, SkDoubleToMScalar(0));
836 EXPECT_FALSE(to.Blend(from, 0.5));
839 TEST(XFormTest, VerifyBlendForTranslation) {
840 Transform from;
841 from.Translate3d(100.0, 200.0, 100.0);
843 Transform to;
845 to.Translate3d(200.0, 100.0, 300.0);
846 to.Blend(from, 0.0);
847 EXPECT_EQ(from, to);
849 to = Transform();
850 to.Translate3d(200.0, 100.0, 300.0);
851 to.Blend(from, 0.25);
852 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 125.0f, to);
853 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 175.0f, to);
854 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 150.0f, to);
855 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
857 to = Transform();
858 to.Translate3d(200.0, 100.0, 300.0);
859 to.Blend(from, 0.5);
860 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 150.0f, to);
861 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 150.0f, to);
862 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 200.0f, to);
863 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
865 to = Transform();
866 to.Translate3d(200.0, 100.0, 300.0);
867 to.Blend(from, 1.0);
868 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 200.0f, to);
869 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 100.0f, to);
870 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 300.0f, to);
871 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
874 TEST(XFormTest, VerifyBlendForScale) {
875 Transform from;
876 from.Scale3d(100.0, 200.0, 100.0);
878 Transform to;
880 to.Scale3d(200.0, 100.0, 300.0);
881 to.Blend(from, 0.0);
882 EXPECT_EQ(from, to);
884 to = Transform();
885 to.Scale3d(200.0, 100.0, 300.0);
886 to.Blend(from, 0.25);
887 EXPECT_ROW1_EQ(125.0f, 0.0f, 0.0f, 0.0f, to);
888 EXPECT_ROW2_EQ(0.0f, 175.0f, 0.0f, 0.0f, to);
889 EXPECT_ROW3_EQ(0.0f, 0.0f, 150.0f, 0.0f, to);
890 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
892 to = Transform();
893 to.Scale3d(200.0, 100.0, 300.0);
894 to.Blend(from, 0.5);
895 EXPECT_ROW1_EQ(150.0f, 0.0f, 0.0f, 0.0f, to);
896 EXPECT_ROW2_EQ(0.0f, 150.0f, 0.0f, 0.0f, to);
897 EXPECT_ROW3_EQ(0.0f, 0.0f, 200.0f, 0.0f, to);
898 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
900 to = Transform();
901 to.Scale3d(200.0, 100.0, 300.0);
902 to.Blend(from, 1.0);
903 EXPECT_ROW1_EQ(200.0f, 0.0f, 0.0f, 0.0f, to);
904 EXPECT_ROW2_EQ(0.0f, 100.0f, 0.0f, 0.0f, to);
905 EXPECT_ROW3_EQ(0.0f, 0.0f, 300.0f, 0.0f, to);
906 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
909 TEST(XFormTest, VerifyBlendForSkewX) {
910 Transform from;
911 from.SkewX(0.0);
913 Transform to;
915 to.SkewX(45.0);
916 to.Blend(from, 0.0);
917 EXPECT_EQ(from, to);
919 to = Transform();
920 to.SkewX(45.0);
921 to.Blend(from, 0.5);
922 EXPECT_ROW1_EQ(1.0f, 0.5f, 0.0f, 0.0f, to);
923 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
924 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
925 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
927 to = Transform();
928 to.SkewX(45.0);
929 to.Blend(from, 0.25);
930 EXPECT_ROW1_EQ(1.0f, 0.25f, 0.0f, 0.0f, to);
931 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
932 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
933 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
935 to = Transform();
936 to.SkewX(45.0);
937 to.Blend(from, 1.0);
938 EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, to);
939 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
940 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
941 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
944 TEST(XFormTest, VerifyBlendForSkewY) {
945 // NOTE CAREFULLY: Decomposition of skew and rotation terms of the matrix
946 // is inherently underconstrained, and so it does not always compute the
947 // originally intended skew parameters. The current implementation uses QR
948 // decomposition, which decomposes the shear into a rotation + non-uniform
949 // scale.
951 // It is unlikely that the decomposition implementation will need to change
952 // very often, so to get any test coverage, the compromise is to verify the
953 // exact matrix that the.Blend() operation produces.
955 // This problem also potentially exists for skewX, but the current QR
956 // decomposition implementation just happens to decompose those test
957 // matrices intuitively.
959 // Unfortunately, this case suffers from uncomfortably large precision
960 // error.
962 Transform from;
963 from.SkewY(0.0);
965 Transform to;
967 to.SkewY(45.0);
968 to.Blend(from, 0.0);
969 EXPECT_EQ(from, to);
971 to = Transform();
972 to.SkewY(45.0);
973 to.Blend(from, 0.25);
974 EXPECT_ROW1_NEAR(1.0823489449280947471976333,
975 0.0464370719145053845178239,
976 0.0,
977 0.0,
979 LOOSE_ERROR_THRESHOLD);
980 EXPECT_ROW2_NEAR(0.2152925909665224513123150,
981 0.9541702441750861130032035,
982 0.0,
983 0.0,
985 LOOSE_ERROR_THRESHOLD);
986 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
987 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
989 to = Transform();
990 to.SkewY(45.0);
991 to.Blend(from, 0.5);
992 EXPECT_ROW1_NEAR(1.1152212925809066312865525,
993 0.0676495144007326631996335,
994 0.0,
995 0.0,
997 LOOSE_ERROR_THRESHOLD);
998 EXPECT_ROW2_NEAR(0.4619397844342648662419037,
999 0.9519009045724774464858342,
1000 0.0,
1001 0.0,
1003 LOOSE_ERROR_THRESHOLD);
1004 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
1005 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1007 to = Transform();
1008 to.SkewY(45.0);
1009 to.Blend(from, 1.0);
1010 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD);
1011 EXPECT_ROW2_NEAR(1.0, 1.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD);
1012 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
1013 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1016 #if defined(_WIN64)
1017 // http://crbug.com/406574
1018 #define MAYBE_VerifyBlendForRotationAboutX DISABLED_VerifyBlendForRotationAboutX
1019 #else
1020 #define MAYBE_VerifyBlendForRotationAboutX VerifyBlendForRotationAboutX
1021 #endif
1022 TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutX) {
1023 // Even though.Blending uses quaternions, axis-aligned rotations should.
1024 // Blend the same with quaternions or Euler angles. So we can test
1025 // rotation.Blending by comparing against manually specified matrices from
1026 // Euler angles.
1028 Transform from;
1029 from.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 0.0);
1031 Transform to;
1033 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1034 to.Blend(from, 0.0);
1035 EXPECT_EQ(from, to);
1037 double expectedRotationAngle = 22.5 * M_PI / 180.0;
1038 to = Transform();
1039 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1040 to.Blend(from, 0.25);
1041 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1042 EXPECT_ROW2_NEAR(0.0,
1043 std::cos(expectedRotationAngle),
1044 -std::sin(expectedRotationAngle),
1045 0.0,
1047 ERROR_THRESHOLD);
1048 EXPECT_ROW3_NEAR(0.0,
1049 std::sin(expectedRotationAngle),
1050 std::cos(expectedRotationAngle),
1051 0.0,
1053 ERROR_THRESHOLD);
1054 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1056 expectedRotationAngle = 45.0 * M_PI / 180.0;
1057 to = Transform();
1058 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1059 to.Blend(from, 0.5);
1060 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1061 EXPECT_ROW2_NEAR(0.0,
1062 std::cos(expectedRotationAngle),
1063 -std::sin(expectedRotationAngle),
1064 0.0,
1066 ERROR_THRESHOLD);
1067 EXPECT_ROW3_NEAR(0.0,
1068 std::sin(expectedRotationAngle),
1069 std::cos(expectedRotationAngle),
1070 0.0,
1072 ERROR_THRESHOLD);
1073 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1075 to = Transform();
1076 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1077 to.Blend(from, 1.0);
1078 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1079 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, to, ERROR_THRESHOLD);
1080 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1081 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1084 #if defined(_WIN64)
1085 // http://crbug.com/406574
1086 #define MAYBE_VerifyBlendForRotationAboutY DISABLED_VerifyBlendForRotationAboutY
1087 #else
1088 #define MAYBE_VerifyBlendForRotationAboutY VerifyBlendForRotationAboutY
1089 #endif
1090 TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutY) {
1091 Transform from;
1092 from.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 0.0);
1094 Transform to;
1096 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1097 to.Blend(from, 0.0);
1098 EXPECT_EQ(from, to);
1100 double expectedRotationAngle = 22.5 * M_PI / 180.0;
1101 to = Transform();
1102 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1103 to.Blend(from, 0.25);
1104 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1105 0.0,
1106 std::sin(expectedRotationAngle),
1107 0.0,
1109 ERROR_THRESHOLD);
1110 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1111 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle),
1112 0.0,
1113 std::cos(expectedRotationAngle),
1114 0.0,
1116 ERROR_THRESHOLD);
1117 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1119 expectedRotationAngle = 45.0 * M_PI / 180.0;
1120 to = Transform();
1121 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1122 to.Blend(from, 0.5);
1123 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1124 0.0,
1125 std::sin(expectedRotationAngle),
1126 0.0,
1128 ERROR_THRESHOLD);
1129 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1130 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle),
1131 0.0,
1132 std::cos(expectedRotationAngle),
1133 0.0,
1135 ERROR_THRESHOLD);
1136 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1138 to = Transform();
1139 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1140 to.Blend(from, 1.0);
1141 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1142 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1143 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1144 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1147 #if defined(_WIN64)
1148 // http://crbug.com/406574
1149 #define MAYBE_VerifyBlendForRotationAboutZ DISABLED_VerifyBlendForRotationAboutZ
1150 #else
1151 #define MAYBE_VerifyBlendForRotationAboutZ VerifyBlendForRotationAboutZ
1152 #endif
1153 TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutZ) {
1154 Transform from;
1155 from.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 0.0);
1157 Transform to;
1159 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1160 to.Blend(from, 0.0);
1161 EXPECT_EQ(from, to);
1163 double expectedRotationAngle = 22.5 * M_PI / 180.0;
1164 to = Transform();
1165 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1166 to.Blend(from, 0.25);
1167 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1168 -std::sin(expectedRotationAngle),
1169 0.0,
1170 0.0,
1172 ERROR_THRESHOLD);
1173 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle),
1174 std::cos(expectedRotationAngle),
1175 0.0,
1176 0.0,
1178 ERROR_THRESHOLD);
1179 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1180 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1182 expectedRotationAngle = 45.0 * M_PI / 180.0;
1183 to = Transform();
1184 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1185 to.Blend(from, 0.5);
1186 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1187 -std::sin(expectedRotationAngle),
1188 0.0,
1189 0.0,
1191 ERROR_THRESHOLD);
1192 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle),
1193 std::cos(expectedRotationAngle),
1194 0.0,
1195 0.0,
1197 ERROR_THRESHOLD);
1198 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1199 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1201 to = Transform();
1202 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1203 to.Blend(from, 1.0);
1204 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1205 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1206 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1207 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1210 TEST(XFormTest, VerifyBlendForCompositeTransform) {
1211 // Verify that the.Blending was done with a decomposition in correct order
1212 // by blending a composite transform. Using matrix x vector notation
1213 // (Ax = b, where x is column vector), the ordering should be:
1214 // perspective * translation * rotation * skew * scale
1216 // It is not as important (or meaningful) to check intermediate
1217 // interpolations; order of operations will be tested well enough by the
1218 // end cases that are easier to specify.
1220 Transform from;
1221 Transform to;
1223 Transform expectedEndOfAnimation;
1224 expectedEndOfAnimation.ApplyPerspectiveDepth(1.0);
1225 expectedEndOfAnimation.Translate3d(10.0, 20.0, 30.0);
1226 expectedEndOfAnimation.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 25.0);
1227 expectedEndOfAnimation.SkewY(45.0);
1228 expectedEndOfAnimation.Scale3d(6.0, 7.0, 8.0);
1230 to = expectedEndOfAnimation;
1231 to.Blend(from, 0.0);
1232 EXPECT_EQ(from, to);
1234 to = expectedEndOfAnimation;
1235 // We short circuit if blend is >= 1, so to check the numerics, we will
1236 // check that we get close to what we expect when we're nearly done
1237 // interpolating.
1238 to.Blend(from, .99999f);
1240 // Recomposing the matrix results in a normalized matrix, so to verify we
1241 // need to normalize the expectedEndOfAnimation before comparing elements.
1242 // Normalizing means dividing everything by expectedEndOfAnimation.m44().
1243 Transform normalizedExpectedEndOfAnimation = expectedEndOfAnimation;
1244 Transform normalizationMatrix;
1245 normalizationMatrix.matrix().set(
1246 0.0,
1247 0.0,
1248 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1249 normalizationMatrix.matrix().set(
1250 1.0,
1251 1.0,
1252 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1253 normalizationMatrix.matrix().set(
1254 2.0,
1255 2.0,
1256 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1257 normalizationMatrix.matrix().set(
1258 3.0,
1259 3.0,
1260 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1261 normalizedExpectedEndOfAnimation.PreconcatTransform(normalizationMatrix);
1263 EXPECT_TRUE(MatricesAreNearlyEqual(normalizedExpectedEndOfAnimation, to));
1266 TEST(XFormTest, DecomposedTransformCtor) {
1267 DecomposedTransform decomp;
1268 for (int i = 0; i < 3; ++i) {
1269 EXPECT_EQ(0.0, decomp.translate[i]);
1270 EXPECT_EQ(1.0, decomp.scale[i]);
1271 EXPECT_EQ(0.0, decomp.skew[i]);
1272 EXPECT_EQ(0.0, decomp.quaternion[i]);
1273 EXPECT_EQ(0.0, decomp.perspective[i]);
1275 EXPECT_EQ(1.0, decomp.quaternion[3]);
1276 EXPECT_EQ(1.0, decomp.perspective[3]);
1277 Transform identity;
1278 Transform composed = ComposeTransform(decomp);
1279 EXPECT_TRUE(MatricesAreNearlyEqual(identity, composed));
1282 TEST(XFormTest, FactorTRS) {
1283 for (int degrees = 0; degrees < 180; ++degrees) {
1284 // build a transformation matrix.
1285 gfx::Transform transform;
1286 transform.Translate(degrees * 2, -degrees * 3);
1287 transform.Rotate(degrees);
1288 transform.Scale(degrees + 1, 2 * degrees + 1);
1290 // factor the matrix
1291 DecomposedTransform decomp;
1292 bool success = DecomposeTransform(&decomp, transform);
1293 EXPECT_TRUE(success);
1294 EXPECT_FLOAT_EQ(decomp.translate[0], degrees * 2);
1295 EXPECT_FLOAT_EQ(decomp.translate[1], -degrees * 3);
1296 double rotation =
1297 std::acos(SkMScalarToDouble(decomp.quaternion[3])) * 360.0 / M_PI;
1298 while (rotation < 0.0)
1299 rotation += 360.0;
1300 while (rotation > 360.0)
1301 rotation -= 360.0;
1303 const float epsilon = 0.00015f;
1304 EXPECT_NEAR(rotation, degrees, epsilon);
1305 EXPECT_NEAR(decomp.scale[0], degrees + 1, epsilon);
1306 EXPECT_NEAR(decomp.scale[1], 2 * degrees + 1, epsilon);
1310 TEST(XFormTest, DecomposeTransform) {
1311 for (float scale = 0.001f; scale < 2.0f; scale += 0.001f) {
1312 gfx::Transform transform;
1313 transform.Scale(scale, scale);
1314 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
1316 DecomposedTransform decomp;
1317 bool success = DecomposeTransform(&decomp, transform);
1318 EXPECT_TRUE(success);
1320 gfx::Transform compose_transform = ComposeTransform(decomp);
1321 EXPECT_TRUE(compose_transform.Preserves2dAxisAlignment());
1325 TEST(XFormTest, IntegerTranslation) {
1326 gfx::Transform transform;
1327 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1329 transform.Translate3d(1, 2, 3);
1330 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1332 transform.MakeIdentity();
1333 transform.Translate3d(-1, -2, -3);
1334 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1336 transform.MakeIdentity();
1337 transform.Translate3d(4.5f, 0, 0);
1338 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1340 transform.MakeIdentity();
1341 transform.Translate3d(0, -6.7f, 0);
1342 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1344 transform.MakeIdentity();
1345 transform.Translate3d(0, 0, 8.9f);
1346 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1349 TEST(XFormTest, verifyMatrixInversion) {
1351 // Invert a translation
1352 gfx::Transform translation;
1353 translation.Translate3d(2.0, 3.0, 4.0);
1354 EXPECT_TRUE(translation.IsInvertible());
1356 gfx::Transform inverse_translation;
1357 bool is_invertible = translation.GetInverse(&inverse_translation);
1358 EXPECT_TRUE(is_invertible);
1359 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, -2.0f, inverse_translation);
1360 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, -3.0f, inverse_translation);
1361 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, -4.0f, inverse_translation);
1362 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_translation);
1366 // Invert a non-uniform scale
1367 gfx::Transform scale;
1368 scale.Scale3d(4.0, 10.0, 100.0);
1369 EXPECT_TRUE(scale.IsInvertible());
1371 gfx::Transform inverse_scale;
1372 bool is_invertible = scale.GetInverse(&inverse_scale);
1373 EXPECT_TRUE(is_invertible);
1374 EXPECT_ROW1_EQ(0.25f, 0.0f, 0.0f, 0.0f, inverse_scale);
1375 EXPECT_ROW2_EQ(0.0f, 0.1f, 0.0f, 0.0f, inverse_scale);
1376 EXPECT_ROW3_EQ(0.0f, 0.0f, 0.01f, 0.0f, inverse_scale);
1377 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_scale);
1381 // Try to invert a matrix that is not invertible.
1382 // The inverse() function should reset the output matrix to identity.
1383 gfx::Transform uninvertible;
1384 uninvertible.matrix().set(0, 0, 0.f);
1385 uninvertible.matrix().set(1, 1, 0.f);
1386 uninvertible.matrix().set(2, 2, 0.f);
1387 uninvertible.matrix().set(3, 3, 0.f);
1388 EXPECT_FALSE(uninvertible.IsInvertible());
1390 gfx::Transform inverse_of_uninvertible;
1392 // Add a scale just to more easily ensure that inverse_of_uninvertible is
1393 // reset to identity.
1394 inverse_of_uninvertible.Scale3d(4.0, 10.0, 100.0);
1396 bool is_invertible = uninvertible.GetInverse(&inverse_of_uninvertible);
1397 EXPECT_FALSE(is_invertible);
1398 EXPECT_TRUE(inverse_of_uninvertible.IsIdentity());
1399 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, inverse_of_uninvertible);
1400 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, inverse_of_uninvertible);
1401 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, inverse_of_uninvertible);
1402 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_of_uninvertible);
1406 TEST(XFormTest, verifyBackfaceVisibilityBasicCases) {
1407 Transform transform;
1409 transform.MakeIdentity();
1410 EXPECT_FALSE(transform.IsBackFaceVisible());
1412 transform.MakeIdentity();
1413 transform.RotateAboutYAxis(80.0);
1414 EXPECT_FALSE(transform.IsBackFaceVisible());
1416 transform.MakeIdentity();
1417 transform.RotateAboutYAxis(100.0);
1418 EXPECT_TRUE(transform.IsBackFaceVisible());
1420 // Edge case, 90 degree rotation should return false.
1421 transform.MakeIdentity();
1422 transform.RotateAboutYAxis(90.0);
1423 EXPECT_FALSE(transform.IsBackFaceVisible());
1426 TEST(XFormTest, verifyBackfaceVisibilityForPerspective) {
1427 Transform layer_space_to_projection_plane;
1429 // This tests if IsBackFaceVisible works properly under perspective
1430 // transforms. Specifically, layers that may have their back face visible in
1431 // orthographic projection, may not actually have back face visible under
1432 // perspective projection.
1434 // Case 1: Layer is rotated by slightly more than 90 degrees, at the center
1435 // of the prespective projection. In this case, the layer's back-side
1436 // is visible to the camera.
1437 layer_space_to_projection_plane.MakeIdentity();
1438 layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0);
1439 layer_space_to_projection_plane.Translate3d(0.0, 0.0, 0.0);
1440 layer_space_to_projection_plane.RotateAboutYAxis(100.0);
1441 EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible());
1443 // Case 2: Layer is rotated by slightly more than 90 degrees, but shifted off
1444 // to the side of the camera. Because of the wide field-of-view, the
1445 // layer's front side is still visible.
1447 // |<-- front side of layer is visible to camera
1448 // \ | /
1449 // \ | /
1450 // \| /
1451 // | /
1452 // |\ /<-- camera field of view
1453 // | \ /
1454 // back side of layer -->| \ /
1455 // \./ <-- camera origin
1457 layer_space_to_projection_plane.MakeIdentity();
1458 layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0);
1459 layer_space_to_projection_plane.Translate3d(-10.0, 0.0, 0.0);
1460 layer_space_to_projection_plane.RotateAboutYAxis(100.0);
1461 EXPECT_FALSE(layer_space_to_projection_plane.IsBackFaceVisible());
1463 // Case 3: Additionally rotating the layer by 180 degrees should of course
1464 // show the opposite result of case 2.
1465 layer_space_to_projection_plane.RotateAboutYAxis(180.0);
1466 EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible());
1469 TEST(XFormTest, verifyDefaultConstructorCreatesIdentityMatrix) {
1470 Transform A;
1471 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1472 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1473 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1474 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1475 EXPECT_TRUE(A.IsIdentity());
1478 TEST(XFormTest, verifyCopyConstructor) {
1479 Transform A;
1480 InitializeTestMatrix(&A);
1482 // Copy constructor should produce exact same elements as matrix A.
1483 Transform B(A);
1484 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B);
1485 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B);
1486 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B);
1487 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B);
1490 TEST(XFormTest, verifyConstructorFor16Elements) {
1491 Transform transform(1.0, 2.0, 3.0, 4.0,
1492 5.0, 6.0, 7.0, 8.0,
1493 9.0, 10.0, 11.0, 12.0,
1494 13.0, 14.0, 15.0, 16.0);
1496 EXPECT_ROW1_EQ(1.0f, 2.0f, 3.0f, 4.0f, transform);
1497 EXPECT_ROW2_EQ(5.0f, 6.0f, 7.0f, 8.0f, transform);
1498 EXPECT_ROW3_EQ(9.0f, 10.0f, 11.0f, 12.0f, transform);
1499 EXPECT_ROW4_EQ(13.0f, 14.0f, 15.0f, 16.0f, transform);
1502 TEST(XFormTest, verifyConstructorFor2dElements) {
1503 Transform transform(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
1505 EXPECT_ROW1_EQ(1.0f, 2.0f, 0.0f, 5.0f, transform);
1506 EXPECT_ROW2_EQ(3.0f, 4.0f, 0.0f, 6.0f, transform);
1507 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, transform);
1508 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, transform);
1512 TEST(XFormTest, verifyAssignmentOperator) {
1513 Transform A;
1514 InitializeTestMatrix(&A);
1515 Transform B;
1516 InitializeTestMatrix2(&B);
1517 Transform C;
1518 InitializeTestMatrix2(&C);
1519 C = B = A;
1521 // Both B and C should now have been re-assigned to the value of A.
1522 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B);
1523 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B);
1524 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B);
1525 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B);
1527 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, C);
1528 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, C);
1529 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, C);
1530 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, C);
1533 TEST(XFormTest, verifyEqualsBooleanOperator) {
1534 Transform A;
1535 InitializeTestMatrix(&A);
1537 Transform B;
1538 InitializeTestMatrix(&B);
1539 EXPECT_TRUE(A == B);
1541 // Modifying multiple elements should cause equals operator to return false.
1542 Transform C;
1543 InitializeTestMatrix2(&C);
1544 EXPECT_FALSE(A == C);
1546 // Modifying any one individual element should cause equals operator to
1547 // return false.
1548 Transform D;
1549 D = A;
1550 D.matrix().set(0, 0, 0.f);
1551 EXPECT_FALSE(A == D);
1553 D = A;
1554 D.matrix().set(1, 0, 0.f);
1555 EXPECT_FALSE(A == D);
1557 D = A;
1558 D.matrix().set(2, 0, 0.f);
1559 EXPECT_FALSE(A == D);
1561 D = A;
1562 D.matrix().set(3, 0, 0.f);
1563 EXPECT_FALSE(A == D);
1565 D = A;
1566 D.matrix().set(0, 1, 0.f);
1567 EXPECT_FALSE(A == D);
1569 D = A;
1570 D.matrix().set(1, 1, 0.f);
1571 EXPECT_FALSE(A == D);
1573 D = A;
1574 D.matrix().set(2, 1, 0.f);
1575 EXPECT_FALSE(A == D);
1577 D = A;
1578 D.matrix().set(3, 1, 0.f);
1579 EXPECT_FALSE(A == D);
1581 D = A;
1582 D.matrix().set(0, 2, 0.f);
1583 EXPECT_FALSE(A == D);
1585 D = A;
1586 D.matrix().set(1, 2, 0.f);
1587 EXPECT_FALSE(A == D);
1589 D = A;
1590 D.matrix().set(2, 2, 0.f);
1591 EXPECT_FALSE(A == D);
1593 D = A;
1594 D.matrix().set(3, 2, 0.f);
1595 EXPECT_FALSE(A == D);
1597 D = A;
1598 D.matrix().set(0, 3, 0.f);
1599 EXPECT_FALSE(A == D);
1601 D = A;
1602 D.matrix().set(1, 3, 0.f);
1603 EXPECT_FALSE(A == D);
1605 D = A;
1606 D.matrix().set(2, 3, 0.f);
1607 EXPECT_FALSE(A == D);
1609 D = A;
1610 D.matrix().set(3, 3, 0.f);
1611 EXPECT_FALSE(A == D);
1614 TEST(XFormTest, verifyMultiplyOperator) {
1615 Transform A;
1616 InitializeTestMatrix(&A);
1618 Transform B;
1619 InitializeTestMatrix2(&B);
1621 Transform C = A * B;
1622 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, C);
1623 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, C);
1624 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, C);
1625 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, C);
1627 // Just an additional sanity check; matrix multiplication is not commutative.
1628 EXPECT_FALSE(A * B == B * A);
1631 TEST(XFormTest, verifyMultiplyAndAssignOperator) {
1632 Transform A;
1633 InitializeTestMatrix(&A);
1635 Transform B;
1636 InitializeTestMatrix2(&B);
1638 A *= B;
1639 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
1640 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
1641 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
1642 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
1644 // Just an additional sanity check; matrix multiplication is not commutative.
1645 Transform C = A;
1646 C *= B;
1647 Transform D = B;
1648 D *= A;
1649 EXPECT_FALSE(C == D);
1652 TEST(XFormTest, verifyMatrixMultiplication) {
1653 Transform A;
1654 InitializeTestMatrix(&A);
1656 Transform B;
1657 InitializeTestMatrix2(&B);
1659 A.PreconcatTransform(B);
1660 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
1661 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
1662 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
1663 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
1666 TEST(XFormTest, verifyMakeIdentiy) {
1667 Transform A;
1668 InitializeTestMatrix(&A);
1669 A.MakeIdentity();
1670 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1671 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1672 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1673 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1674 EXPECT_TRUE(A.IsIdentity());
1677 TEST(XFormTest, verifyTranslate) {
1678 Transform A;
1679 A.Translate(2.0, 3.0);
1680 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
1681 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
1682 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1683 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1685 // Verify that Translate() post-multiplies the existing matrix.
1686 A.MakeIdentity();
1687 A.Scale(5.0, 5.0);
1688 A.Translate(2.0, 3.0);
1689 EXPECT_ROW1_EQ(5.0f, 0.0f, 0.0f, 10.0f, A);
1690 EXPECT_ROW2_EQ(0.0f, 5.0f, 0.0f, 15.0f, A);
1691 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1692 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1695 TEST(XFormTest, verifyTranslate3d) {
1696 Transform A;
1697 A.Translate3d(2.0, 3.0, 4.0);
1698 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
1699 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
1700 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
1701 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1703 // Verify that Translate3d() post-multiplies the existing matrix.
1704 A.MakeIdentity();
1705 A.Scale3d(6.0, 7.0, 8.0);
1706 A.Translate3d(2.0, 3.0, 4.0);
1707 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 12.0f, A);
1708 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 21.0f, A);
1709 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 32.0f, A);
1710 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1713 TEST(XFormTest, verifyScale) {
1714 Transform A;
1715 A.Scale(6.0, 7.0);
1716 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
1717 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
1718 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1719 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1721 // Verify that Scale() post-multiplies the existing matrix.
1722 A.MakeIdentity();
1723 A.Translate3d(2.0, 3.0, 4.0);
1724 A.Scale(6.0, 7.0);
1725 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
1726 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
1727 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
1728 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1731 TEST(XFormTest, verifyScale3d) {
1732 Transform A;
1733 A.Scale3d(6.0, 7.0, 8.0);
1734 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
1735 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
1736 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1737 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1739 // Verify that scale3d() post-multiplies the existing matrix.
1740 A.MakeIdentity();
1741 A.Translate3d(2.0, 3.0, 4.0);
1742 A.Scale3d(6.0, 7.0, 8.0);
1743 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
1744 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
1745 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 4.0f, A);
1746 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1749 TEST(XFormTest, verifyRotate) {
1750 Transform A;
1751 A.Rotate(90.0);
1752 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1753 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1754 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1755 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1757 // Verify that Rotate() post-multiplies the existing matrix.
1758 A.MakeIdentity();
1759 A.Scale3d(6.0, 7.0, 8.0);
1760 A.Rotate(90.0);
1761 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1762 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1763 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1764 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1767 TEST(XFormTest, verifyRotateAboutXAxis) {
1768 Transform A;
1769 double sin45 = 0.5 * sqrt(2.0);
1770 double cos45 = sin45;
1772 A.MakeIdentity();
1773 A.RotateAboutXAxis(90.0);
1774 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1775 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD);
1776 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1777 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1779 A.MakeIdentity();
1780 A.RotateAboutXAxis(45.0);
1781 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1782 EXPECT_ROW2_NEAR(0.0, cos45, -sin45, 0.0, A, ERROR_THRESHOLD);
1783 EXPECT_ROW3_NEAR(0.0, sin45, cos45, 0.0, A, ERROR_THRESHOLD);
1784 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1786 // Verify that RotateAboutXAxis(angle) post-multiplies the existing matrix.
1787 A.MakeIdentity();
1788 A.Scale3d(6.0, 7.0, 8.0);
1789 A.RotateAboutXAxis(90.0);
1790 EXPECT_ROW1_NEAR(6.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1791 EXPECT_ROW2_NEAR(0.0, 0.0, -7.0, 0.0, A, ERROR_THRESHOLD);
1792 EXPECT_ROW3_NEAR(0.0, 8.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1793 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1796 TEST(XFormTest, verifyRotateAboutYAxis) {
1797 Transform A;
1798 double sin45 = 0.5 * sqrt(2.0);
1799 double cos45 = sin45;
1801 // Note carefully, the expected pattern is inverted compared to rotating
1802 // about x axis or z axis.
1803 A.MakeIdentity();
1804 A.RotateAboutYAxis(90.0);
1805 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD);
1806 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1807 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1808 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1810 A.MakeIdentity();
1811 A.RotateAboutYAxis(45.0);
1812 EXPECT_ROW1_NEAR(cos45, 0.0, sin45, 0.0, A, ERROR_THRESHOLD);
1813 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1814 EXPECT_ROW3_NEAR(-sin45, 0.0, cos45, 0.0, A, ERROR_THRESHOLD);
1815 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1817 // Verify that RotateAboutYAxis(angle) post-multiplies the existing matrix.
1818 A.MakeIdentity();
1819 A.Scale3d(6.0, 7.0, 8.0);
1820 A.RotateAboutYAxis(90.0);
1821 EXPECT_ROW1_NEAR(0.0, 0.0, 6.0, 0.0, A, ERROR_THRESHOLD);
1822 EXPECT_ROW2_NEAR(0.0, 7.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1823 EXPECT_ROW3_NEAR(-8.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1824 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1827 TEST(XFormTest, verifyRotateAboutZAxis) {
1828 Transform A;
1829 double sin45 = 0.5 * sqrt(2.0);
1830 double cos45 = sin45;
1832 A.MakeIdentity();
1833 A.RotateAboutZAxis(90.0);
1834 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1835 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1836 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1837 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1839 A.MakeIdentity();
1840 A.RotateAboutZAxis(45.0);
1841 EXPECT_ROW1_NEAR(cos45, -sin45, 0.0, 0.0, A, ERROR_THRESHOLD);
1842 EXPECT_ROW2_NEAR(sin45, cos45, 0.0, 0.0, A, ERROR_THRESHOLD);
1843 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1844 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1846 // Verify that RotateAboutZAxis(angle) post-multiplies the existing matrix.
1847 A.MakeIdentity();
1848 A.Scale3d(6.0, 7.0, 8.0);
1849 A.RotateAboutZAxis(90.0);
1850 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1851 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1852 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1853 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1856 TEST(XFormTest, verifyRotateAboutForAlignedAxes) {
1857 Transform A;
1859 // Check rotation about z-axis
1860 A.MakeIdentity();
1861 A.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1862 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1863 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1864 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1865 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1867 // Check rotation about x-axis
1868 A.MakeIdentity();
1869 A.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1870 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1871 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD);
1872 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1873 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1875 // Check rotation about y-axis. Note carefully, the expected pattern is
1876 // inverted compared to rotating about x axis or z axis.
1877 A.MakeIdentity();
1878 A.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1879 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD);
1880 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1881 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1882 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1884 // Verify that rotate3d(axis, angle) post-multiplies the existing matrix.
1885 A.MakeIdentity();
1886 A.Scale3d(6.0, 7.0, 8.0);
1887 A.RotateAboutZAxis(90.0);
1888 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1889 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1890 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1891 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1894 TEST(XFormTest, verifyRotateAboutForArbitraryAxis) {
1895 // Check rotation about an arbitrary non-axis-aligned vector.
1896 Transform A;
1897 A.RotateAbout(Vector3dF(1.0, 1.0, 1.0), 90.0);
1898 EXPECT_ROW1_NEAR(0.3333333333333334258519187,
1899 -0.2440169358562924717404030,
1900 0.9106836025229592124219380,
1901 0.0, A, ERROR_THRESHOLD);
1902 EXPECT_ROW2_NEAR(0.9106836025229592124219380,
1903 0.3333333333333334258519187,
1904 -0.2440169358562924717404030,
1905 0.0, A, ERROR_THRESHOLD);
1906 EXPECT_ROW3_NEAR(-0.2440169358562924717404030,
1907 0.9106836025229592124219380,
1908 0.3333333333333334258519187,
1909 0.0, A, ERROR_THRESHOLD);
1910 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1913 TEST(XFormTest, verifyRotateAboutForDegenerateAxis) {
1914 // Check rotation about a degenerate zero vector.
1915 // It is expected to skip applying the rotation.
1916 Transform A;
1918 A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 45.0);
1919 // Verify that A remains unchanged.
1920 EXPECT_TRUE(A.IsIdentity());
1922 InitializeTestMatrix(&A);
1923 A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 35.0);
1925 // Verify that A remains unchanged.
1926 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, A);
1927 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, A);
1928 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, A);
1929 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, A);
1932 TEST(XFormTest, verifySkewX) {
1933 Transform A;
1934 A.SkewX(45.0);
1935 EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
1936 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1937 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1938 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1940 // Verify that skewX() post-multiplies the existing matrix. Row 1, column 2,
1941 // would incorrectly have value "7" if the matrix is pre-multiplied instead
1942 // of post-multiplied.
1943 A.MakeIdentity();
1944 A.Scale3d(6.0, 7.0, 8.0);
1945 A.SkewX(45.0);
1946 EXPECT_ROW1_EQ(6.0f, 6.0f, 0.0f, 0.0f, A);
1947 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
1948 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1949 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1952 TEST(XFormTest, verifySkewY) {
1953 Transform A;
1954 A.SkewY(45.0);
1955 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1956 EXPECT_ROW2_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
1957 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1958 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1960 // Verify that skewY() post-multiplies the existing matrix. Row 2, column 1 ,
1961 // would incorrectly have value "6" if the matrix is pre-multiplied instead
1962 // of post-multiplied.
1963 A.MakeIdentity();
1964 A.Scale3d(6.0, 7.0, 8.0);
1965 A.SkewY(45.0);
1966 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
1967 EXPECT_ROW2_EQ(7.0f, 7.0f, 0.0f, 0.0f, A);
1968 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1969 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1972 TEST(XFormTest, verifyPerspectiveDepth) {
1973 Transform A;
1974 A.ApplyPerspectiveDepth(1.0);
1975 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1976 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1977 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1978 EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
1980 // Verify that PerspectiveDepth() post-multiplies the existing matrix.
1981 A.MakeIdentity();
1982 A.Translate3d(2.0, 3.0, 4.0);
1983 A.ApplyPerspectiveDepth(1.0);
1984 EXPECT_ROW1_EQ(1.0f, 0.0f, -2.0f, 2.0f, A);
1985 EXPECT_ROW2_EQ(0.0f, 1.0f, -3.0f, 3.0f, A);
1986 EXPECT_ROW3_EQ(0.0f, 0.0f, -3.0f, 4.0f, A);
1987 EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
1990 TEST(XFormTest, verifyHasPerspective) {
1991 Transform A;
1992 A.ApplyPerspectiveDepth(1.0);
1993 EXPECT_TRUE(A.HasPerspective());
1995 A.MakeIdentity();
1996 A.ApplyPerspectiveDepth(0.0);
1997 EXPECT_FALSE(A.HasPerspective());
1999 A.MakeIdentity();
2000 A.matrix().set(3, 0, -1.f);
2001 EXPECT_TRUE(A.HasPerspective());
2003 A.MakeIdentity();
2004 A.matrix().set(3, 1, -1.f);
2005 EXPECT_TRUE(A.HasPerspective());
2007 A.MakeIdentity();
2008 A.matrix().set(3, 2, -0.3f);
2009 EXPECT_TRUE(A.HasPerspective());
2011 A.MakeIdentity();
2012 A.matrix().set(3, 3, 0.5f);
2013 EXPECT_TRUE(A.HasPerspective());
2015 A.MakeIdentity();
2016 A.matrix().set(3, 3, 0.f);
2017 EXPECT_TRUE(A.HasPerspective());
2020 TEST(XFormTest, verifyIsInvertible) {
2021 Transform A;
2023 // Translations, rotations, scales, skews and arbitrary combinations of them
2024 // are invertible.
2025 A.MakeIdentity();
2026 EXPECT_TRUE(A.IsInvertible());
2028 A.MakeIdentity();
2029 A.Translate3d(2.0, 3.0, 4.0);
2030 EXPECT_TRUE(A.IsInvertible());
2032 A.MakeIdentity();
2033 A.Scale3d(6.0, 7.0, 8.0);
2034 EXPECT_TRUE(A.IsInvertible());
2036 A.MakeIdentity();
2037 A.RotateAboutXAxis(10.0);
2038 A.RotateAboutYAxis(20.0);
2039 A.RotateAboutZAxis(30.0);
2040 EXPECT_TRUE(A.IsInvertible());
2042 A.MakeIdentity();
2043 A.SkewX(45.0);
2044 EXPECT_TRUE(A.IsInvertible());
2046 // A perspective matrix (projection plane at z=0) is invertible. The
2047 // intuitive explanation is that perspective is eqivalent to a skew of the
2048 // w-axis; skews are invertible.
2049 A.MakeIdentity();
2050 A.ApplyPerspectiveDepth(1.0);
2051 EXPECT_TRUE(A.IsInvertible());
2053 // A "pure" perspective matrix derived by similar triangles, with m44() set
2054 // to zero (i.e. camera positioned at the origin), is not invertible.
2055 A.MakeIdentity();
2056 A.ApplyPerspectiveDepth(1.0);
2057 A.matrix().set(3, 3, 0.f);
2058 EXPECT_FALSE(A.IsInvertible());
2060 // Adding more to a non-invertible matrix will not make it invertible in the
2061 // general case.
2062 A.MakeIdentity();
2063 A.ApplyPerspectiveDepth(1.0);
2064 A.matrix().set(3, 3, 0.f);
2065 A.Scale3d(6.0, 7.0, 8.0);
2066 A.RotateAboutXAxis(10.0);
2067 A.RotateAboutYAxis(20.0);
2068 A.RotateAboutZAxis(30.0);
2069 A.Translate3d(6.0, 7.0, 8.0);
2070 EXPECT_FALSE(A.IsInvertible());
2072 // A degenerate matrix of all zeros is not invertible.
2073 A.MakeIdentity();
2074 A.matrix().set(0, 0, 0.f);
2075 A.matrix().set(1, 1, 0.f);
2076 A.matrix().set(2, 2, 0.f);
2077 A.matrix().set(3, 3, 0.f);
2078 EXPECT_FALSE(A.IsInvertible());
2081 TEST(XFormTest, verifyIsIdentity) {
2082 Transform A;
2084 InitializeTestMatrix(&A);
2085 EXPECT_FALSE(A.IsIdentity());
2087 A.MakeIdentity();
2088 EXPECT_TRUE(A.IsIdentity());
2090 // Modifying any one individual element should cause the matrix to no longer
2091 // be identity.
2092 A.MakeIdentity();
2093 A.matrix().set(0, 0, 2.f);
2094 EXPECT_FALSE(A.IsIdentity());
2096 A.MakeIdentity();
2097 A.matrix().set(1, 0, 2.f);
2098 EXPECT_FALSE(A.IsIdentity());
2100 A.MakeIdentity();
2101 A.matrix().set(2, 0, 2.f);
2102 EXPECT_FALSE(A.IsIdentity());
2104 A.MakeIdentity();
2105 A.matrix().set(3, 0, 2.f);
2106 EXPECT_FALSE(A.IsIdentity());
2108 A.MakeIdentity();
2109 A.matrix().set(0, 1, 2.f);
2110 EXPECT_FALSE(A.IsIdentity());
2112 A.MakeIdentity();
2113 A.matrix().set(1, 1, 2.f);
2114 EXPECT_FALSE(A.IsIdentity());
2116 A.MakeIdentity();
2117 A.matrix().set(2, 1, 2.f);
2118 EXPECT_FALSE(A.IsIdentity());
2120 A.MakeIdentity();
2121 A.matrix().set(3, 1, 2.f);
2122 EXPECT_FALSE(A.IsIdentity());
2124 A.MakeIdentity();
2125 A.matrix().set(0, 2, 2.f);
2126 EXPECT_FALSE(A.IsIdentity());
2128 A.MakeIdentity();
2129 A.matrix().set(1, 2, 2.f);
2130 EXPECT_FALSE(A.IsIdentity());
2132 A.MakeIdentity();
2133 A.matrix().set(2, 2, 2.f);
2134 EXPECT_FALSE(A.IsIdentity());
2136 A.MakeIdentity();
2137 A.matrix().set(3, 2, 2.f);
2138 EXPECT_FALSE(A.IsIdentity());
2140 A.MakeIdentity();
2141 A.matrix().set(0, 3, 2.f);
2142 EXPECT_FALSE(A.IsIdentity());
2144 A.MakeIdentity();
2145 A.matrix().set(1, 3, 2.f);
2146 EXPECT_FALSE(A.IsIdentity());
2148 A.MakeIdentity();
2149 A.matrix().set(2, 3, 2.f);
2150 EXPECT_FALSE(A.IsIdentity());
2152 A.MakeIdentity();
2153 A.matrix().set(3, 3, 2.f);
2154 EXPECT_FALSE(A.IsIdentity());
2157 TEST(XFormTest, verifyIsIdentityOrTranslation) {
2158 Transform A;
2160 InitializeTestMatrix(&A);
2161 EXPECT_FALSE(A.IsIdentityOrTranslation());
2163 A.MakeIdentity();
2164 EXPECT_TRUE(A.IsIdentityOrTranslation());
2166 // Modifying any non-translation components should cause
2167 // IsIdentityOrTranslation() to return false. NOTE: (0, 3), (1, 3), and
2168 // (2, 3) are the translation components, so modifying them should still
2169 // return true.
2170 A.MakeIdentity();
2171 A.matrix().set(0, 0, 2.f);
2172 EXPECT_FALSE(A.IsIdentityOrTranslation());
2174 A.MakeIdentity();
2175 A.matrix().set(1, 0, 2.f);
2176 EXPECT_FALSE(A.IsIdentityOrTranslation());
2178 A.MakeIdentity();
2179 A.matrix().set(2, 0, 2.f);
2180 EXPECT_FALSE(A.IsIdentityOrTranslation());
2182 A.MakeIdentity();
2183 A.matrix().set(3, 0, 2.f);
2184 EXPECT_FALSE(A.IsIdentityOrTranslation());
2186 A.MakeIdentity();
2187 A.matrix().set(0, 1, 2.f);
2188 EXPECT_FALSE(A.IsIdentityOrTranslation());
2190 A.MakeIdentity();
2191 A.matrix().set(1, 1, 2.f);
2192 EXPECT_FALSE(A.IsIdentityOrTranslation());
2194 A.MakeIdentity();
2195 A.matrix().set(2, 1, 2.f);
2196 EXPECT_FALSE(A.IsIdentityOrTranslation());
2198 A.MakeIdentity();
2199 A.matrix().set(3, 1, 2.f);
2200 EXPECT_FALSE(A.IsIdentityOrTranslation());
2202 A.MakeIdentity();
2203 A.matrix().set(0, 2, 2.f);
2204 EXPECT_FALSE(A.IsIdentityOrTranslation());
2206 A.MakeIdentity();
2207 A.matrix().set(1, 2, 2.f);
2208 EXPECT_FALSE(A.IsIdentityOrTranslation());
2210 A.MakeIdentity();
2211 A.matrix().set(2, 2, 2.f);
2212 EXPECT_FALSE(A.IsIdentityOrTranslation());
2214 A.MakeIdentity();
2215 A.matrix().set(3, 2, 2.f);
2216 EXPECT_FALSE(A.IsIdentityOrTranslation());
2218 // Note carefully - expecting true here.
2219 A.MakeIdentity();
2220 A.matrix().set(0, 3, 2.f);
2221 EXPECT_TRUE(A.IsIdentityOrTranslation());
2223 // Note carefully - expecting true here.
2224 A.MakeIdentity();
2225 A.matrix().set(1, 3, 2.f);
2226 EXPECT_TRUE(A.IsIdentityOrTranslation());
2228 // Note carefully - expecting true here.
2229 A.MakeIdentity();
2230 A.matrix().set(2, 3, 2.f);
2231 EXPECT_TRUE(A.IsIdentityOrTranslation());
2233 A.MakeIdentity();
2234 A.matrix().set(3, 3, 2.f);
2235 EXPECT_FALSE(A.IsIdentityOrTranslation());
2238 TEST(XFormTest, verifyIsApproximatelyIdentityOrTranslation) {
2239 Transform A;
2240 SkMatrix44& matrix = A.matrix();
2242 // Exact pure translation.
2243 A.MakeIdentity();
2245 // Set translate values to values other than 0 or 1.
2246 matrix.set(0, 3, 3.4f);
2247 matrix.set(1, 3, 4.4f);
2248 matrix.set(2, 3, 5.6f);
2250 EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(0));
2251 EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2253 // Approximately pure translation.
2254 InitializeApproxIdentityMatrix(&A);
2256 // Some values must be exact.
2257 matrix.set(3, 0, 0);
2258 matrix.set(3, 1, 0);
2259 matrix.set(3, 2, 0);
2260 matrix.set(3, 3, 1);
2262 // Set translate values to values other than 0 or 1.
2263 matrix.set(0, 3, 3.4f);
2264 matrix.set(1, 3, 4.4f);
2265 matrix.set(2, 3, 5.6f);
2267 EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
2268 EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2270 // Not approximately pure translation.
2271 InitializeApproxIdentityMatrix(&A);
2273 // Some values must be exact.
2274 matrix.set(3, 0, 0);
2275 matrix.set(3, 1, 0);
2276 matrix.set(3, 2, 0);
2277 matrix.set(3, 3, 1);
2279 // Set some values (not translate values) to values other than 0 or 1.
2280 matrix.set(0, 1, 3.4f);
2281 matrix.set(3, 2, 4.4f);
2282 matrix.set(2, 0, 5.6f);
2284 EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
2285 EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2288 TEST(XFormTest, verifyIsScaleOrTranslation) {
2289 Transform A;
2291 InitializeTestMatrix(&A);
2292 EXPECT_FALSE(A.IsScaleOrTranslation());
2294 A.MakeIdentity();
2295 EXPECT_TRUE(A.IsScaleOrTranslation());
2297 // Modifying any non-scale or non-translation components should cause
2298 // IsScaleOrTranslation() to return false. (0, 0), (1, 1), (2, 2), (0, 3),
2299 // (1, 3), and (2, 3) are the scale and translation components, so
2300 // modifying them should still return true.
2302 // Note carefully - expecting true here.
2303 A.MakeIdentity();
2304 A.matrix().set(0, 0, 2.f);
2305 EXPECT_TRUE(A.IsScaleOrTranslation());
2307 A.MakeIdentity();
2308 A.matrix().set(1, 0, 2.f);
2309 EXPECT_FALSE(A.IsScaleOrTranslation());
2311 A.MakeIdentity();
2312 A.matrix().set(2, 0, 2.f);
2313 EXPECT_FALSE(A.IsScaleOrTranslation());
2315 A.MakeIdentity();
2316 A.matrix().set(3, 0, 2.f);
2317 EXPECT_FALSE(A.IsScaleOrTranslation());
2319 A.MakeIdentity();
2320 A.matrix().set(0, 1, 2.f);
2321 EXPECT_FALSE(A.IsScaleOrTranslation());
2323 // Note carefully - expecting true here.
2324 A.MakeIdentity();
2325 A.matrix().set(1, 1, 2.f);
2326 EXPECT_TRUE(A.IsScaleOrTranslation());
2328 A.MakeIdentity();
2329 A.matrix().set(2, 1, 2.f);
2330 EXPECT_FALSE(A.IsScaleOrTranslation());
2332 A.MakeIdentity();
2333 A.matrix().set(3, 1, 2.f);
2334 EXPECT_FALSE(A.IsScaleOrTranslation());
2336 A.MakeIdentity();
2337 A.matrix().set(0, 2, 2.f);
2338 EXPECT_FALSE(A.IsScaleOrTranslation());
2340 A.MakeIdentity();
2341 A.matrix().set(1, 2, 2.f);
2342 EXPECT_FALSE(A.IsScaleOrTranslation());
2344 // Note carefully - expecting true here.
2345 A.MakeIdentity();
2346 A.matrix().set(2, 2, 2.f);
2347 EXPECT_TRUE(A.IsScaleOrTranslation());
2349 A.MakeIdentity();
2350 A.matrix().set(3, 2, 2.f);
2351 EXPECT_FALSE(A.IsScaleOrTranslation());
2353 // Note carefully - expecting true here.
2354 A.MakeIdentity();
2355 A.matrix().set(0, 3, 2.f);
2356 EXPECT_TRUE(A.IsScaleOrTranslation());
2358 // Note carefully - expecting true here.
2359 A.MakeIdentity();
2360 A.matrix().set(1, 3, 2.f);
2361 EXPECT_TRUE(A.IsScaleOrTranslation());
2363 // Note carefully - expecting true here.
2364 A.MakeIdentity();
2365 A.matrix().set(2, 3, 2.f);
2366 EXPECT_TRUE(A.IsScaleOrTranslation());
2368 A.MakeIdentity();
2369 A.matrix().set(3, 3, 2.f);
2370 EXPECT_FALSE(A.IsScaleOrTranslation());
2373 TEST(XFormTest, verifyFlattenTo2d) {
2374 Transform A;
2375 InitializeTestMatrix(&A);
2377 A.FlattenTo2d();
2378 EXPECT_ROW1_EQ(10.0f, 14.0f, 0.0f, 22.0f, A);
2379 EXPECT_ROW2_EQ(11.0f, 15.0f, 0.0f, 23.0f, A);
2380 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
2381 EXPECT_ROW4_EQ(13.0f, 17.0f, 0.0f, 25.0f, A);
2384 TEST(XFormTest, IsFlat) {
2385 Transform transform;
2386 InitializeTestMatrix(&transform);
2388 // A transform with all entries non-zero isn't flat.
2389 EXPECT_FALSE(transform.IsFlat());
2391 transform.matrix().set(0, 2, 0.f);
2392 transform.matrix().set(1, 2, 0.f);
2393 transform.matrix().set(2, 2, 1.f);
2394 transform.matrix().set(3, 2, 0.f);
2396 EXPECT_FALSE(transform.IsFlat());
2398 transform.matrix().set(2, 0, 0.f);
2399 transform.matrix().set(2, 1, 0.f);
2400 transform.matrix().set(2, 3, 0.f);
2402 // Since the third column and row are both (0, 0, 1, 0), the transform is
2403 // flat.
2404 EXPECT_TRUE(transform.IsFlat());
2407 // Another implementation of Preserves2dAxisAlignment that isn't as fast,
2408 // good for testing the faster implementation.
2409 static bool EmpiricallyPreserves2dAxisAlignment(const Transform& transform) {
2410 Point3F p1(5.0f, 5.0f, 0.0f);
2411 Point3F p2(10.0f, 5.0f, 0.0f);
2412 Point3F p3(10.0f, 20.0f, 0.0f);
2413 Point3F p4(5.0f, 20.0f, 0.0f);
2415 QuadF test_quad(PointF(p1.x(), p1.y()),
2416 PointF(p2.x(), p2.y()),
2417 PointF(p3.x(), p3.y()),
2418 PointF(p4.x(), p4.y()));
2419 EXPECT_TRUE(test_quad.IsRectilinear());
2421 transform.TransformPoint(&p1);
2422 transform.TransformPoint(&p2);
2423 transform.TransformPoint(&p3);
2424 transform.TransformPoint(&p4);
2426 QuadF transformedQuad(PointF(p1.x(), p1.y()),
2427 PointF(p2.x(), p2.y()),
2428 PointF(p3.x(), p3.y()),
2429 PointF(p4.x(), p4.y()));
2430 return transformedQuad.IsRectilinear();
2433 TEST(XFormTest, Preserves2dAxisAlignment) {
2434 static const struct TestCase {
2435 SkMScalar a; // row 1, column 1
2436 SkMScalar b; // row 1, column 2
2437 SkMScalar c; // row 2, column 1
2438 SkMScalar d; // row 2, column 2
2439 bool expected;
2440 } test_cases[] = {
2441 { 3.f, 0.f,
2442 0.f, 4.f, true }, // basic case
2443 { 0.f, 4.f,
2444 3.f, 0.f, true }, // rotate by 90
2445 { 0.f, 0.f,
2446 0.f, 4.f, true }, // degenerate x
2447 { 3.f, 0.f,
2448 0.f, 0.f, true }, // degenerate y
2449 { 0.f, 0.f,
2450 3.f, 0.f, true }, // degenerate x + rotate by 90
2451 { 0.f, 4.f,
2452 0.f, 0.f, true }, // degenerate y + rotate by 90
2453 { 3.f, 4.f,
2454 0.f, 0.f, false },
2455 { 0.f, 0.f,
2456 3.f, 4.f, false },
2457 { 0.f, 3.f,
2458 0.f, 4.f, false },
2459 { 3.f, 0.f,
2460 4.f, 0.f, false },
2461 { 3.f, 4.f,
2462 5.f, 0.f, false },
2463 { 3.f, 4.f,
2464 0.f, 5.f, false },
2465 { 3.f, 0.f,
2466 4.f, 5.f, false },
2467 { 0.f, 3.f,
2468 4.f, 5.f, false },
2469 { 2.f, 3.f,
2470 4.f, 5.f, false },
2473 Transform transform;
2474 for (size_t i = 0; i < arraysize(test_cases); ++i) {
2475 const TestCase& value = test_cases[i];
2476 transform.MakeIdentity();
2477 transform.matrix().set(0, 0, value.a);
2478 transform.matrix().set(0, 1, value.b);
2479 transform.matrix().set(1, 0, value.c);
2480 transform.matrix().set(1, 1, value.d);
2482 if (value.expected) {
2483 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2484 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2485 } else {
2486 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2487 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2491 // Try the same test cases again, but this time make sure that other matrix
2492 // elements (except perspective) have entries, to test that they are ignored.
2493 for (size_t i = 0; i < arraysize(test_cases); ++i) {
2494 const TestCase& value = test_cases[i];
2495 transform.MakeIdentity();
2496 transform.matrix().set(0, 0, value.a);
2497 transform.matrix().set(0, 1, value.b);
2498 transform.matrix().set(1, 0, value.c);
2499 transform.matrix().set(1, 1, value.d);
2501 transform.matrix().set(0, 2, 1.f);
2502 transform.matrix().set(0, 3, 2.f);
2503 transform.matrix().set(1, 2, 3.f);
2504 transform.matrix().set(1, 3, 4.f);
2505 transform.matrix().set(2, 0, 5.f);
2506 transform.matrix().set(2, 1, 6.f);
2507 transform.matrix().set(2, 2, 7.f);
2508 transform.matrix().set(2, 3, 8.f);
2510 if (value.expected) {
2511 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2512 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2513 } else {
2514 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2515 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2519 // Try the same test cases again, but this time add perspective which is
2520 // always assumed to not-preserve axis alignment.
2521 for (size_t i = 0; i < arraysize(test_cases); ++i) {
2522 const TestCase& value = test_cases[i];
2523 transform.MakeIdentity();
2524 transform.matrix().set(0, 0, value.a);
2525 transform.matrix().set(0, 1, value.b);
2526 transform.matrix().set(1, 0, value.c);
2527 transform.matrix().set(1, 1, value.d);
2529 transform.matrix().set(0, 2, 1.f);
2530 transform.matrix().set(0, 3, 2.f);
2531 transform.matrix().set(1, 2, 3.f);
2532 transform.matrix().set(1, 3, 4.f);
2533 transform.matrix().set(2, 0, 5.f);
2534 transform.matrix().set(2, 1, 6.f);
2535 transform.matrix().set(2, 2, 7.f);
2536 transform.matrix().set(2, 3, 8.f);
2537 transform.matrix().set(3, 0, 9.f);
2538 transform.matrix().set(3, 1, 10.f);
2539 transform.matrix().set(3, 2, 11.f);
2540 transform.matrix().set(3, 3, 12.f);
2542 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2543 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2546 // Try a few more practical situations to check precision
2547 transform.MakeIdentity();
2548 transform.RotateAboutZAxis(90.0);
2549 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2550 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2552 transform.MakeIdentity();
2553 transform.RotateAboutZAxis(180.0);
2554 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2555 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2557 transform.MakeIdentity();
2558 transform.RotateAboutZAxis(270.0);
2559 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2560 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2562 transform.MakeIdentity();
2563 transform.RotateAboutYAxis(90.0);
2564 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2565 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2567 transform.MakeIdentity();
2568 transform.RotateAboutXAxis(90.0);
2569 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2570 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2572 transform.MakeIdentity();
2573 transform.RotateAboutZAxis(90.0);
2574 transform.RotateAboutYAxis(90.0);
2575 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2576 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2578 transform.MakeIdentity();
2579 transform.RotateAboutZAxis(90.0);
2580 transform.RotateAboutXAxis(90.0);
2581 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2582 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2584 transform.MakeIdentity();
2585 transform.RotateAboutYAxis(90.0);
2586 transform.RotateAboutZAxis(90.0);
2587 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2588 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2590 transform.MakeIdentity();
2591 transform.RotateAboutZAxis(45.0);
2592 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2593 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2595 // 3-d case; In 2d after an orthographic projection, this case does
2596 // preserve 2d axis alignment. But in 3d, it does not preserve axis
2597 // alignment.
2598 transform.MakeIdentity();
2599 transform.RotateAboutYAxis(45.0);
2600 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2601 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2603 transform.MakeIdentity();
2604 transform.RotateAboutXAxis(45.0);
2605 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2606 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2608 // Perspective cases.
2609 transform.MakeIdentity();
2610 transform.ApplyPerspectiveDepth(10.0);
2611 transform.RotateAboutYAxis(45.0);
2612 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2613 EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2615 transform.MakeIdentity();
2616 transform.ApplyPerspectiveDepth(10.0);
2617 transform.RotateAboutZAxis(90.0);
2618 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2619 EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2622 TEST(XFormTest, To2dTranslation) {
2623 Vector2dF translation(3.f, 7.f);
2624 Transform transform;
2625 transform.Translate(translation.x(), translation.y() + 1);
2626 EXPECT_NE(translation.ToString(), transform.To2dTranslation().ToString());
2627 transform.MakeIdentity();
2628 transform.Translate(translation.x(), translation.y());
2629 EXPECT_EQ(translation.ToString(), transform.To2dTranslation().ToString());
2632 TEST(XFormTest, TransformRect) {
2633 Transform translation;
2634 translation.Translate(3.f, 7.f);
2635 RectF rect(1.f, 2.f, 3.f, 4.f);
2636 RectF expected(4.f, 9.f, 3.f, 4.f);
2637 translation.TransformRect(&rect);
2638 EXPECT_EQ(expected.ToString(), rect.ToString());
2641 TEST(XFormTest, TransformRectReverse) {
2642 Transform translation;
2643 translation.Translate(3.f, 7.f);
2644 RectF rect(1.f, 2.f, 3.f, 4.f);
2645 RectF expected(-2.f, -5.f, 3.f, 4.f);
2646 EXPECT_TRUE(translation.TransformRectReverse(&rect));
2647 EXPECT_EQ(expected.ToString(), rect.ToString());
2649 Transform singular;
2650 singular.Scale3d(0.f, 0.f, 0.f);
2651 EXPECT_FALSE(singular.TransformRectReverse(&rect));
2654 TEST(XFormTest, TransformBox) {
2655 Transform translation;
2656 translation.Translate3d(3.f, 7.f, 6.f);
2657 BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f);
2658 BoxF expected(4.f, 9.f, 9.f, 4.f, 5.f, 6.f);
2659 translation.TransformBox(&box);
2660 EXPECT_EQ(expected.ToString(), box.ToString());
2663 TEST(XFormTest, TransformBoxReverse) {
2664 Transform translation;
2665 translation.Translate3d(3.f, 7.f, 6.f);
2666 BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f);
2667 BoxF expected(-2.f, -5.f, -3.f, 4.f, 5.f, 6.f);
2668 EXPECT_TRUE(translation.TransformBoxReverse(&box));
2669 EXPECT_EQ(expected.ToString(), box.ToString());
2671 Transform singular;
2672 singular.Scale3d(0.f, 0.f, 0.f);
2673 EXPECT_FALSE(singular.TransformBoxReverse(&box));
2676 TEST(XFormTest, RoundTranslationComponents) {
2677 Transform translation;
2678 Transform expected;
2680 translation.RoundTranslationComponents();
2681 EXPECT_EQ(expected.ToString(), translation.ToString());
2683 translation.Translate(1.0f, 1.0f);
2684 expected.Translate(1.0f, 1.0f);
2685 translation.RoundTranslationComponents();
2686 EXPECT_EQ(expected.ToString(), translation.ToString());
2688 translation.Translate(0.5f, 0.4f);
2689 expected.Translate(1.0f, 0.0f);
2690 translation.RoundTranslationComponents();
2691 EXPECT_EQ(expected.ToString(), translation.ToString());
2693 // Rounding should only affect 2d translation components.
2694 translation.Translate3d(0.f, 0.f, 0.5f);
2695 expected.Translate3d(0.f, 0.f, 0.5f);
2696 translation.RoundTranslationComponents();
2697 EXPECT_EQ(expected.ToString(), translation.ToString());
2700 } // namespace
2702 } // namespace gfx