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. 4 5 // MSVC++ requires this to be set before any other includes to get M_PI. 6 #define _USE_MATH_DEFINES 7 8 #include "ui/gfx/transform.h" 9 10 #include <cmath> 11 #include <ostream> 12 #include <limits> 13 14 #include "base/basictypes.h" 15 #include "base/logging.h" 16 #include "testing/gtest/include/gtest/gtest.h" 17 #include "ui/gfx/box_f.h" 18 #include "ui/gfx/point.h" 19 #include "ui/gfx/point3_f.h" 20 #include "ui/gfx/quad_f.h" 21 #include "ui/gfx/transform_util.h" 22 #include "ui/gfx/vector3d_f.h" 23 24 namespace gfx { 25 26 namespace { 27 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)); 33 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)); 39 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)); 45 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)); \ 51 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)); 60 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)); 66 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)); 72 73 bool PointsAreNearlyEqual(const Point3F& lhs, 74 const Point3F& rhs) { 75 float epsilon = 0.0001f; 76 return lhs.SquaredDistanceTo(rhs) < epsilon; 77 } 78 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; 87 } 88 } 89 return true; 90 } 91 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); 110 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)); 116 } 117 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); 136 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)); 142 } 143 144 const SkMScalar kApproxZero = 145 SkFloatToMScalar(std::numeric_limits<float>::epsilon()); 146 const SkMScalar kApproxOne = 1 - kApproxZero; 147 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); 154 155 matrix.set(1, 0, kApproxZero); 156 matrix.set(1, 1, kApproxOne); 157 matrix.set(1, 2, kApproxZero); 158 matrix.set(1, 3, kApproxZero); 159 160 matrix.set(2, 0, kApproxZero); 161 matrix.set(2, 1, kApproxZero); 162 matrix.set(2, 2, kApproxOne); 163 matrix.set(2, 3, kApproxZero); 164 165 matrix.set(3, 0, kApproxZero); 166 matrix.set(3, 1, kApproxZero); 167 matrix.set(3, 2, kApproxZero); 168 matrix.set(3, 3, kApproxOne); 169 } 170 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 177 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); 191 } 192 } 193 if (i == 100) { 194 EXPECT_TRUE(rhs == interpolated); 195 } else { 196 EXPECT_TRUE(rhs != interpolated); 197 } 198 } 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); 209 } 210 } 211 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 }, 228 }; 229 230 Transform xform; 231 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 232 const TestCase& value = test_cases[i]; 233 Transform translation; 234 translation.Translate(value.tx, value.ty); 235 xform = translation * xform; 236 Point3F p1(value.x1, value.y1, 0); 237 Point3F p2(value.x2, value.y2, 0); 238 xform.TransformPoint(&p1); 239 if (value.tx == value.tx && 240 value.ty == value.ty) { 241 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2)); 242 } 243 } 244 } 245 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 } 257 }; 258 259 Transform xform; 260 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(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)); 270 } 271 } 272 } 273 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 } 288 }; 289 290 Transform xform; 291 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(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)); 301 } 302 } 303 } 304 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 } 318 }; 319 320 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 321 const TestCase& value = test_cases[i]; 322 for (int k = 0; k < 3; ++k) { 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; 341 } 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)); 349 } 350 } 351 } 352 } 353 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 }, 365 }; 366 367 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 368 const TestCase& value = test_cases[i]; 369 for (int k = 0; k < 3; ++k) { 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; 388 } 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)); 396 } 397 } 398 } 399 } 400 } 401 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 } 418 }; 419 420 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(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)); 434 } 435 } 436 } 437 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}, 455 }; 456 457 Transform xform; 458 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 459 const TestCase& value = test_cases[i]; 460 Transform translation; 461 translation.Translate(value.tx, value.ty); 462 xform = translation * xform; 463 Point p1(value.x1, value.y1); 464 Point p2(value.x2, value.y2); 465 xform.TransformPoint(&p1); 466 if (value.tx == value.tx && 467 value.ty == value.ty) { 468 EXPECT_EQ(p1.x(), p2.x()); 469 EXPECT_EQ(p1.y(), p2.y()); 470 } 471 } 472 } 473 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} 485 }; 486 487 Transform xform; 488 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(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()); 499 } 500 } 501 } 502 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} 517 }; 518 519 Transform xform; 520 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(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()); 531 } 532 } 533 } 534 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} 548 }; 549 550 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 551 const TestCase& value = test_cases[i]; 552 for (int j = -1; j < 2; ++j) { 553 for (int k = 0; k < 3; ++k) { 554 float epsilon = 0.0001f; 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; 574 } 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()); 584 } 585 } 586 } 587 } 588 } 589 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}, 601 }; 602 603 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 604 const TestCase& value = test_cases[i]; 605 for (int j = -1; j < 2; ++j) { 606 for (int k = 0; k < 3; ++k) { 607 float epsilon = 0.0001f; 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; 629 } 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()); 639 } 640 } 641 } 642 } 643 } 644 } 645 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} 662 }; 663 664 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(set_rotate_cases); ++i) { 665 const SetRotateCase& value = set_rotate_cases[i]; 666 for (int j = 1; j >= -1; --j) { 667 float epsilon = 0.1f; 668 Point pt(value.x, value.y); 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); 680 } 681 } 682 } 683 } 684 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()); 692 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()); 700 } 701 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)); 712 } 713 } 714 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) 721 }; 722 Transform from; 723 for (size_t index = 0; index < ARRAYSIZE_UNSAFE(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)); 729 730 Transform expected; 731 expected.RotateAbout(axes[index], 90 * t); 732 733 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to)); 734 } 735 } 736 } 737 738 TEST(XFormTest, BlendRotateFollowsShortestPath) { 739 // Verify that we interpolate along the shortest path regardless of whether 740 // this path crosses the 180-degree point. 741 Vector3dF axes[] = { 742 Vector3dF(1, 0, 0), 743 Vector3dF(0, 1, 0), 744 Vector3dF(0, 0, 1), 745 Vector3dF(1, 1, 1) 746 }; 747 for (size_t index = 0; index < ARRAYSIZE_UNSAFE(axes); ++index) { 748 for (int i = -5; i < 15; ++i) { 749 Transform from1; 750 from1.RotateAbout(axes[index], 130.0); 751 Transform to1; 752 to1.RotateAbout(axes[index], 175.0); 753 754 Transform from2; 755 from2.RotateAbout(axes[index], 140.0); 756 Transform to2; 757 to2.RotateAbout(axes[index], 185.0); 758 759 double t = i / 9.0; 760 EXPECT_TRUE(to1.Blend(from1, t)); 761 EXPECT_TRUE(to2.Blend(from2, t)); 762 763 Transform expected1; 764 expected1.RotateAbout(axes[index], 130.0 + 45.0 * t); 765 766 Transform expected2; 767 expected2.RotateAbout(axes[index], 140.0 + 45.0 * t); 768 769 EXPECT_TRUE(MatricesAreNearlyEqual(expected1, to1)); 770 EXPECT_TRUE(MatricesAreNearlyEqual(expected2, to2)); 771 } 772 } 773 } 774 775 TEST(XFormTest, CanBlend180DegreeRotation) { 776 Vector3dF axes[] = { 777 Vector3dF(1, 0, 0), 778 Vector3dF(0, 1, 0), 779 Vector3dF(0, 0, 1), 780 Vector3dF(1, 1, 1) 781 }; 782 Transform from; 783 for (size_t index = 0; index < ARRAYSIZE_UNSAFE(axes); ++index) { 784 for (int i = -5; i < 15; ++i) { 785 Transform to; 786 to.RotateAbout(axes[index], 180.0); 787 double t = i / 9.0; 788 EXPECT_TRUE(to.Blend(from, t)); 789 790 // A 180 degree rotation is exactly opposite on the sphere, therefore 791 // either great circle arc to it is equivalent (and numerical precision 792 // will determine which is closer). Test both directions. 793 Transform expected1; 794 expected1.RotateAbout(axes[index], 180.0 * t); 795 Transform expected2; 796 expected2.RotateAbout(axes[index], -180.0 * t); 797 798 EXPECT_TRUE(MatricesAreNearlyEqual(expected1, to) || 799 MatricesAreNearlyEqual(expected2, to)) 800 << "axis: " << index << ", i: " << i; 801 } 802 } 803 } 804 805 TEST(XFormTest, BlendScale) { 806 Transform from; 807 for (int i = -5; i < 15; ++i) { 808 Transform to; 809 to.Scale3d(5, 4, 3); 810 double t = i / 9.0; 811 EXPECT_TRUE(to.Blend(from, t)); 812 EXPECT_FLOAT_EQ(t * 4 + 1, to.matrix().get(0, 0)) << "i: " << i; 813 EXPECT_FLOAT_EQ(t * 3 + 1, to.matrix().get(1, 1)) << "i: " << i; 814 EXPECT_FLOAT_EQ(t * 2 + 1, to.matrix().get(2, 2)) << "i: " << i; 815 } 816 } 817 818 TEST(XFormTest, BlendSkew) { 819 Transform from; 820 for (int i = 0; i < 2; ++i) { 821 Transform to; 822 to.SkewX(10); 823 to.SkewY(5); 824 double t = i; 825 Transform expected; 826 expected.SkewX(t * 10); 827 expected.SkewY(t * 5); 828 EXPECT_TRUE(to.Blend(from, t)); 829 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to)); 830 } 831 } 832 833 TEST(XFormTest, ExtrapolateSkew) { 834 Transform from; 835 for (int i = -1; i < 2; ++i) { 836 Transform to; 837 to.SkewX(20); 838 double t = i; 839 Transform expected; 840 expected.SkewX(t * 20); 841 EXPECT_TRUE(to.Blend(from, t)); 842 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to)); 843 } 844 } 845 846 TEST(XFormTest, BlendPerspective) { 847 Transform from; 848 from.ApplyPerspectiveDepth(200); 849 for (int i = -1; i < 3; ++i) { 850 Transform to; 851 to.ApplyPerspectiveDepth(800); 852 double t = i; 853 double depth = 1.0 / ((1.0 / 200) * (1.0 - t) + (1.0 / 800) * t); 854 Transform expected; 855 expected.ApplyPerspectiveDepth(depth); 856 EXPECT_TRUE(to.Blend(from, t)); 857 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to)); 858 } 859 } 860 861 TEST(XFormTest, BlendIdentity) { 862 Transform from; 863 Transform to; 864 EXPECT_TRUE(to.Blend(from, 0.5)); 865 EXPECT_EQ(to, from); 866 } 867 868 TEST(XFormTest, CannotBlendSingularMatrix) { 869 Transform from; 870 Transform to; 871 to.matrix().set(1, 1, SkDoubleToMScalar(0)); 872 EXPECT_FALSE(to.Blend(from, 0.5)); 873 } 874 875 TEST(XFormTest, VerifyBlendForTranslation) { 876 Transform from; 877 from.Translate3d(100.0, 200.0, 100.0); 878 879 Transform to; 880 881 to.Translate3d(200.0, 100.0, 300.0); 882 to.Blend(from, 0.0); 883 EXPECT_EQ(from, to); 884 885 to = Transform(); 886 to.Translate3d(200.0, 100.0, 300.0); 887 to.Blend(from, 0.25); 888 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 125.0f, to); 889 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 175.0f, to); 890 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 150.0f, to); 891 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 892 893 to = Transform(); 894 to.Translate3d(200.0, 100.0, 300.0); 895 to.Blend(from, 0.5); 896 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 150.0f, to); 897 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 150.0f, to); 898 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 200.0f, to); 899 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 900 901 to = Transform(); 902 to.Translate3d(200.0, 100.0, 300.0); 903 to.Blend(from, 1.0); 904 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 200.0f, to); 905 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 100.0f, to); 906 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 300.0f, to); 907 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 908 } 909 910 TEST(XFormTest, VerifyBlendForScale) { 911 Transform from; 912 from.Scale3d(100.0, 200.0, 100.0); 913 914 Transform to; 915 916 to.Scale3d(200.0, 100.0, 300.0); 917 to.Blend(from, 0.0); 918 EXPECT_EQ(from, to); 919 920 to = Transform(); 921 to.Scale3d(200.0, 100.0, 300.0); 922 to.Blend(from, 0.25); 923 EXPECT_ROW1_EQ(125.0f, 0.0f, 0.0f, 0.0f, to); 924 EXPECT_ROW2_EQ(0.0f, 175.0f, 0.0f, 0.0f, to); 925 EXPECT_ROW3_EQ(0.0f, 0.0f, 150.0f, 0.0f, to); 926 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 927 928 to = Transform(); 929 to.Scale3d(200.0, 100.0, 300.0); 930 to.Blend(from, 0.5); 931 EXPECT_ROW1_EQ(150.0f, 0.0f, 0.0f, 0.0f, to); 932 EXPECT_ROW2_EQ(0.0f, 150.0f, 0.0f, 0.0f, to); 933 EXPECT_ROW3_EQ(0.0f, 0.0f, 200.0f, 0.0f, to); 934 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 935 936 to = Transform(); 937 to.Scale3d(200.0, 100.0, 300.0); 938 to.Blend(from, 1.0); 939 EXPECT_ROW1_EQ(200.0f, 0.0f, 0.0f, 0.0f, to); 940 EXPECT_ROW2_EQ(0.0f, 100.0f, 0.0f, 0.0f, to); 941 EXPECT_ROW3_EQ(0.0f, 0.0f, 300.0f, 0.0f, to); 942 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 943 } 944 945 TEST(XFormTest, VerifyBlendForSkewX) { 946 Transform from; 947 from.SkewX(0.0); 948 949 Transform to; 950 951 to.SkewX(45.0); 952 to.Blend(from, 0.0); 953 EXPECT_EQ(from, to); 954 955 to = Transform(); 956 to.SkewX(45.0); 957 to.Blend(from, 0.5); 958 EXPECT_ROW1_EQ(1.0f, 0.5f, 0.0f, 0.0f, to); 959 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to); 960 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to); 961 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 962 963 to = Transform(); 964 to.SkewX(45.0); 965 to.Blend(from, 0.25); 966 EXPECT_ROW1_EQ(1.0f, 0.25f, 0.0f, 0.0f, to); 967 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to); 968 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to); 969 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 970 971 to = Transform(); 972 to.SkewX(45.0); 973 to.Blend(from, 1.0); 974 EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, to); 975 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to); 976 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to); 977 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 978 } 979 980 TEST(XFormTest, VerifyBlendForSkewY) { 981 // NOTE CAREFULLY: Decomposition of skew and rotation terms of the matrix 982 // is inherently underconstrained, and so it does not always compute the 983 // originally intended skew parameters. The current implementation uses QR 984 // decomposition, which decomposes the shear into a rotation + non-uniform 985 // scale. 986 // 987 // It is unlikely that the decomposition implementation will need to change 988 // very often, so to get any test coverage, the compromise is to verify the 989 // exact matrix that the.Blend() operation produces. 990 // 991 // This problem also potentially exists for skewX, but the current QR 992 // decomposition implementation just happens to decompose those test 993 // matrices intuitively. 994 // 995 // Unfortunately, this case suffers from uncomfortably large precision 996 // error. 997 998 Transform from; 999 from.SkewY(0.0); 1000 1001 Transform to; 1002 1003 to.SkewY(45.0); 1004 to.Blend(from, 0.0); 1005 EXPECT_EQ(from, to); 1006 1007 to = Transform(); 1008 to.SkewY(45.0); 1009 to.Blend(from, 0.25); 1010 EXPECT_ROW1_NEAR(1.0823489449280947471976333, 1011 0.0464370719145053845178239, 1012 0.0, 1013 0.0, 1014 to, 1015 LOOSE_ERROR_THRESHOLD); 1016 EXPECT_ROW2_NEAR(0.2152925909665224513123150, 1017 0.9541702441750861130032035, 1018 0.0, 1019 0.0, 1020 to, 1021 LOOSE_ERROR_THRESHOLD); 1022 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to); 1023 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1024 1025 to = Transform(); 1026 to.SkewY(45.0); 1027 to.Blend(from, 0.5); 1028 EXPECT_ROW1_NEAR(1.1152212925809066312865525, 1029 0.0676495144007326631996335, 1030 0.0, 1031 0.0, 1032 to, 1033 LOOSE_ERROR_THRESHOLD); 1034 EXPECT_ROW2_NEAR(0.4619397844342648662419037, 1035 0.9519009045724774464858342, 1036 0.0, 1037 0.0, 1038 to, 1039 LOOSE_ERROR_THRESHOLD); 1040 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to); 1041 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1042 1043 to = Transform(); 1044 to.SkewY(45.0); 1045 to.Blend(from, 1.0); 1046 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD); 1047 EXPECT_ROW2_NEAR(1.0, 1.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD); 1048 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to); 1049 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1050 } 1051 1052 TEST(XFormTest, VerifyBlendForRotationAboutX) { 1053 // Even though.Blending uses quaternions, axis-aligned rotations should. 1054 // Blend the same with quaternions or Euler angles. So we can test 1055 // rotation.Blending by comparing against manually specified matrices from 1056 // Euler angles. 1057 1058 Transform from; 1059 from.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 0.0); 1060 1061 Transform to; 1062 1063 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0); 1064 to.Blend(from, 0.0); 1065 EXPECT_EQ(from, to); 1066 1067 double expectedRotationAngle = 22.5 * M_PI / 180.0; 1068 to = Transform(); 1069 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0); 1070 to.Blend(from, 0.25); 1071 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1072 EXPECT_ROW2_NEAR(0.0, 1073 std::cos(expectedRotationAngle), 1074 -std::sin(expectedRotationAngle), 1075 0.0, 1076 to, 1077 ERROR_THRESHOLD); 1078 EXPECT_ROW3_NEAR(0.0, 1079 std::sin(expectedRotationAngle), 1080 std::cos(expectedRotationAngle), 1081 0.0, 1082 to, 1083 ERROR_THRESHOLD); 1084 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1085 1086 expectedRotationAngle = 45.0 * M_PI / 180.0; 1087 to = Transform(); 1088 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0); 1089 to.Blend(from, 0.5); 1090 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1091 EXPECT_ROW2_NEAR(0.0, 1092 std::cos(expectedRotationAngle), 1093 -std::sin(expectedRotationAngle), 1094 0.0, 1095 to, 1096 ERROR_THRESHOLD); 1097 EXPECT_ROW3_NEAR(0.0, 1098 std::sin(expectedRotationAngle), 1099 std::cos(expectedRotationAngle), 1100 0.0, 1101 to, 1102 ERROR_THRESHOLD); 1103 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1104 1105 to = Transform(); 1106 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0); 1107 to.Blend(from, 1.0); 1108 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1109 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, to, ERROR_THRESHOLD); 1110 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1111 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1112 } 1113 1114 TEST(XFormTest, VerifyBlendForRotationAboutY) { 1115 Transform from; 1116 from.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 0.0); 1117 1118 Transform to; 1119 1120 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0); 1121 to.Blend(from, 0.0); 1122 EXPECT_EQ(from, to); 1123 1124 double expectedRotationAngle = 22.5 * M_PI / 180.0; 1125 to = Transform(); 1126 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0); 1127 to.Blend(from, 0.25); 1128 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle), 1129 0.0, 1130 std::sin(expectedRotationAngle), 1131 0.0, 1132 to, 1133 ERROR_THRESHOLD); 1134 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1135 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle), 1136 0.0, 1137 std::cos(expectedRotationAngle), 1138 0.0, 1139 to, 1140 ERROR_THRESHOLD); 1141 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1142 1143 expectedRotationAngle = 45.0 * M_PI / 180.0; 1144 to = Transform(); 1145 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0); 1146 to.Blend(from, 0.5); 1147 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle), 1148 0.0, 1149 std::sin(expectedRotationAngle), 1150 0.0, 1151 to, 1152 ERROR_THRESHOLD); 1153 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1154 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle), 1155 0.0, 1156 std::cos(expectedRotationAngle), 1157 0.0, 1158 to, 1159 ERROR_THRESHOLD); 1160 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1161 1162 to = Transform(); 1163 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0); 1164 to.Blend(from, 1.0); 1165 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD); 1166 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1167 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1168 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1169 } 1170 1171 TEST(XFormTest, VerifyBlendForRotationAboutZ) { 1172 Transform from; 1173 from.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 0.0); 1174 1175 Transform to; 1176 1177 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0); 1178 to.Blend(from, 0.0); 1179 EXPECT_EQ(from, to); 1180 1181 double expectedRotationAngle = 22.5 * M_PI / 180.0; 1182 to = Transform(); 1183 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0); 1184 to.Blend(from, 0.25); 1185 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle), 1186 -std::sin(expectedRotationAngle), 1187 0.0, 1188 0.0, 1189 to, 1190 ERROR_THRESHOLD); 1191 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle), 1192 std::cos(expectedRotationAngle), 1193 0.0, 1194 0.0, 1195 to, 1196 ERROR_THRESHOLD); 1197 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD); 1198 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1199 1200 expectedRotationAngle = 45.0 * M_PI / 180.0; 1201 to = Transform(); 1202 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0); 1203 to.Blend(from, 0.5); 1204 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle), 1205 -std::sin(expectedRotationAngle), 1206 0.0, 1207 0.0, 1208 to, 1209 ERROR_THRESHOLD); 1210 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle), 1211 std::cos(expectedRotationAngle), 1212 0.0, 1213 0.0, 1214 to, 1215 ERROR_THRESHOLD); 1216 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD); 1217 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1218 1219 to = Transform(); 1220 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0); 1221 to.Blend(from, 1.0); 1222 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1223 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1224 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD); 1225 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1226 } 1227 1228 TEST(XFormTest, VerifyBlendForCompositeTransform) { 1229 // Verify that the.Blending was done with a decomposition in correct order 1230 // by blending a composite transform. Using matrix x vector notation 1231 // (Ax = b, where x is column vector), the ordering should be: 1232 // perspective * translation * rotation * skew * scale 1233 // 1234 // It is not as important (or meaningful) to check intermediate 1235 // interpolations; order of operations will be tested well enough by the 1236 // end cases that are easier to specify. 1237 1238 Transform from; 1239 Transform to; 1240 1241 Transform expectedEndOfAnimation; 1242 expectedEndOfAnimation.ApplyPerspectiveDepth(1.0); 1243 expectedEndOfAnimation.Translate3d(10.0, 20.0, 30.0); 1244 expectedEndOfAnimation.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 25.0); 1245 expectedEndOfAnimation.SkewY(45.0); 1246 expectedEndOfAnimation.Scale3d(6.0, 7.0, 8.0); 1247 1248 to = expectedEndOfAnimation; 1249 to.Blend(from, 0.0); 1250 EXPECT_EQ(from, to); 1251 1252 to = expectedEndOfAnimation; 1253 // We short circuit if blend is >= 1, so to check the numerics, we will 1254 // check that we get close to what we expect when we're nearly done 1255 // interpolating. 1256 to.Blend(from, .99999f); 1257 1258 // Recomposing the matrix results in a normalized matrix, so to verify we 1259 // need to normalize the expectedEndOfAnimation before comparing elements. 1260 // Normalizing means dividing everything by expectedEndOfAnimation.m44(). 1261 Transform normalizedExpectedEndOfAnimation = expectedEndOfAnimation; 1262 Transform normalizationMatrix; 1263 normalizationMatrix.matrix().set( 1264 0.0, 1265 0.0, 1266 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0))); 1267 normalizationMatrix.matrix().set( 1268 1.0, 1269 1.0, 1270 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0))); 1271 normalizationMatrix.matrix().set( 1272 2.0, 1273 2.0, 1274 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0))); 1275 normalizationMatrix.matrix().set( 1276 3.0, 1277 3.0, 1278 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0))); 1279 normalizedExpectedEndOfAnimation.PreconcatTransform(normalizationMatrix); 1280 1281 EXPECT_TRUE(MatricesAreNearlyEqual(normalizedExpectedEndOfAnimation, to)); 1282 } 1283 1284 TEST(XFormTest, DecomposedTransformCtor) { 1285 DecomposedTransform decomp; 1286 for (int i = 0; i < 3; ++i) { 1287 EXPECT_EQ(0.0, decomp.translate[i]); 1288 EXPECT_EQ(1.0, decomp.scale[i]); 1289 EXPECT_EQ(0.0, decomp.skew[i]); 1290 EXPECT_EQ(0.0, decomp.quaternion[i]); 1291 EXPECT_EQ(0.0, decomp.perspective[i]); 1292 } 1293 EXPECT_EQ(1.0, decomp.quaternion[3]); 1294 EXPECT_EQ(1.0, decomp.perspective[3]); 1295 Transform identity; 1296 Transform composed = ComposeTransform(decomp); 1297 EXPECT_TRUE(MatricesAreNearlyEqual(identity, composed)); 1298 } 1299 1300 TEST(XFormTest, FactorTRS) { 1301 for (int degrees = 0; degrees < 180; ++degrees) { 1302 // build a transformation matrix. 1303 gfx::Transform transform; 1304 transform.Translate(degrees * 2, -degrees * 3); 1305 transform.Rotate(degrees); 1306 transform.Scale(degrees + 1, 2 * degrees + 1); 1307 1308 // factor the matrix 1309 DecomposedTransform decomp; 1310 bool success = DecomposeTransform(&decomp, transform); 1311 EXPECT_TRUE(success); 1312 EXPECT_FLOAT_EQ(decomp.translate[0], degrees * 2); 1313 EXPECT_FLOAT_EQ(decomp.translate[1], -degrees * 3); 1314 double rotation = 1315 std::acos(SkMScalarToDouble(decomp.quaternion[3])) * 360.0 / M_PI; 1316 while (rotation < 0.0) 1317 rotation += 360.0; 1318 while (rotation > 360.0) 1319 rotation -= 360.0; 1320 1321 const float epsilon = 0.00015f; 1322 EXPECT_NEAR(rotation, degrees, epsilon); 1323 EXPECT_NEAR(decomp.scale[0], degrees + 1, epsilon); 1324 EXPECT_NEAR(decomp.scale[1], 2 * degrees + 1, epsilon); 1325 } 1326 } 1327 1328 TEST(XFormTest, IntegerTranslation) { 1329 gfx::Transform transform; 1330 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation()); 1331 1332 transform.Translate3d(1, 2, 3); 1333 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation()); 1334 1335 transform.MakeIdentity(); 1336 transform.Translate3d(-1, -2, -3); 1337 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation()); 1338 1339 transform.MakeIdentity(); 1340 transform.Translate3d(4.5f, 0, 0); 1341 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation()); 1342 1343 transform.MakeIdentity(); 1344 transform.Translate3d(0, -6.7f, 0); 1345 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation()); 1346 1347 transform.MakeIdentity(); 1348 transform.Translate3d(0, 0, 8.9f); 1349 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation()); 1350 } 1351 1352 TEST(XFormTest, verifyMatrixInversion) { 1353 { 1354 // Invert a translation 1355 gfx::Transform translation; 1356 translation.Translate3d(2.0, 3.0, 4.0); 1357 EXPECT_TRUE(translation.IsInvertible()); 1358 1359 gfx::Transform inverse_translation; 1360 bool is_invertible = translation.GetInverse(&inverse_translation); 1361 EXPECT_TRUE(is_invertible); 1362 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, -2.0f, inverse_translation); 1363 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, -3.0f, inverse_translation); 1364 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, -4.0f, inverse_translation); 1365 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_translation); 1366 } 1367 1368 { 1369 // Invert a non-uniform scale 1370 gfx::Transform scale; 1371 scale.Scale3d(4.0, 10.0, 100.0); 1372 EXPECT_TRUE(scale.IsInvertible()); 1373 1374 gfx::Transform inverse_scale; 1375 bool is_invertible = scale.GetInverse(&inverse_scale); 1376 EXPECT_TRUE(is_invertible); 1377 EXPECT_ROW1_EQ(0.25f, 0.0f, 0.0f, 0.0f, inverse_scale); 1378 EXPECT_ROW2_EQ(0.0f, 0.1f, 0.0f, 0.0f, inverse_scale); 1379 EXPECT_ROW3_EQ(0.0f, 0.0f, 0.01f, 0.0f, inverse_scale); 1380 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_scale); 1381 } 1382 1383 { 1384 // Try to invert a matrix that is not invertible. 1385 // The inverse() function should reset the output matrix to identity. 1386 gfx::Transform uninvertible; 1387 uninvertible.matrix().set(0, 0, 0.f); 1388 uninvertible.matrix().set(1, 1, 0.f); 1389 uninvertible.matrix().set(2, 2, 0.f); 1390 uninvertible.matrix().set(3, 3, 0.f); 1391 EXPECT_FALSE(uninvertible.IsInvertible()); 1392 1393 gfx::Transform inverse_of_uninvertible; 1394 1395 // Add a scale just to more easily ensure that inverse_of_uninvertible is 1396 // reset to identity. 1397 inverse_of_uninvertible.Scale3d(4.0, 10.0, 100.0); 1398 1399 bool is_invertible = uninvertible.GetInverse(&inverse_of_uninvertible); 1400 EXPECT_FALSE(is_invertible); 1401 EXPECT_TRUE(inverse_of_uninvertible.IsIdentity()); 1402 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, inverse_of_uninvertible); 1403 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, inverse_of_uninvertible); 1404 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, inverse_of_uninvertible); 1405 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_of_uninvertible); 1406 } 1407 } 1408 1409 TEST(XFormTest, verifyBackfaceVisibilityBasicCases) { 1410 Transform transform; 1411 1412 transform.MakeIdentity(); 1413 EXPECT_FALSE(transform.IsBackFaceVisible()); 1414 1415 transform.MakeIdentity(); 1416 transform.RotateAboutYAxis(80.0); 1417 EXPECT_FALSE(transform.IsBackFaceVisible()); 1418 1419 transform.MakeIdentity(); 1420 transform.RotateAboutYAxis(100.0); 1421 EXPECT_TRUE(transform.IsBackFaceVisible()); 1422 1423 // Edge case, 90 degree rotation should return false. 1424 transform.MakeIdentity(); 1425 transform.RotateAboutYAxis(90.0); 1426 EXPECT_FALSE(transform.IsBackFaceVisible()); 1427 } 1428 1429 TEST(XFormTest, verifyBackfaceVisibilityForPerspective) { 1430 Transform layer_space_to_projection_plane; 1431 1432 // This tests if IsBackFaceVisible works properly under perspective 1433 // transforms. Specifically, layers that may have their back face visible in 1434 // orthographic projection, may not actually have back face visible under 1435 // perspective projection. 1436 1437 // Case 1: Layer is rotated by slightly more than 90 degrees, at the center 1438 // of the prespective projection. In this case, the layer's back-side 1439 // is visible to the camera. 1440 layer_space_to_projection_plane.MakeIdentity(); 1441 layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0); 1442 layer_space_to_projection_plane.Translate3d(0.0, 0.0, 0.0); 1443 layer_space_to_projection_plane.RotateAboutYAxis(100.0); 1444 EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible()); 1445 1446 // Case 2: Layer is rotated by slightly more than 90 degrees, but shifted off 1447 // to the side of the camera. Because of the wide field-of-view, the 1448 // layer's front side is still visible. 1449 // 1450 // |<-- front side of layer is visible to camera 1451 // \ | / 1452 // \ | / 1453 // \| / 1454 // | / 1455 // |\ /<-- camera field of view 1456 // | \ / 1457 // back side of layer -->| \ / 1458 // \./ <-- camera origin 1459 // 1460 layer_space_to_projection_plane.MakeIdentity(); 1461 layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0); 1462 layer_space_to_projection_plane.Translate3d(-10.0, 0.0, 0.0); 1463 layer_space_to_projection_plane.RotateAboutYAxis(100.0); 1464 EXPECT_FALSE(layer_space_to_projection_plane.IsBackFaceVisible()); 1465 1466 // Case 3: Additionally rotating the layer by 180 degrees should of course 1467 // show the opposite result of case 2. 1468 layer_space_to_projection_plane.RotateAboutYAxis(180.0); 1469 EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible()); 1470 } 1471 1472 TEST(XFormTest, verifyDefaultConstructorCreatesIdentityMatrix) { 1473 Transform A; 1474 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A); 1475 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A); 1476 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1477 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1478 EXPECT_TRUE(A.IsIdentity()); 1479 } 1480 1481 TEST(XFormTest, verifyCopyConstructor) { 1482 Transform A; 1483 InitializeTestMatrix(&A); 1484 1485 // Copy constructor should produce exact same elements as matrix A. 1486 Transform B(A); 1487 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B); 1488 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B); 1489 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B); 1490 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B); 1491 } 1492 1493 TEST(XFormTest, verifyConstructorFor16Elements) { 1494 Transform transform(1.0, 2.0, 3.0, 4.0, 1495 5.0, 6.0, 7.0, 8.0, 1496 9.0, 10.0, 11.0, 12.0, 1497 13.0, 14.0, 15.0, 16.0); 1498 1499 EXPECT_ROW1_EQ(1.0f, 2.0f, 3.0f, 4.0f, transform); 1500 EXPECT_ROW2_EQ(5.0f, 6.0f, 7.0f, 8.0f, transform); 1501 EXPECT_ROW3_EQ(9.0f, 10.0f, 11.0f, 12.0f, transform); 1502 EXPECT_ROW4_EQ(13.0f, 14.0f, 15.0f, 16.0f, transform); 1503 } 1504 1505 TEST(XFormTest, verifyConstructorFor2dElements) { 1506 Transform transform(1.0, 2.0, 3.0, 4.0, 5.0, 6.0); 1507 1508 EXPECT_ROW1_EQ(1.0f, 2.0f, 0.0f, 5.0f, transform); 1509 EXPECT_ROW2_EQ(3.0f, 4.0f, 0.0f, 6.0f, transform); 1510 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, transform); 1511 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, transform); 1512 } 1513 1514 1515 TEST(XFormTest, verifyAssignmentOperator) { 1516 Transform A; 1517 InitializeTestMatrix(&A); 1518 Transform B; 1519 InitializeTestMatrix2(&B); 1520 Transform C; 1521 InitializeTestMatrix2(&C); 1522 C = B = A; 1523 1524 // Both B and C should now have been re-assigned to the value of A. 1525 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B); 1526 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B); 1527 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B); 1528 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B); 1529 1530 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, C); 1531 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, C); 1532 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, C); 1533 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, C); 1534 } 1535 1536 TEST(XFormTest, verifyEqualsBooleanOperator) { 1537 Transform A; 1538 InitializeTestMatrix(&A); 1539 1540 Transform B; 1541 InitializeTestMatrix(&B); 1542 EXPECT_TRUE(A == B); 1543 1544 // Modifying multiple elements should cause equals operator to return false. 1545 Transform C; 1546 InitializeTestMatrix2(&C); 1547 EXPECT_FALSE(A == C); 1548 1549 // Modifying any one individual element should cause equals operator to 1550 // return false. 1551 Transform D; 1552 D = A; 1553 D.matrix().set(0, 0, 0.f); 1554 EXPECT_FALSE(A == D); 1555 1556 D = A; 1557 D.matrix().set(1, 0, 0.f); 1558 EXPECT_FALSE(A == D); 1559 1560 D = A; 1561 D.matrix().set(2, 0, 0.f); 1562 EXPECT_FALSE(A == D); 1563 1564 D = A; 1565 D.matrix().set(3, 0, 0.f); 1566 EXPECT_FALSE(A == D); 1567 1568 D = A; 1569 D.matrix().set(0, 1, 0.f); 1570 EXPECT_FALSE(A == D); 1571 1572 D = A; 1573 D.matrix().set(1, 1, 0.f); 1574 EXPECT_FALSE(A == D); 1575 1576 D = A; 1577 D.matrix().set(2, 1, 0.f); 1578 EXPECT_FALSE(A == D); 1579 1580 D = A; 1581 D.matrix().set(3, 1, 0.f); 1582 EXPECT_FALSE(A == D); 1583 1584 D = A; 1585 D.matrix().set(0, 2, 0.f); 1586 EXPECT_FALSE(A == D); 1587 1588 D = A; 1589 D.matrix().set(1, 2, 0.f); 1590 EXPECT_FALSE(A == D); 1591 1592 D = A; 1593 D.matrix().set(2, 2, 0.f); 1594 EXPECT_FALSE(A == D); 1595 1596 D = A; 1597 D.matrix().set(3, 2, 0.f); 1598 EXPECT_FALSE(A == D); 1599 1600 D = A; 1601 D.matrix().set(0, 3, 0.f); 1602 EXPECT_FALSE(A == D); 1603 1604 D = A; 1605 D.matrix().set(1, 3, 0.f); 1606 EXPECT_FALSE(A == D); 1607 1608 D = A; 1609 D.matrix().set(2, 3, 0.f); 1610 EXPECT_FALSE(A == D); 1611 1612 D = A; 1613 D.matrix().set(3, 3, 0.f); 1614 EXPECT_FALSE(A == D); 1615 } 1616 1617 TEST(XFormTest, verifyMultiplyOperator) { 1618 Transform A; 1619 InitializeTestMatrix(&A); 1620 1621 Transform B; 1622 InitializeTestMatrix2(&B); 1623 1624 Transform C = A * B; 1625 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, C); 1626 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, C); 1627 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, C); 1628 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, C); 1629 1630 // Just an additional sanity check; matrix multiplication is not commutative. 1631 EXPECT_FALSE(A * B == B * A); 1632 } 1633 1634 TEST(XFormTest, verifyMultiplyAndAssignOperator) { 1635 Transform A; 1636 InitializeTestMatrix(&A); 1637 1638 Transform B; 1639 InitializeTestMatrix2(&B); 1640 1641 A *= B; 1642 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A); 1643 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A); 1644 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A); 1645 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A); 1646 1647 // Just an additional sanity check; matrix multiplication is not commutative. 1648 Transform C = A; 1649 C *= B; 1650 Transform D = B; 1651 D *= A; 1652 EXPECT_FALSE(C == D); 1653 } 1654 1655 TEST(XFormTest, verifyMatrixMultiplication) { 1656 Transform A; 1657 InitializeTestMatrix(&A); 1658 1659 Transform B; 1660 InitializeTestMatrix2(&B); 1661 1662 A.PreconcatTransform(B); 1663 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A); 1664 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A); 1665 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A); 1666 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A); 1667 } 1668 1669 TEST(XFormTest, verifyMakeIdentiy) { 1670 Transform A; 1671 InitializeTestMatrix(&A); 1672 A.MakeIdentity(); 1673 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A); 1674 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A); 1675 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1676 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1677 EXPECT_TRUE(A.IsIdentity()); 1678 } 1679 1680 TEST(XFormTest, verifyTranslate) { 1681 Transform A; 1682 A.Translate(2.0, 3.0); 1683 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A); 1684 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A); 1685 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1686 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1687 1688 // Verify that Translate() post-multiplies the existing matrix. 1689 A.MakeIdentity(); 1690 A.Scale(5.0, 5.0); 1691 A.Translate(2.0, 3.0); 1692 EXPECT_ROW1_EQ(5.0f, 0.0f, 0.0f, 10.0f, A); 1693 EXPECT_ROW2_EQ(0.0f, 5.0f, 0.0f, 15.0f, A); 1694 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1695 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1696 } 1697 1698 TEST(XFormTest, verifyTranslate3d) { 1699 Transform A; 1700 A.Translate3d(2.0, 3.0, 4.0); 1701 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A); 1702 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A); 1703 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A); 1704 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1705 1706 // Verify that Translate3d() post-multiplies the existing matrix. 1707 A.MakeIdentity(); 1708 A.Scale3d(6.0, 7.0, 8.0); 1709 A.Translate3d(2.0, 3.0, 4.0); 1710 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 12.0f, A); 1711 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 21.0f, A); 1712 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 32.0f, A); 1713 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1714 } 1715 1716 TEST(XFormTest, verifyScale) { 1717 Transform A; 1718 A.Scale(6.0, 7.0); 1719 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A); 1720 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A); 1721 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1722 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1723 1724 // Verify that Scale() post-multiplies the existing matrix. 1725 A.MakeIdentity(); 1726 A.Translate3d(2.0, 3.0, 4.0); 1727 A.Scale(6.0, 7.0); 1728 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A); 1729 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A); 1730 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A); 1731 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1732 } 1733 1734 TEST(XFormTest, verifyScale3d) { 1735 Transform A; 1736 A.Scale3d(6.0, 7.0, 8.0); 1737 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A); 1738 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A); 1739 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A); 1740 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1741 1742 // Verify that scale3d() post-multiplies the existing matrix. 1743 A.MakeIdentity(); 1744 A.Translate3d(2.0, 3.0, 4.0); 1745 A.Scale3d(6.0, 7.0, 8.0); 1746 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A); 1747 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A); 1748 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 4.0f, A); 1749 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1750 } 1751 1752 TEST(XFormTest, verifyRotate) { 1753 Transform A; 1754 A.Rotate(90.0); 1755 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1756 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1757 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1758 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1759 1760 // Verify that Rotate() post-multiplies the existing matrix. 1761 A.MakeIdentity(); 1762 A.Scale3d(6.0, 7.0, 8.0); 1763 A.Rotate(90.0); 1764 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1765 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1766 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A); 1767 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1768 } 1769 1770 TEST(XFormTest, verifyRotateAboutXAxis) { 1771 Transform A; 1772 double sin45 = 0.5 * sqrt(2.0); 1773 double cos45 = sin45; 1774 1775 A.MakeIdentity(); 1776 A.RotateAboutXAxis(90.0); 1777 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A); 1778 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD); 1779 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1780 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1781 1782 A.MakeIdentity(); 1783 A.RotateAboutXAxis(45.0); 1784 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A); 1785 EXPECT_ROW2_NEAR(0.0, cos45, -sin45, 0.0, A, ERROR_THRESHOLD); 1786 EXPECT_ROW3_NEAR(0.0, sin45, cos45, 0.0, A, ERROR_THRESHOLD); 1787 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1788 1789 // Verify that RotateAboutXAxis(angle) post-multiplies the existing matrix. 1790 A.MakeIdentity(); 1791 A.Scale3d(6.0, 7.0, 8.0); 1792 A.RotateAboutXAxis(90.0); 1793 EXPECT_ROW1_NEAR(6.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1794 EXPECT_ROW2_NEAR(0.0, 0.0, -7.0, 0.0, A, ERROR_THRESHOLD); 1795 EXPECT_ROW3_NEAR(0.0, 8.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1796 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1797 } 1798 1799 TEST(XFormTest, verifyRotateAboutYAxis) { 1800 Transform A; 1801 double sin45 = 0.5 * sqrt(2.0); 1802 double cos45 = sin45; 1803 1804 // Note carefully, the expected pattern is inverted compared to rotating 1805 // about x axis or z axis. 1806 A.MakeIdentity(); 1807 A.RotateAboutYAxis(90.0); 1808 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD); 1809 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A); 1810 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1811 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1812 1813 A.MakeIdentity(); 1814 A.RotateAboutYAxis(45.0); 1815 EXPECT_ROW1_NEAR(cos45, 0.0, sin45, 0.0, A, ERROR_THRESHOLD); 1816 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A); 1817 EXPECT_ROW3_NEAR(-sin45, 0.0, cos45, 0.0, A, ERROR_THRESHOLD); 1818 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1819 1820 // Verify that RotateAboutYAxis(angle) post-multiplies the existing matrix. 1821 A.MakeIdentity(); 1822 A.Scale3d(6.0, 7.0, 8.0); 1823 A.RotateAboutYAxis(90.0); 1824 EXPECT_ROW1_NEAR(0.0, 0.0, 6.0, 0.0, A, ERROR_THRESHOLD); 1825 EXPECT_ROW2_NEAR(0.0, 7.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1826 EXPECT_ROW3_NEAR(-8.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1827 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1828 } 1829 1830 TEST(XFormTest, verifyRotateAboutZAxis) { 1831 Transform A; 1832 double sin45 = 0.5 * sqrt(2.0); 1833 double cos45 = sin45; 1834 1835 A.MakeIdentity(); 1836 A.RotateAboutZAxis(90.0); 1837 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1838 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1839 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1840 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1841 1842 A.MakeIdentity(); 1843 A.RotateAboutZAxis(45.0); 1844 EXPECT_ROW1_NEAR(cos45, -sin45, 0.0, 0.0, A, ERROR_THRESHOLD); 1845 EXPECT_ROW2_NEAR(sin45, cos45, 0.0, 0.0, A, ERROR_THRESHOLD); 1846 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1847 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1848 1849 // Verify that RotateAboutZAxis(angle) post-multiplies the existing matrix. 1850 A.MakeIdentity(); 1851 A.Scale3d(6.0, 7.0, 8.0); 1852 A.RotateAboutZAxis(90.0); 1853 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1854 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1855 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A); 1856 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1857 } 1858 1859 TEST(XFormTest, verifyRotateAboutForAlignedAxes) { 1860 Transform A; 1861 1862 // Check rotation about z-axis 1863 A.MakeIdentity(); 1864 A.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0); 1865 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1866 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1867 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1868 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1869 1870 // Check rotation about x-axis 1871 A.MakeIdentity(); 1872 A.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0); 1873 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A); 1874 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD); 1875 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1876 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1877 1878 // Check rotation about y-axis. Note carefully, the expected pattern is 1879 // inverted compared to rotating about x axis or z axis. 1880 A.MakeIdentity(); 1881 A.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0); 1882 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD); 1883 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A); 1884 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1885 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1886 1887 // Verify that rotate3d(axis, angle) post-multiplies the existing matrix. 1888 A.MakeIdentity(); 1889 A.Scale3d(6.0, 7.0, 8.0); 1890 A.RotateAboutZAxis(90.0); 1891 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1892 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1893 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A); 1894 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1895 } 1896 1897 TEST(XFormTest, verifyRotateAboutForArbitraryAxis) { 1898 // Check rotation about an arbitrary non-axis-aligned vector. 1899 Transform A; 1900 A.RotateAbout(Vector3dF(1.0, 1.0, 1.0), 90.0); 1901 EXPECT_ROW1_NEAR(0.3333333333333334258519187, 1902 -0.2440169358562924717404030, 1903 0.9106836025229592124219380, 1904 0.0, A, ERROR_THRESHOLD); 1905 EXPECT_ROW2_NEAR(0.9106836025229592124219380, 1906 0.3333333333333334258519187, 1907 -0.2440169358562924717404030, 1908 0.0, A, ERROR_THRESHOLD); 1909 EXPECT_ROW3_NEAR(-0.2440169358562924717404030, 1910 0.9106836025229592124219380, 1911 0.3333333333333334258519187, 1912 0.0, A, ERROR_THRESHOLD); 1913 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1914 } 1915 1916 TEST(XFormTest, verifyRotateAboutForDegenerateAxis) { 1917 // Check rotation about a degenerate zero vector. 1918 // It is expected to skip applying the rotation. 1919 Transform A; 1920 1921 A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 45.0); 1922 // Verify that A remains unchanged. 1923 EXPECT_TRUE(A.IsIdentity()); 1924 1925 InitializeTestMatrix(&A); 1926 A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 35.0); 1927 1928 // Verify that A remains unchanged. 1929 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, A); 1930 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, A); 1931 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, A); 1932 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, A); 1933 } 1934 1935 TEST(XFormTest, verifySkewX) { 1936 Transform A; 1937 A.SkewX(45.0); 1938 EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, A); 1939 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A); 1940 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1941 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1942 1943 // Verify that skewX() post-multiplies the existing matrix. Row 1, column 2, 1944 // would incorrectly have value "7" if the matrix is pre-multiplied instead 1945 // of post-multiplied. 1946 A.MakeIdentity(); 1947 A.Scale3d(6.0, 7.0, 8.0); 1948 A.SkewX(45.0); 1949 EXPECT_ROW1_EQ(6.0f, 6.0f, 0.0f, 0.0f, A); 1950 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A); 1951 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A); 1952 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1953 } 1954 1955 TEST(XFormTest, verifySkewY) { 1956 Transform A; 1957 A.SkewY(45.0); 1958 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A); 1959 EXPECT_ROW2_EQ(1.0f, 1.0f, 0.0f, 0.0f, A); 1960 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1961 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1962 1963 // Verify that skewY() post-multiplies the existing matrix. Row 2, column 1 , 1964 // would incorrectly have value "6" if the matrix is pre-multiplied instead 1965 // of post-multiplied. 1966 A.MakeIdentity(); 1967 A.Scale3d(6.0, 7.0, 8.0); 1968 A.SkewY(45.0); 1969 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A); 1970 EXPECT_ROW2_EQ(7.0f, 7.0f, 0.0f, 0.0f, A); 1971 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A); 1972 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1973 } 1974 1975 TEST(XFormTest, verifyPerspectiveDepth) { 1976 Transform A; 1977 A.ApplyPerspectiveDepth(1.0); 1978 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A); 1979 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A); 1980 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1981 EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A); 1982 1983 // Verify that PerspectiveDepth() post-multiplies the existing matrix. 1984 A.MakeIdentity(); 1985 A.Translate3d(2.0, 3.0, 4.0); 1986 A.ApplyPerspectiveDepth(1.0); 1987 EXPECT_ROW1_EQ(1.0f, 0.0f, -2.0f, 2.0f, A); 1988 EXPECT_ROW2_EQ(0.0f, 1.0f, -3.0f, 3.0f, A); 1989 EXPECT_ROW3_EQ(0.0f, 0.0f, -3.0f, 4.0f, A); 1990 EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A); 1991 } 1992 1993 TEST(XFormTest, verifyHasPerspective) { 1994 Transform A; 1995 A.ApplyPerspectiveDepth(1.0); 1996 EXPECT_TRUE(A.HasPerspective()); 1997 1998 A.MakeIdentity(); 1999 A.ApplyPerspectiveDepth(0.0); 2000 EXPECT_FALSE(A.HasPerspective()); 2001 2002 A.MakeIdentity(); 2003 A.matrix().set(3, 0, -1.f); 2004 EXPECT_TRUE(A.HasPerspective()); 2005 2006 A.MakeIdentity(); 2007 A.matrix().set(3, 1, -1.f); 2008 EXPECT_TRUE(A.HasPerspective()); 2009 2010 A.MakeIdentity(); 2011 A.matrix().set(3, 2, -0.3f); 2012 EXPECT_TRUE(A.HasPerspective()); 2013 2014 A.MakeIdentity(); 2015 A.matrix().set(3, 3, 0.5f); 2016 EXPECT_TRUE(A.HasPerspective()); 2017 2018 A.MakeIdentity(); 2019 A.matrix().set(3, 3, 0.f); 2020 EXPECT_TRUE(A.HasPerspective()); 2021 } 2022 2023 TEST(XFormTest, verifyIsInvertible) { 2024 Transform A; 2025 2026 // Translations, rotations, scales, skews and arbitrary combinations of them 2027 // are invertible. 2028 A.MakeIdentity(); 2029 EXPECT_TRUE(A.IsInvertible()); 2030 2031 A.MakeIdentity(); 2032 A.Translate3d(2.0, 3.0, 4.0); 2033 EXPECT_TRUE(A.IsInvertible()); 2034 2035 A.MakeIdentity(); 2036 A.Scale3d(6.0, 7.0, 8.0); 2037 EXPECT_TRUE(A.IsInvertible()); 2038 2039 A.MakeIdentity(); 2040 A.RotateAboutXAxis(10.0); 2041 A.RotateAboutYAxis(20.0); 2042 A.RotateAboutZAxis(30.0); 2043 EXPECT_TRUE(A.IsInvertible()); 2044 2045 A.MakeIdentity(); 2046 A.SkewX(45.0); 2047 EXPECT_TRUE(A.IsInvertible()); 2048 2049 // A perspective matrix (projection plane at z=0) is invertible. The 2050 // intuitive explanation is that perspective is eqivalent to a skew of the 2051 // w-axis; skews are invertible. 2052 A.MakeIdentity(); 2053 A.ApplyPerspectiveDepth(1.0); 2054 EXPECT_TRUE(A.IsInvertible()); 2055 2056 // A "pure" perspective matrix derived by similar triangles, with m44() set 2057 // to zero (i.e. camera positioned at the origin), is not invertible. 2058 A.MakeIdentity(); 2059 A.ApplyPerspectiveDepth(1.0); 2060 A.matrix().set(3, 3, 0.f); 2061 EXPECT_FALSE(A.IsInvertible()); 2062 2063 // Adding more to a non-invertible matrix will not make it invertible in the 2064 // general case. 2065 A.MakeIdentity(); 2066 A.ApplyPerspectiveDepth(1.0); 2067 A.matrix().set(3, 3, 0.f); 2068 A.Scale3d(6.0, 7.0, 8.0); 2069 A.RotateAboutXAxis(10.0); 2070 A.RotateAboutYAxis(20.0); 2071 A.RotateAboutZAxis(30.0); 2072 A.Translate3d(6.0, 7.0, 8.0); 2073 EXPECT_FALSE(A.IsInvertible()); 2074 2075 // A degenerate matrix of all zeros is not invertible. 2076 A.MakeIdentity(); 2077 A.matrix().set(0, 0, 0.f); 2078 A.matrix().set(1, 1, 0.f); 2079 A.matrix().set(2, 2, 0.f); 2080 A.matrix().set(3, 3, 0.f); 2081 EXPECT_FALSE(A.IsInvertible()); 2082 } 2083 2084 TEST(XFormTest, verifyIsIdentity) { 2085 Transform A; 2086 2087 InitializeTestMatrix(&A); 2088 EXPECT_FALSE(A.IsIdentity()); 2089 2090 A.MakeIdentity(); 2091 EXPECT_TRUE(A.IsIdentity()); 2092 2093 // Modifying any one individual element should cause the matrix to no longer 2094 // be identity. 2095 A.MakeIdentity(); 2096 A.matrix().set(0, 0, 2.f); 2097 EXPECT_FALSE(A.IsIdentity()); 2098 2099 A.MakeIdentity(); 2100 A.matrix().set(1, 0, 2.f); 2101 EXPECT_FALSE(A.IsIdentity()); 2102 2103 A.MakeIdentity(); 2104 A.matrix().set(2, 0, 2.f); 2105 EXPECT_FALSE(A.IsIdentity()); 2106 2107 A.MakeIdentity(); 2108 A.matrix().set(3, 0, 2.f); 2109 EXPECT_FALSE(A.IsIdentity()); 2110 2111 A.MakeIdentity(); 2112 A.matrix().set(0, 1, 2.f); 2113 EXPECT_FALSE(A.IsIdentity()); 2114 2115 A.MakeIdentity(); 2116 A.matrix().set(1, 1, 2.f); 2117 EXPECT_FALSE(A.IsIdentity()); 2118 2119 A.MakeIdentity(); 2120 A.matrix().set(2, 1, 2.f); 2121 EXPECT_FALSE(A.IsIdentity()); 2122 2123 A.MakeIdentity(); 2124 A.matrix().set(3, 1, 2.f); 2125 EXPECT_FALSE(A.IsIdentity()); 2126 2127 A.MakeIdentity(); 2128 A.matrix().set(0, 2, 2.f); 2129 EXPECT_FALSE(A.IsIdentity()); 2130 2131 A.MakeIdentity(); 2132 A.matrix().set(1, 2, 2.f); 2133 EXPECT_FALSE(A.IsIdentity()); 2134 2135 A.MakeIdentity(); 2136 A.matrix().set(2, 2, 2.f); 2137 EXPECT_FALSE(A.IsIdentity()); 2138 2139 A.MakeIdentity(); 2140 A.matrix().set(3, 2, 2.f); 2141 EXPECT_FALSE(A.IsIdentity()); 2142 2143 A.MakeIdentity(); 2144 A.matrix().set(0, 3, 2.f); 2145 EXPECT_FALSE(A.IsIdentity()); 2146 2147 A.MakeIdentity(); 2148 A.matrix().set(1, 3, 2.f); 2149 EXPECT_FALSE(A.IsIdentity()); 2150 2151 A.MakeIdentity(); 2152 A.matrix().set(2, 3, 2.f); 2153 EXPECT_FALSE(A.IsIdentity()); 2154 2155 A.MakeIdentity(); 2156 A.matrix().set(3, 3, 2.f); 2157 EXPECT_FALSE(A.IsIdentity()); 2158 } 2159 2160 TEST(XFormTest, verifyIsIdentityOrTranslation) { 2161 Transform A; 2162 2163 InitializeTestMatrix(&A); 2164 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2165 2166 A.MakeIdentity(); 2167 EXPECT_TRUE(A.IsIdentityOrTranslation()); 2168 2169 // Modifying any non-translation components should cause 2170 // IsIdentityOrTranslation() to return false. NOTE: (0, 3), (1, 3), and 2171 // (2, 3) are the translation components, so modifying them should still 2172 // return true. 2173 A.MakeIdentity(); 2174 A.matrix().set(0, 0, 2.f); 2175 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2176 2177 A.MakeIdentity(); 2178 A.matrix().set(1, 0, 2.f); 2179 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2180 2181 A.MakeIdentity(); 2182 A.matrix().set(2, 0, 2.f); 2183 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2184 2185 A.MakeIdentity(); 2186 A.matrix().set(3, 0, 2.f); 2187 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2188 2189 A.MakeIdentity(); 2190 A.matrix().set(0, 1, 2.f); 2191 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2192 2193 A.MakeIdentity(); 2194 A.matrix().set(1, 1, 2.f); 2195 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2196 2197 A.MakeIdentity(); 2198 A.matrix().set(2, 1, 2.f); 2199 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2200 2201 A.MakeIdentity(); 2202 A.matrix().set(3, 1, 2.f); 2203 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2204 2205 A.MakeIdentity(); 2206 A.matrix().set(0, 2, 2.f); 2207 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2208 2209 A.MakeIdentity(); 2210 A.matrix().set(1, 2, 2.f); 2211 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2212 2213 A.MakeIdentity(); 2214 A.matrix().set(2, 2, 2.f); 2215 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2216 2217 A.MakeIdentity(); 2218 A.matrix().set(3, 2, 2.f); 2219 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2220 2221 // Note carefully - expecting true here. 2222 A.MakeIdentity(); 2223 A.matrix().set(0, 3, 2.f); 2224 EXPECT_TRUE(A.IsIdentityOrTranslation()); 2225 2226 // Note carefully - expecting true here. 2227 A.MakeIdentity(); 2228 A.matrix().set(1, 3, 2.f); 2229 EXPECT_TRUE(A.IsIdentityOrTranslation()); 2230 2231 // Note carefully - expecting true here. 2232 A.MakeIdentity(); 2233 A.matrix().set(2, 3, 2.f); 2234 EXPECT_TRUE(A.IsIdentityOrTranslation()); 2235 2236 A.MakeIdentity(); 2237 A.matrix().set(3, 3, 2.f); 2238 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2239 } 2240 2241 TEST(XFormTest, verifyIsApproximatelyIdentityOrTranslation) { 2242 Transform A; 2243 SkMatrix44& matrix = A.matrix(); 2244 2245 // Exact pure translation. 2246 A.MakeIdentity(); 2247 2248 // Set translate values to values other than 0 or 1. 2249 matrix.set(0, 3, 3.4f); 2250 matrix.set(1, 3, 4.4f); 2251 matrix.set(2, 3, 5.6f); 2252 2253 EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(0)); 2254 EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero)); 2255 2256 // Approximately pure translation. 2257 InitializeApproxIdentityMatrix(&A); 2258 2259 // Some values must be exact. 2260 matrix.set(3, 0, 0); 2261 matrix.set(3, 1, 0); 2262 matrix.set(3, 2, 0); 2263 matrix.set(3, 3, 1); 2264 2265 // Set translate values to values other than 0 or 1. 2266 matrix.set(0, 3, 3.4f); 2267 matrix.set(1, 3, 4.4f); 2268 matrix.set(2, 3, 5.6f); 2269 2270 EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0)); 2271 EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero)); 2272 2273 // Not approximately pure translation. 2274 InitializeApproxIdentityMatrix(&A); 2275 2276 // Some values must be exact. 2277 matrix.set(3, 0, 0); 2278 matrix.set(3, 1, 0); 2279 matrix.set(3, 2, 0); 2280 matrix.set(3, 3, 1); 2281 2282 // Set some values (not translate values) to values other than 0 or 1. 2283 matrix.set(0, 1, 3.4f); 2284 matrix.set(3, 2, 4.4f); 2285 matrix.set(2, 0, 5.6f); 2286 2287 EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0)); 2288 EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(kApproxZero)); 2289 } 2290 2291 TEST(XFormTest, verifyIsScaleOrTranslation) { 2292 Transform A; 2293 2294 InitializeTestMatrix(&A); 2295 EXPECT_FALSE(A.IsScaleOrTranslation()); 2296 2297 A.MakeIdentity(); 2298 EXPECT_TRUE(A.IsScaleOrTranslation()); 2299 2300 // Modifying any non-scale or non-translation components should cause 2301 // IsScaleOrTranslation() to return false. (0, 0), (1, 1), (2, 2), (0, 3), 2302 // (1, 3), and (2, 3) are the scale and translation components, so 2303 // modifying them should still return true. 2304 2305 // Note carefully - expecting true here. 2306 A.MakeIdentity(); 2307 A.matrix().set(0, 0, 2.f); 2308 EXPECT_TRUE(A.IsScaleOrTranslation()); 2309 2310 A.MakeIdentity(); 2311 A.matrix().set(1, 0, 2.f); 2312 EXPECT_FALSE(A.IsScaleOrTranslation()); 2313 2314 A.MakeIdentity(); 2315 A.matrix().set(2, 0, 2.f); 2316 EXPECT_FALSE(A.IsScaleOrTranslation()); 2317 2318 A.MakeIdentity(); 2319 A.matrix().set(3, 0, 2.f); 2320 EXPECT_FALSE(A.IsScaleOrTranslation()); 2321 2322 A.MakeIdentity(); 2323 A.matrix().set(0, 1, 2.f); 2324 EXPECT_FALSE(A.IsScaleOrTranslation()); 2325 2326 // Note carefully - expecting true here. 2327 A.MakeIdentity(); 2328 A.matrix().set(1, 1, 2.f); 2329 EXPECT_TRUE(A.IsScaleOrTranslation()); 2330 2331 A.MakeIdentity(); 2332 A.matrix().set(2, 1, 2.f); 2333 EXPECT_FALSE(A.IsScaleOrTranslation()); 2334 2335 A.MakeIdentity(); 2336 A.matrix().set(3, 1, 2.f); 2337 EXPECT_FALSE(A.IsScaleOrTranslation()); 2338 2339 A.MakeIdentity(); 2340 A.matrix().set(0, 2, 2.f); 2341 EXPECT_FALSE(A.IsScaleOrTranslation()); 2342 2343 A.MakeIdentity(); 2344 A.matrix().set(1, 2, 2.f); 2345 EXPECT_FALSE(A.IsScaleOrTranslation()); 2346 2347 // Note carefully - expecting true here. 2348 A.MakeIdentity(); 2349 A.matrix().set(2, 2, 2.f); 2350 EXPECT_TRUE(A.IsScaleOrTranslation()); 2351 2352 A.MakeIdentity(); 2353 A.matrix().set(3, 2, 2.f); 2354 EXPECT_FALSE(A.IsScaleOrTranslation()); 2355 2356 // Note carefully - expecting true here. 2357 A.MakeIdentity(); 2358 A.matrix().set(0, 3, 2.f); 2359 EXPECT_TRUE(A.IsScaleOrTranslation()); 2360 2361 // Note carefully - expecting true here. 2362 A.MakeIdentity(); 2363 A.matrix().set(1, 3, 2.f); 2364 EXPECT_TRUE(A.IsScaleOrTranslation()); 2365 2366 // Note carefully - expecting true here. 2367 A.MakeIdentity(); 2368 A.matrix().set(2, 3, 2.f); 2369 EXPECT_TRUE(A.IsScaleOrTranslation()); 2370 2371 A.MakeIdentity(); 2372 A.matrix().set(3, 3, 2.f); 2373 EXPECT_FALSE(A.IsScaleOrTranslation()); 2374 } 2375 2376 TEST(XFormTest, verifyFlattenTo2d) { 2377 Transform A; 2378 InitializeTestMatrix(&A); 2379 2380 A.FlattenTo2d(); 2381 EXPECT_ROW1_EQ(10.0f, 14.0f, 0.0f, 22.0f, A); 2382 EXPECT_ROW2_EQ(11.0f, 15.0f, 0.0f, 23.0f, A); 2383 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 2384 EXPECT_ROW4_EQ(13.0f, 17.0f, 0.0f, 25.0f, A); 2385 } 2386 2387 // Another implementation of Preserves2dAxisAlignment that isn't as fast, 2388 // good for testing the faster implementation. 2389 static bool EmpiricallyPreserves2dAxisAlignment(const Transform& transform) { 2390 Point3F p1(5.0f, 5.0f, 0.0f); 2391 Point3F p2(10.0f, 5.0f, 0.0f); 2392 Point3F p3(10.0f, 20.0f, 0.0f); 2393 Point3F p4(5.0f, 20.0f, 0.0f); 2394 2395 QuadF test_quad(PointF(p1.x(), p1.y()), 2396 PointF(p2.x(), p2.y()), 2397 PointF(p3.x(), p3.y()), 2398 PointF(p4.x(), p4.y())); 2399 EXPECT_TRUE(test_quad.IsRectilinear()); 2400 2401 transform.TransformPoint(&p1); 2402 transform.TransformPoint(&p2); 2403 transform.TransformPoint(&p3); 2404 transform.TransformPoint(&p4); 2405 2406 QuadF transformedQuad(PointF(p1.x(), p1.y()), 2407 PointF(p2.x(), p2.y()), 2408 PointF(p3.x(), p3.y()), 2409 PointF(p4.x(), p4.y())); 2410 return transformedQuad.IsRectilinear(); 2411 } 2412 2413 TEST(XFormTest, Preserves2dAxisAlignment) { 2414 static const struct TestCase { 2415 SkMScalar a; // row 1, column 1 2416 SkMScalar b; // row 1, column 2 2417 SkMScalar c; // row 2, column 1 2418 SkMScalar d; // row 2, column 2 2419 bool expected; 2420 } test_cases[] = { 2421 { 3.f, 0.f, 2422 0.f, 4.f, true }, // basic case 2423 { 0.f, 4.f, 2424 3.f, 0.f, true }, // rotate by 90 2425 { 0.f, 0.f, 2426 0.f, 4.f, true }, // degenerate x 2427 { 3.f, 0.f, 2428 0.f, 0.f, true }, // degenerate y 2429 { 0.f, 0.f, 2430 3.f, 0.f, true }, // degenerate x + rotate by 90 2431 { 0.f, 4.f, 2432 0.f, 0.f, true }, // degenerate y + rotate by 90 2433 { 3.f, 4.f, 2434 0.f, 0.f, false }, 2435 { 0.f, 0.f, 2436 3.f, 4.f, false }, 2437 { 0.f, 3.f, 2438 0.f, 4.f, false }, 2439 { 3.f, 0.f, 2440 4.f, 0.f, false }, 2441 { 3.f, 4.f, 2442 5.f, 0.f, false }, 2443 { 3.f, 4.f, 2444 0.f, 5.f, false }, 2445 { 3.f, 0.f, 2446 4.f, 5.f, false }, 2447 { 0.f, 3.f, 2448 4.f, 5.f, false }, 2449 { 2.f, 3.f, 2450 4.f, 5.f, false }, 2451 }; 2452 2453 Transform transform; 2454 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 2455 const TestCase& value = test_cases[i]; 2456 transform.MakeIdentity(); 2457 transform.matrix().set(0, 0, value.a); 2458 transform.matrix().set(0, 1, value.b); 2459 transform.matrix().set(1, 0, value.c); 2460 transform.matrix().set(1, 1, value.d); 2461 2462 if (value.expected) { 2463 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2464 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2465 } else { 2466 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform)); 2467 EXPECT_FALSE(transform.Preserves2dAxisAlignment()); 2468 } 2469 } 2470 2471 // Try the same test cases again, but this time make sure that other matrix 2472 // elements (except perspective) have entries, to test that they are ignored. 2473 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 2474 const TestCase& value = test_cases[i]; 2475 transform.MakeIdentity(); 2476 transform.matrix().set(0, 0, value.a); 2477 transform.matrix().set(0, 1, value.b); 2478 transform.matrix().set(1, 0, value.c); 2479 transform.matrix().set(1, 1, value.d); 2480 2481 transform.matrix().set(0, 2, 1.f); 2482 transform.matrix().set(0, 3, 2.f); 2483 transform.matrix().set(1, 2, 3.f); 2484 transform.matrix().set(1, 3, 4.f); 2485 transform.matrix().set(2, 0, 5.f); 2486 transform.matrix().set(2, 1, 6.f); 2487 transform.matrix().set(2, 2, 7.f); 2488 transform.matrix().set(2, 3, 8.f); 2489 2490 if (value.expected) { 2491 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2492 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2493 } else { 2494 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform)); 2495 EXPECT_FALSE(transform.Preserves2dAxisAlignment()); 2496 } 2497 } 2498 2499 // Try the same test cases again, but this time add perspective which is 2500 // always assumed to not-preserve axis alignment. 2501 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 2502 const TestCase& value = test_cases[i]; 2503 transform.MakeIdentity(); 2504 transform.matrix().set(0, 0, value.a); 2505 transform.matrix().set(0, 1, value.b); 2506 transform.matrix().set(1, 0, value.c); 2507 transform.matrix().set(1, 1, value.d); 2508 2509 transform.matrix().set(0, 2, 1.f); 2510 transform.matrix().set(0, 3, 2.f); 2511 transform.matrix().set(1, 2, 3.f); 2512 transform.matrix().set(1, 3, 4.f); 2513 transform.matrix().set(2, 0, 5.f); 2514 transform.matrix().set(2, 1, 6.f); 2515 transform.matrix().set(2, 2, 7.f); 2516 transform.matrix().set(2, 3, 8.f); 2517 transform.matrix().set(3, 0, 9.f); 2518 transform.matrix().set(3, 1, 10.f); 2519 transform.matrix().set(3, 2, 11.f); 2520 transform.matrix().set(3, 3, 12.f); 2521 2522 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform)); 2523 EXPECT_FALSE(transform.Preserves2dAxisAlignment()); 2524 } 2525 2526 // Try a few more practical situations to check precision 2527 transform.MakeIdentity(); 2528 transform.RotateAboutZAxis(90.0); 2529 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2530 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2531 2532 transform.MakeIdentity(); 2533 transform.RotateAboutZAxis(180.0); 2534 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2535 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2536 2537 transform.MakeIdentity(); 2538 transform.RotateAboutZAxis(270.0); 2539 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2540 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2541 2542 transform.MakeIdentity(); 2543 transform.RotateAboutYAxis(90.0); 2544 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2545 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2546 2547 transform.MakeIdentity(); 2548 transform.RotateAboutXAxis(90.0); 2549 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2550 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2551 2552 transform.MakeIdentity(); 2553 transform.RotateAboutZAxis(90.0); 2554 transform.RotateAboutYAxis(90.0); 2555 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2556 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2557 2558 transform.MakeIdentity(); 2559 transform.RotateAboutZAxis(90.0); 2560 transform.RotateAboutXAxis(90.0); 2561 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2562 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2563 2564 transform.MakeIdentity(); 2565 transform.RotateAboutYAxis(90.0); 2566 transform.RotateAboutZAxis(90.0); 2567 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2568 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2569 2570 transform.MakeIdentity(); 2571 transform.RotateAboutZAxis(45.0); 2572 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform)); 2573 EXPECT_FALSE(transform.Preserves2dAxisAlignment()); 2574 2575 // 3-d case; In 2d after an orthographic projection, this case does 2576 // preserve 2d axis alignment. But in 3d, it does not preserve axis 2577 // alignment. 2578 transform.MakeIdentity(); 2579 transform.RotateAboutYAxis(45.0); 2580 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2581 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2582 2583 transform.MakeIdentity(); 2584 transform.RotateAboutXAxis(45.0); 2585 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2586 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2587 2588 // Perspective cases. 2589 transform.MakeIdentity(); 2590 transform.ApplyPerspectiveDepth(10.0); 2591 transform.RotateAboutYAxis(45.0); 2592 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform)); 2593 EXPECT_FALSE(transform.Preserves2dAxisAlignment()); 2594 2595 transform.MakeIdentity(); 2596 transform.ApplyPerspectiveDepth(10.0); 2597 transform.RotateAboutZAxis(90.0); 2598 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2599 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2600 } 2601 2602 TEST(XFormTest, To2dTranslation) { 2603 Vector2dF translation(3.f, 7.f); 2604 Transform transform; 2605 transform.Translate(translation.x(), translation.y() + 1); 2606 EXPECT_NE(translation.ToString(), transform.To2dTranslation().ToString()); 2607 transform.MakeIdentity(); 2608 transform.Translate(translation.x(), translation.y()); 2609 EXPECT_EQ(translation.ToString(), transform.To2dTranslation().ToString()); 2610 } 2611 2612 TEST(XFormTest, TransformRect) { 2613 Transform translation; 2614 translation.Translate(3.f, 7.f); 2615 RectF rect(1.f, 2.f, 3.f, 4.f); 2616 RectF expected(4.f, 9.f, 3.f, 4.f); 2617 translation.TransformRect(&rect); 2618 EXPECT_EQ(expected.ToString(), rect.ToString()); 2619 } 2620 2621 TEST(XFormTest, TransformRectReverse) { 2622 Transform translation; 2623 translation.Translate(3.f, 7.f); 2624 RectF rect(1.f, 2.f, 3.f, 4.f); 2625 RectF expected(-2.f, -5.f, 3.f, 4.f); 2626 EXPECT_TRUE(translation.TransformRectReverse(&rect)); 2627 EXPECT_EQ(expected.ToString(), rect.ToString()); 2628 2629 Transform singular; 2630 singular.Scale3d(0.f, 0.f, 0.f); 2631 EXPECT_FALSE(singular.TransformRectReverse(&rect)); 2632 } 2633 2634 TEST(XFormTest, TransformBox) { 2635 Transform translation; 2636 translation.Translate3d(3.f, 7.f, 6.f); 2637 BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f); 2638 BoxF expected(4.f, 9.f, 9.f, 4.f, 5.f, 6.f); 2639 translation.TransformBox(&box); 2640 EXPECT_EQ(expected.ToString(), box.ToString()); 2641 } 2642 2643 TEST(XFormTest, TransformBoxReverse) { 2644 Transform translation; 2645 translation.Translate3d(3.f, 7.f, 6.f); 2646 BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f); 2647 BoxF expected(-2.f, -5.f, -3.f, 4.f, 5.f, 6.f); 2648 EXPECT_TRUE(translation.TransformBoxReverse(&box)); 2649 EXPECT_EQ(expected.ToString(), box.ToString()); 2650 2651 Transform singular; 2652 singular.Scale3d(0.f, 0.f, 0.f); 2653 EXPECT_FALSE(singular.TransformBoxReverse(&box)); 2654 } 2655 2656 } // namespace 2657 2658 } // namespace gfx 2659