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/point.h" 18 #include "ui/gfx/point3_f.h" 19 #include "ui/gfx/quad_f.h" 20 #include "ui/gfx/transform_util.h" 21 #include "ui/gfx/vector3d_f.h" 22 23 namespace gfx { 24 25 namespace { 26 27 #define EXPECT_ROW1_EQ(a, b, c, d, transform) \ 28 EXPECT_FLOAT_EQ((a), (transform).matrix().get(0, 0)); \ 29 EXPECT_FLOAT_EQ((b), (transform).matrix().get(0, 1)); \ 30 EXPECT_FLOAT_EQ((c), (transform).matrix().get(0, 2)); \ 31 EXPECT_FLOAT_EQ((d), (transform).matrix().get(0, 3)); 32 33 #define EXPECT_ROW2_EQ(a, b, c, d, transform) \ 34 EXPECT_FLOAT_EQ((a), (transform).matrix().get(1, 0)); \ 35 EXPECT_FLOAT_EQ((b), (transform).matrix().get(1, 1)); \ 36 EXPECT_FLOAT_EQ((c), (transform).matrix().get(1, 2)); \ 37 EXPECT_FLOAT_EQ((d), (transform).matrix().get(1, 3)); 38 39 #define EXPECT_ROW3_EQ(a, b, c, d, transform) \ 40 EXPECT_FLOAT_EQ((a), (transform).matrix().get(2, 0)); \ 41 EXPECT_FLOAT_EQ((b), (transform).matrix().get(2, 1)); \ 42 EXPECT_FLOAT_EQ((c), (transform).matrix().get(2, 2)); \ 43 EXPECT_FLOAT_EQ((d), (transform).matrix().get(2, 3)); 44 45 #define EXPECT_ROW4_EQ(a, b, c, d, transform) \ 46 EXPECT_FLOAT_EQ((a), (transform).matrix().get(3, 0)); \ 47 EXPECT_FLOAT_EQ((b), (transform).matrix().get(3, 1)); \ 48 EXPECT_FLOAT_EQ((c), (transform).matrix().get(3, 2)); \ 49 EXPECT_FLOAT_EQ((d), (transform).matrix().get(3, 3)); \ 50 51 // Checking float values for equality close to zero is not robust using 52 // EXPECT_FLOAT_EQ (see gtest documentation). So, to verify rotation matrices, 53 // we must use a looser absolute error threshold in some places. 54 #define EXPECT_ROW1_NEAR(a, b, c, d, transform, errorThreshold) \ 55 EXPECT_NEAR((a), (transform).matrix().get(0, 0), (errorThreshold)); \ 56 EXPECT_NEAR((b), (transform).matrix().get(0, 1), (errorThreshold)); \ 57 EXPECT_NEAR((c), (transform).matrix().get(0, 2), (errorThreshold)); \ 58 EXPECT_NEAR((d), (transform).matrix().get(0, 3), (errorThreshold)); 59 60 #define EXPECT_ROW2_NEAR(a, b, c, d, transform, errorThreshold) \ 61 EXPECT_NEAR((a), (transform).matrix().get(1, 0), (errorThreshold)); \ 62 EXPECT_NEAR((b), (transform).matrix().get(1, 1), (errorThreshold)); \ 63 EXPECT_NEAR((c), (transform).matrix().get(1, 2), (errorThreshold)); \ 64 EXPECT_NEAR((d), (transform).matrix().get(1, 3), (errorThreshold)); 65 66 #define EXPECT_ROW3_NEAR(a, b, c, d, transform, errorThreshold) \ 67 EXPECT_NEAR((a), (transform).matrix().get(2, 0), (errorThreshold)); \ 68 EXPECT_NEAR((b), (transform).matrix().get(2, 1), (errorThreshold)); \ 69 EXPECT_NEAR((c), (transform).matrix().get(2, 2), (errorThreshold)); \ 70 EXPECT_NEAR((d), (transform).matrix().get(2, 3), (errorThreshold)); 71 72 bool PointsAreNearlyEqual(const Point3F& lhs, 73 const Point3F& rhs) { 74 float epsilon = 0.0001f; 75 return lhs.SquaredDistanceTo(rhs) < epsilon; 76 } 77 78 bool MatricesAreNearlyEqual(const Transform& lhs, 79 const Transform& rhs) { 80 float epsilon = 0.0001f; 81 for (int row = 0; row < 4; ++row) { 82 for (int col = 0; col < 4; ++col) { 83 if (std::abs(lhs.matrix().get(row, col) - 84 rhs.matrix().get(row, col)) > epsilon) 85 return false; 86 } 87 } 88 return true; 89 } 90 91 void InitializeTestMatrix(Transform* transform) { 92 SkMatrix44& matrix = transform->matrix(); 93 matrix.setDouble(0, 0, 10.0); 94 matrix.setDouble(1, 0, 11.0); 95 matrix.setDouble(2, 0, 12.0); 96 matrix.setDouble(3, 0, 13.0); 97 matrix.setDouble(0, 1, 14.0); 98 matrix.setDouble(1, 1, 15.0); 99 matrix.setDouble(2, 1, 16.0); 100 matrix.setDouble(3, 1, 17.0); 101 matrix.setDouble(0, 2, 18.0); 102 matrix.setDouble(1, 2, 19.0); 103 matrix.setDouble(2, 2, 20.0); 104 matrix.setDouble(3, 2, 21.0); 105 matrix.setDouble(0, 3, 22.0); 106 matrix.setDouble(1, 3, 23.0); 107 matrix.setDouble(2, 3, 24.0); 108 matrix.setDouble(3, 3, 25.0); 109 110 // Sanity check 111 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, (*transform)); 112 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, (*transform)); 113 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, (*transform)); 114 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, (*transform)); 115 } 116 117 void InitializeTestMatrix2(Transform* transform) { 118 SkMatrix44& matrix = transform->matrix(); 119 matrix.setDouble(0, 0, 30.0); 120 matrix.setDouble(1, 0, 31.0); 121 matrix.setDouble(2, 0, 32.0); 122 matrix.setDouble(3, 0, 33.0); 123 matrix.setDouble(0, 1, 34.0); 124 matrix.setDouble(1, 1, 35.0); 125 matrix.setDouble(2, 1, 36.0); 126 matrix.setDouble(3, 1, 37.0); 127 matrix.setDouble(0, 2, 38.0); 128 matrix.setDouble(1, 2, 39.0); 129 matrix.setDouble(2, 2, 40.0); 130 matrix.setDouble(3, 2, 41.0); 131 matrix.setDouble(0, 3, 42.0); 132 matrix.setDouble(1, 3, 43.0); 133 matrix.setDouble(2, 3, 44.0); 134 matrix.setDouble(3, 3, 45.0); 135 136 // Sanity check 137 EXPECT_ROW1_EQ(30.0f, 34.0f, 38.0f, 42.0f, (*transform)); 138 EXPECT_ROW2_EQ(31.0f, 35.0f, 39.0f, 43.0f, (*transform)); 139 EXPECT_ROW3_EQ(32.0f, 36.0f, 40.0f, 44.0f, (*transform)); 140 EXPECT_ROW4_EQ(33.0f, 37.0f, 41.0f, 45.0f, (*transform)); 141 } 142 143 #ifdef SK_MSCALAR_IS_DOUBLE 144 #define ERROR_THRESHOLD 1e-14 145 #else 146 #define ERROR_THRESHOLD 1e-7 147 #endif 148 #define LOOSE_ERROR_THRESHOLD 1e-7 149 150 TEST(XFormTest, Equality) { 151 Transform lhs, rhs, interpolated; 152 rhs.matrix().set3x3(1, 2, 3, 153 4, 5, 6, 154 7, 8, 9); 155 interpolated = lhs; 156 for (int i = 0; i <= 100; ++i) { 157 for (int row = 0; row < 4; ++row) { 158 for (int col = 0; col < 4; ++col) { 159 float a = lhs.matrix().get(row, col); 160 float b = rhs.matrix().get(row, col); 161 float t = i / 100.0f; 162 interpolated.matrix().set(row, col, a + (b - a) * t); 163 } 164 } 165 if (i == 100) { 166 EXPECT_TRUE(rhs == interpolated); 167 } else { 168 EXPECT_TRUE(rhs != interpolated); 169 } 170 } 171 lhs = Transform(); 172 rhs = Transform(); 173 for (int i = 1; i < 100; ++i) { 174 lhs.MakeIdentity(); 175 rhs.MakeIdentity(); 176 lhs.Translate(i, i); 177 rhs.Translate(-i, -i); 178 EXPECT_TRUE(lhs != rhs); 179 rhs.Translate(2*i, 2*i); 180 EXPECT_TRUE(lhs == rhs); 181 } 182 } 183 184 TEST(XFormTest, ConcatTranslate) { 185 static const struct TestCase { 186 int x1; 187 int y1; 188 float tx; 189 float ty; 190 int x2; 191 int y2; 192 } test_cases[] = { 193 { 0, 0, 10.0f, 20.0f, 10, 20 }, 194 { 0, 0, -10.0f, -20.0f, 0, 0 }, 195 { 0, 0, -10.0f, -20.0f, -10, -20 }, 196 { 0, 0, 197 std::numeric_limits<float>::quiet_NaN(), 198 std::numeric_limits<float>::quiet_NaN(), 199 10, 20 }, 200 }; 201 202 Transform xform; 203 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 204 const TestCase& value = test_cases[i]; 205 Transform translation; 206 translation.Translate(value.tx, value.ty); 207 xform = translation * xform; 208 Point3F p1(value.x1, value.y1, 0); 209 Point3F p2(value.x2, value.y2, 0); 210 xform.TransformPoint(p1); 211 if (value.tx == value.tx && 212 value.ty == value.ty) { 213 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2)); 214 } 215 } 216 } 217 218 TEST(XFormTest, ConcatScale) { 219 static const struct TestCase { 220 int before; 221 float scale; 222 int after; 223 } test_cases[] = { 224 { 1, 10.0f, 10 }, 225 { 1, .1f, 1 }, 226 { 1, 100.0f, 100 }, 227 { 1, -1.0f, -100 }, 228 { 1, std::numeric_limits<float>::quiet_NaN(), 1 } 229 }; 230 231 Transform xform; 232 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 233 const TestCase& value = test_cases[i]; 234 Transform scale; 235 scale.Scale(value.scale, value.scale); 236 xform = scale * xform; 237 Point3F p1(value.before, value.before, 0); 238 Point3F p2(value.after, value.after, 0); 239 xform.TransformPoint(p1); 240 if (value.scale == value.scale) { 241 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2)); 242 } 243 } 244 } 245 246 TEST(XFormTest, ConcatRotate) { 247 static const struct TestCase { 248 int x1; 249 int y1; 250 float degrees; 251 int x2; 252 int y2; 253 } test_cases[] = { 254 { 1, 0, 90.0f, 0, 1 }, 255 { 1, 0, -90.0f, 1, 0 }, 256 { 1, 0, 90.0f, 0, 1 }, 257 { 1, 0, 360.0f, 0, 1 }, 258 { 1, 0, 0.0f, 0, 1 }, 259 { 1, 0, std::numeric_limits<float>::quiet_NaN(), 1, 0 } 260 }; 261 262 Transform xform; 263 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 264 const TestCase& value = test_cases[i]; 265 Transform rotation; 266 rotation.Rotate(value.degrees); 267 xform = rotation * xform; 268 Point3F p1(value.x1, value.y1, 0); 269 Point3F p2(value.x2, value.y2, 0); 270 xform.TransformPoint(p1); 271 if (value.degrees == value.degrees) { 272 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2)); 273 } 274 } 275 } 276 277 TEST(XFormTest, SetTranslate) { 278 static const struct TestCase { 279 int x1; int y1; 280 float tx; float ty; 281 int x2; int y2; 282 } test_cases[] = { 283 { 0, 0, 10.0f, 20.0f, 10, 20 }, 284 { 10, 20, 10.0f, 20.0f, 20, 40 }, 285 { 10, 20, 0.0f, 0.0f, 10, 20 }, 286 { 0, 0, 287 std::numeric_limits<float>::quiet_NaN(), 288 std::numeric_limits<float>::quiet_NaN(), 289 0, 0 } 290 }; 291 292 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 293 const TestCase& value = test_cases[i]; 294 for (int k = 0; k < 3; ++k) { 295 Point3F p0, p1, p2; 296 Transform xform; 297 switch (k) { 298 case 0: 299 p1.SetPoint(value.x1, 0, 0); 300 p2.SetPoint(value.x2, 0, 0); 301 xform.Translate(value.tx, 0.0); 302 break; 303 case 1: 304 p1.SetPoint(0, value.y1, 0); 305 p2.SetPoint(0, value.y2, 0); 306 xform.Translate(0.0, value.ty); 307 break; 308 case 2: 309 p1.SetPoint(value.x1, value.y1, 0); 310 p2.SetPoint(value.x2, value.y2, 0); 311 xform.Translate(value.tx, value.ty); 312 break; 313 } 314 p0 = p1; 315 xform.TransformPoint(p1); 316 if (value.tx == value.tx && 317 value.ty == value.ty) { 318 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2)); 319 xform.TransformPointReverse(p1); 320 EXPECT_TRUE(PointsAreNearlyEqual(p1, p0)); 321 } 322 } 323 } 324 } 325 326 TEST(XFormTest, SetScale) { 327 static const struct TestCase { 328 int before; 329 float s; 330 int after; 331 } test_cases[] = { 332 { 1, 10.0f, 10 }, 333 { 1, 1.0f, 1 }, 334 { 1, 0.0f, 0 }, 335 { 0, 10.0f, 0 }, 336 { 1, std::numeric_limits<float>::quiet_NaN(), 0 }, 337 }; 338 339 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 340 const TestCase& value = test_cases[i]; 341 for (int k = 0; k < 3; ++k) { 342 Point3F p0, p1, p2; 343 Transform xform; 344 switch (k) { 345 case 0: 346 p1.SetPoint(value.before, 0, 0); 347 p2.SetPoint(value.after, 0, 0); 348 xform.Scale(value.s, 1.0); 349 break; 350 case 1: 351 p1.SetPoint(0, value.before, 0); 352 p2.SetPoint(0, value.after, 0); 353 xform.Scale(1.0, value.s); 354 break; 355 case 2: 356 p1.SetPoint(value.before, value.before, 0); 357 p2.SetPoint(value.after, value.after, 0); 358 xform.Scale(value.s, value.s); 359 break; 360 } 361 p0 = p1; 362 xform.TransformPoint(p1); 363 if (value.s == value.s) { 364 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2)); 365 if (value.s != 0.0f) { 366 xform.TransformPointReverse(p1); 367 EXPECT_TRUE(PointsAreNearlyEqual(p1, p0)); 368 } 369 } 370 } 371 } 372 } 373 374 TEST(XFormTest, SetRotate) { 375 static const struct SetRotateCase { 376 int x; 377 int y; 378 float degree; 379 int xprime; 380 int yprime; 381 } set_rotate_cases[] = { 382 { 100, 0, 90.0f, 0, 100 }, 383 { 0, 0, 90.0f, 0, 0 }, 384 { 0, 100, 90.0f, -100, 0 }, 385 { 0, 1, -90.0f, 1, 0 }, 386 { 100, 0, 0.0f, 100, 0 }, 387 { 0, 0, 0.0f, 0, 0 }, 388 { 0, 0, std::numeric_limits<float>::quiet_NaN(), 0, 0 }, 389 { 100, 0, 360.0f, 100, 0 } 390 }; 391 392 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(set_rotate_cases); ++i) { 393 const SetRotateCase& value = set_rotate_cases[i]; 394 Point3F p0; 395 Point3F p1(value.x, value.y, 0); 396 Point3F p2(value.xprime, value.yprime, 0); 397 p0 = p1; 398 Transform xform; 399 xform.Rotate(value.degree); 400 // just want to make sure that we don't crash in the case of NaN. 401 if (value.degree == value.degree) { 402 xform.TransformPoint(p1); 403 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2)); 404 xform.TransformPointReverse(p1); 405 EXPECT_TRUE(PointsAreNearlyEqual(p1, p0)); 406 } 407 } 408 } 409 410 // 2D tests 411 TEST(XFormTest, ConcatTranslate2D) { 412 static const struct TestCase { 413 int x1; 414 int y1; 415 float tx; 416 float ty; 417 int x2; 418 int y2; 419 } test_cases[] = { 420 { 0, 0, 10.0f, 20.0f, 10, 20}, 421 { 0, 0, -10.0f, -20.0f, 0, 0}, 422 { 0, 0, -10.0f, -20.0f, -10, -20}, 423 { 0, 0, 424 std::numeric_limits<float>::quiet_NaN(), 425 std::numeric_limits<float>::quiet_NaN(), 426 10, 20}, 427 }; 428 429 Transform xform; 430 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 431 const TestCase& value = test_cases[i]; 432 Transform translation; 433 translation.Translate(value.tx, value.ty); 434 xform = translation * xform; 435 Point p1(value.x1, value.y1); 436 Point p2(value.x2, value.y2); 437 xform.TransformPoint(p1); 438 if (value.tx == value.tx && 439 value.ty == value.ty) { 440 EXPECT_EQ(p1.x(), p2.x()); 441 EXPECT_EQ(p1.y(), p2.y()); 442 } 443 } 444 } 445 446 TEST(XFormTest, ConcatScale2D) { 447 static const struct TestCase { 448 int before; 449 float scale; 450 int after; 451 } test_cases[] = { 452 { 1, 10.0f, 10}, 453 { 1, .1f, 1}, 454 { 1, 100.0f, 100}, 455 { 1, -1.0f, -100}, 456 { 1, std::numeric_limits<float>::quiet_NaN(), 1} 457 }; 458 459 Transform xform; 460 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 461 const TestCase& value = test_cases[i]; 462 Transform scale; 463 scale.Scale(value.scale, value.scale); 464 xform = scale * xform; 465 Point p1(value.before, value.before); 466 Point p2(value.after, value.after); 467 xform.TransformPoint(p1); 468 if (value.scale == value.scale) { 469 EXPECT_EQ(p1.x(), p2.x()); 470 EXPECT_EQ(p1.y(), p2.y()); 471 } 472 } 473 } 474 475 TEST(XFormTest, ConcatRotate2D) { 476 static const struct TestCase { 477 int x1; 478 int y1; 479 float degrees; 480 int x2; 481 int y2; 482 } test_cases[] = { 483 { 1, 0, 90.0f, 0, 1}, 484 { 1, 0, -90.0f, 1, 0}, 485 { 1, 0, 90.0f, 0, 1}, 486 { 1, 0, 360.0f, 0, 1}, 487 { 1, 0, 0.0f, 0, 1}, 488 { 1, 0, std::numeric_limits<float>::quiet_NaN(), 1, 0} 489 }; 490 491 Transform xform; 492 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 493 const TestCase& value = test_cases[i]; 494 Transform rotation; 495 rotation.Rotate(value.degrees); 496 xform = rotation * xform; 497 Point p1(value.x1, value.y1); 498 Point p2(value.x2, value.y2); 499 xform.TransformPoint(p1); 500 if (value.degrees == value.degrees) { 501 EXPECT_EQ(p1.x(), p2.x()); 502 EXPECT_EQ(p1.y(), p2.y()); 503 } 504 } 505 } 506 507 TEST(XFormTest, SetTranslate2D) { 508 static const struct TestCase { 509 int x1; int y1; 510 float tx; float ty; 511 int x2; int y2; 512 } test_cases[] = { 513 { 0, 0, 10.0f, 20.0f, 10, 20}, 514 { 10, 20, 10.0f, 20.0f, 20, 40}, 515 { 10, 20, 0.0f, 0.0f, 10, 20}, 516 { 0, 0, 517 std::numeric_limits<float>::quiet_NaN(), 518 std::numeric_limits<float>::quiet_NaN(), 519 0, 0} 520 }; 521 522 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 523 const TestCase& value = test_cases[i]; 524 for (int j = -1; j < 2; ++j) { 525 for (int k = 0; k < 3; ++k) { 526 float epsilon = 0.0001f; 527 Point p0, p1, p2; 528 Transform xform; 529 switch (k) { 530 case 0: 531 p1.SetPoint(value.x1, 0); 532 p2.SetPoint(value.x2, 0); 533 xform.Translate(value.tx + j * epsilon, 0.0); 534 break; 535 case 1: 536 p1.SetPoint(0, value.y1); 537 p2.SetPoint(0, value.y2); 538 xform.Translate(0.0, value.ty + j * epsilon); 539 break; 540 case 2: 541 p1.SetPoint(value.x1, value.y1); 542 p2.SetPoint(value.x2, value.y2); 543 xform.Translate(value.tx + j * epsilon, 544 value.ty + j * epsilon); 545 break; 546 } 547 p0 = p1; 548 xform.TransformPoint(p1); 549 if (value.tx == value.tx && 550 value.ty == value.ty) { 551 EXPECT_EQ(p1.x(), p2.x()); 552 EXPECT_EQ(p1.y(), p2.y()); 553 xform.TransformPointReverse(p1); 554 EXPECT_EQ(p1.x(), p0.x()); 555 EXPECT_EQ(p1.y(), p0.y()); 556 } 557 } 558 } 559 } 560 } 561 562 TEST(XFormTest, SetScale2D) { 563 static const struct TestCase { 564 int before; 565 float s; 566 int after; 567 } test_cases[] = { 568 { 1, 10.0f, 10}, 569 { 1, 1.0f, 1}, 570 { 1, 0.0f, 0}, 571 { 0, 10.0f, 0}, 572 { 1, std::numeric_limits<float>::quiet_NaN(), 0}, 573 }; 574 575 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 576 const TestCase& value = test_cases[i]; 577 for (int j = -1; j < 2; ++j) { 578 for (int k = 0; k < 3; ++k) { 579 float epsilon = 0.0001f; 580 Point p0, p1, p2; 581 Transform xform; 582 switch (k) { 583 case 0: 584 p1.SetPoint(value.before, 0); 585 p2.SetPoint(value.after, 0); 586 xform.Scale(value.s + j * epsilon, 1.0); 587 break; 588 case 1: 589 p1.SetPoint(0, value.before); 590 p2.SetPoint(0, value.after); 591 xform.Scale(1.0, value.s + j * epsilon); 592 break; 593 case 2: 594 p1.SetPoint(value.before, 595 value.before); 596 p2.SetPoint(value.after, 597 value.after); 598 xform.Scale(value.s + j * epsilon, 599 value.s + j * epsilon); 600 break; 601 } 602 p0 = p1; 603 xform.TransformPoint(p1); 604 if (value.s == value.s) { 605 EXPECT_EQ(p1.x(), p2.x()); 606 EXPECT_EQ(p1.y(), p2.y()); 607 if (value.s != 0.0f) { 608 xform.TransformPointReverse(p1); 609 EXPECT_EQ(p1.x(), p0.x()); 610 EXPECT_EQ(p1.y(), p0.y()); 611 } 612 } 613 } 614 } 615 } 616 } 617 618 TEST(XFormTest, SetRotate2D) { 619 static const struct SetRotateCase { 620 int x; 621 int y; 622 float degree; 623 int xprime; 624 int yprime; 625 } set_rotate_cases[] = { 626 { 100, 0, 90.0f, 0, 100}, 627 { 0, 0, 90.0f, 0, 0}, 628 { 0, 100, 90.0f, -100, 0}, 629 { 0, 1, -90.0f, 1, 0}, 630 { 100, 0, 0.0f, 100, 0}, 631 { 0, 0, 0.0f, 0, 0}, 632 { 0, 0, std::numeric_limits<float>::quiet_NaN(), 0, 0}, 633 { 100, 0, 360.0f, 100, 0} 634 }; 635 636 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(set_rotate_cases); ++i) { 637 const SetRotateCase& value = set_rotate_cases[i]; 638 for (int j = 1; j >= -1; --j) { 639 float epsilon = 0.1f; 640 Point pt(value.x, value.y); 641 Transform xform; 642 // should be invariant to small floating point errors. 643 xform.Rotate(value.degree + j * epsilon); 644 // just want to make sure that we don't crash in the case of NaN. 645 if (value.degree == value.degree) { 646 xform.TransformPoint(pt); 647 EXPECT_EQ(value.xprime, pt.x()); 648 EXPECT_EQ(value.yprime, pt.y()); 649 xform.TransformPointReverse(pt); 650 EXPECT_EQ(pt.x(), value.x); 651 EXPECT_EQ(pt.y(), value.y); 652 } 653 } 654 } 655 } 656 657 TEST(XFormTest, BlendTranslate) { 658 Transform from; 659 for (int i = -5; i < 15; ++i) { 660 Transform to; 661 to.Translate3d(1, 1, 1); 662 double t = i / 9.0; 663 EXPECT_TRUE(to.Blend(from, t)); 664 EXPECT_FLOAT_EQ(t, to.matrix().get(0, 3)); 665 EXPECT_FLOAT_EQ(t, to.matrix().get(1, 3)); 666 EXPECT_FLOAT_EQ(t, to.matrix().get(2, 3)); 667 } 668 } 669 670 TEST(XFormTest, BlendRotate) { 671 Vector3dF axes[] = { 672 Vector3dF(1, 0, 0), 673 Vector3dF(0, 1, 0), 674 Vector3dF(0, 0, 1), 675 Vector3dF(1, 1, 1) 676 }; 677 Transform from; 678 for (size_t index = 0; index < ARRAYSIZE_UNSAFE(axes); ++index) { 679 for (int i = -5; i < 15; ++i) { 680 Transform to; 681 to.RotateAbout(axes[index], 90); 682 double t = i / 9.0; 683 EXPECT_TRUE(to.Blend(from, t)); 684 685 Transform expected; 686 expected.RotateAbout(axes[index], 90 * t); 687 688 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to)); 689 } 690 } 691 } 692 693 TEST(XFormTest, BlendRotateFollowsShortestPath) { 694 // Verify that we interpolate along the shortest path regardless of whether 695 // this path crosses the 180-degree point. 696 Vector3dF axes[] = { 697 Vector3dF(1, 0, 0), 698 Vector3dF(0, 1, 0), 699 Vector3dF(0, 0, 1), 700 Vector3dF(1, 1, 1) 701 }; 702 for (size_t index = 0; index < ARRAYSIZE_UNSAFE(axes); ++index) { 703 for (int i = -5; i < 15; ++i) { 704 Transform from1; 705 from1.RotateAbout(axes[index], 130.0); 706 Transform to1; 707 to1.RotateAbout(axes[index], 175.0); 708 709 Transform from2; 710 from2.RotateAbout(axes[index], 140.0); 711 Transform to2; 712 to2.RotateAbout(axes[index], 185.0); 713 714 double t = i / 9.0; 715 EXPECT_TRUE(to1.Blend(from1, t)); 716 EXPECT_TRUE(to2.Blend(from2, t)); 717 718 Transform expected1; 719 expected1.RotateAbout(axes[index], 130.0 + 45.0 * t); 720 721 Transform expected2; 722 expected2.RotateAbout(axes[index], 140.0 + 45.0 * t); 723 724 EXPECT_TRUE(MatricesAreNearlyEqual(expected1, to1)); 725 EXPECT_TRUE(MatricesAreNearlyEqual(expected2, to2)); 726 } 727 } 728 } 729 730 TEST(XFormTest, CanBlend180DegreeRotation) { 731 Vector3dF axes[] = { 732 Vector3dF(1, 0, 0), 733 Vector3dF(0, 1, 0), 734 Vector3dF(0, 0, 1), 735 Vector3dF(1, 1, 1) 736 }; 737 Transform from; 738 for (size_t index = 0; index < ARRAYSIZE_UNSAFE(axes); ++index) { 739 for (int i = -5; i < 15; ++i) { 740 Transform to; 741 to.RotateAbout(axes[index], 180); 742 double t = i / 9.0; 743 EXPECT_TRUE(to.Blend(from, t)); 744 745 Transform expected; 746 expected.RotateAbout(axes[index], 180 * t); 747 748 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to)); 749 } 750 } 751 } 752 753 TEST(XFormTest, BlendScale) { 754 Transform from; 755 for (int i = -5; i < 15; ++i) { 756 Transform to; 757 to.Scale3d(5, 4, 3); 758 double t = i / 9.0; 759 EXPECT_TRUE(to.Blend(from, t)); 760 EXPECT_FLOAT_EQ(t * 4 + 1, to.matrix().get(0, 0)); 761 EXPECT_FLOAT_EQ(t * 3 + 1, to.matrix().get(1, 1)); 762 EXPECT_FLOAT_EQ(t * 2 + 1, to.matrix().get(2, 2)); 763 } 764 } 765 766 TEST(XFormTest, BlendSkew) { 767 Transform from; 768 for (int i = 0; i < 2; ++i) { 769 Transform to; 770 to.SkewX(20); 771 to.SkewY(10); 772 double t = i; 773 Transform expected; 774 expected.SkewX(t * 20); 775 expected.SkewY(t * 10); 776 EXPECT_TRUE(to.Blend(from, t)); 777 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to)); 778 } 779 } 780 781 TEST(XFormTest, ExtrapolateSkew) { 782 Transform from; 783 for (int i = -1; i < 2; ++i) { 784 Transform to; 785 to.SkewX(20); 786 double t = i; 787 Transform expected; 788 expected.SkewX(t * 20); 789 EXPECT_TRUE(to.Blend(from, t)); 790 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to)); 791 } 792 } 793 794 TEST(XFormTest, BlendPerspective) { 795 Transform from; 796 from.ApplyPerspectiveDepth(200); 797 for (int i = -1; i < 3; ++i) { 798 Transform to; 799 to.ApplyPerspectiveDepth(800); 800 double t = i; 801 double depth = 1.0 / ((1.0 / 200) * (1.0 - t) + (1.0 / 800) * t); 802 Transform expected; 803 expected.ApplyPerspectiveDepth(depth); 804 EXPECT_TRUE(to.Blend(from, t)); 805 EXPECT_TRUE(MatricesAreNearlyEqual(expected, to)); 806 } 807 } 808 809 TEST(XFormTest, BlendIdentity) { 810 Transform from; 811 Transform to; 812 EXPECT_TRUE(to.Blend(from, 0.5)); 813 EXPECT_EQ(to, from); 814 } 815 816 TEST(XFormTest, CannotBlendSingularMatrix) { 817 Transform from; 818 Transform to; 819 to.matrix().set(1, 1, SkDoubleToMScalar(0)); 820 EXPECT_FALSE(to.Blend(from, 0.5)); 821 } 822 823 TEST(XFormTest, VerifyBlendForTranslation) { 824 Transform from; 825 from.Translate3d(100.0, 200.0, 100.0); 826 827 Transform to; 828 829 to.Translate3d(200.0, 100.0, 300.0); 830 to.Blend(from, 0.0); 831 EXPECT_EQ(from, to); 832 833 to = Transform(); 834 to.Translate3d(200.0, 100.0, 300.0); 835 to.Blend(from, 0.25); 836 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 125.0f, to); 837 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 175.0f, to); 838 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 150.0f, to); 839 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 840 841 to = Transform(); 842 to.Translate3d(200.0, 100.0, 300.0); 843 to.Blend(from, 0.5); 844 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 150.0f, to); 845 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 150.0f, to); 846 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 200.0f, to); 847 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 848 849 to = Transform(); 850 to.Translate3d(200.0, 100.0, 300.0); 851 to.Blend(from, 1.0); 852 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 200.0f, to); 853 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 100.0f, to); 854 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 300.0f, to); 855 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 856 } 857 858 TEST(XFormTest, VerifyBlendForScale) { 859 Transform from; 860 from.Scale3d(100.0, 200.0, 100.0); 861 862 Transform to; 863 864 to.Scale3d(200.0, 100.0, 300.0); 865 to.Blend(from, 0.0); 866 EXPECT_EQ(from, to); 867 868 to = Transform(); 869 to.Scale3d(200.0, 100.0, 300.0); 870 to.Blend(from, 0.25); 871 EXPECT_ROW1_EQ(125.0f, 0.0f, 0.0f, 0.0f, to); 872 EXPECT_ROW2_EQ(0.0f, 175.0f, 0.0f, 0.0f, to); 873 EXPECT_ROW3_EQ(0.0f, 0.0f, 150.0f, 0.0f, to); 874 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 875 876 to = Transform(); 877 to.Scale3d(200.0, 100.0, 300.0); 878 to.Blend(from, 0.5); 879 EXPECT_ROW1_EQ(150.0f, 0.0f, 0.0f, 0.0f, to); 880 EXPECT_ROW2_EQ(0.0f, 150.0f, 0.0f, 0.0f, to); 881 EXPECT_ROW3_EQ(0.0f, 0.0f, 200.0f, 0.0f, to); 882 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 883 884 to = Transform(); 885 to.Scale3d(200.0, 100.0, 300.0); 886 to.Blend(from, 1.0); 887 EXPECT_ROW1_EQ(200.0f, 0.0f, 0.0f, 0.0f, to); 888 EXPECT_ROW2_EQ(0.0f, 100.0f, 0.0f, 0.0f, to); 889 EXPECT_ROW3_EQ(0.0f, 0.0f, 300.0f, 0.0f, to); 890 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 891 } 892 893 TEST(XFormTest, VerifyBlendForSkewX) { 894 Transform from; 895 from.SkewX(0.0); 896 897 Transform to; 898 899 to.SkewX(45.0); 900 to.Blend(from, 0.0); 901 EXPECT_EQ(from, to); 902 903 to = Transform(); 904 to.SkewX(45.0); 905 to.Blend(from, 0.5); 906 EXPECT_ROW1_EQ(1.0f, 0.5f, 0.0f, 0.0f, to); 907 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to); 908 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to); 909 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 910 911 to = Transform(); 912 to.SkewX(45.0); 913 to.Blend(from, 0.25); 914 EXPECT_ROW1_EQ(1.0f, 0.25f, 0.0f, 0.0f, to); 915 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to); 916 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to); 917 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 918 919 to = Transform(); 920 to.SkewX(45.0); 921 to.Blend(from, 1.0); 922 EXPECT_ROW1_EQ(1.0f, 1.0f, 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); 926 } 927 928 TEST(XFormTest, VerifyBlendForSkewY) { 929 // NOTE CAREFULLY: Decomposition of skew and rotation terms of the matrix 930 // is inherently underconstrained, and so it does not always compute the 931 // originally intended skew parameters. The current implementation uses QR 932 // decomposition, which decomposes the shear into a rotation + non-uniform 933 // scale. 934 // 935 // It is unlikely that the decomposition implementation will need to change 936 // very often, so to get any test coverage, the compromise is to verify the 937 // exact matrix that the.Blend() operation produces. 938 // 939 // This problem also potentially exists for skewX, but the current QR 940 // decomposition implementation just happens to decompose those test 941 // matrices intuitively. 942 // 943 // Unfortunately, this case suffers from uncomfortably large precision 944 // error. 945 946 Transform from; 947 from.SkewY(0.0); 948 949 Transform to; 950 951 to.SkewY(45.0); 952 to.Blend(from, 0.0); 953 EXPECT_EQ(from, to); 954 955 to = Transform(); 956 to.SkewY(45.0); 957 to.Blend(from, 0.25); 958 EXPECT_ROW1_NEAR(1.0823489449280947471976333, 959 0.0464370719145053845178239, 960 0.0, 961 0.0, 962 to, 963 LOOSE_ERROR_THRESHOLD); 964 EXPECT_ROW2_NEAR(0.2152925909665224513123150, 965 0.9541702441750861130032035, 966 0.0, 967 0.0, 968 to, 969 LOOSE_ERROR_THRESHOLD); 970 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to); 971 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 972 973 to = Transform(); 974 to.SkewY(45.0); 975 to.Blend(from, 0.5); 976 EXPECT_ROW1_NEAR(1.1152212925809066312865525, 977 0.0676495144007326631996335, 978 0.0, 979 0.0, 980 to, 981 LOOSE_ERROR_THRESHOLD); 982 EXPECT_ROW2_NEAR(0.4619397844342648662419037, 983 0.9519009045724774464858342, 984 0.0, 985 0.0, 986 to, 987 LOOSE_ERROR_THRESHOLD); 988 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to); 989 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 990 991 to = Transform(); 992 to.SkewY(45.0); 993 to.Blend(from, 1.0); 994 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD); 995 EXPECT_ROW2_NEAR(1.0, 1.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD); 996 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to); 997 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 998 } 999 1000 TEST(XFormTest, VerifyBlendForRotationAboutX) { 1001 // Even though.Blending uses quaternions, axis-aligned rotations should. 1002 // Blend the same with quaternions or Euler angles. So we can test 1003 // rotation.Blending by comparing against manually specified matrices from 1004 // Euler angles. 1005 1006 Transform from; 1007 from.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 0.0); 1008 1009 Transform to; 1010 1011 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0); 1012 to.Blend(from, 0.0); 1013 EXPECT_EQ(from, to); 1014 1015 double expectedRotationAngle = 22.5 * M_PI / 180.0; 1016 to = Transform(); 1017 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0); 1018 to.Blend(from, 0.25); 1019 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1020 EXPECT_ROW2_NEAR(0.0, 1021 std::cos(expectedRotationAngle), 1022 -std::sin(expectedRotationAngle), 1023 0.0, 1024 to, 1025 ERROR_THRESHOLD); 1026 EXPECT_ROW3_NEAR(0.0, 1027 std::sin(expectedRotationAngle), 1028 std::cos(expectedRotationAngle), 1029 0.0, 1030 to, 1031 ERROR_THRESHOLD); 1032 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1033 1034 expectedRotationAngle = 45.0 * M_PI / 180.0; 1035 to = Transform(); 1036 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0); 1037 to.Blend(from, 0.5); 1038 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1039 EXPECT_ROW2_NEAR(0.0, 1040 std::cos(expectedRotationAngle), 1041 -std::sin(expectedRotationAngle), 1042 0.0, 1043 to, 1044 ERROR_THRESHOLD); 1045 EXPECT_ROW3_NEAR(0.0, 1046 std::sin(expectedRotationAngle), 1047 std::cos(expectedRotationAngle), 1048 0.0, 1049 to, 1050 ERROR_THRESHOLD); 1051 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1052 1053 to = Transform(); 1054 to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0); 1055 to.Blend(from, 1.0); 1056 EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1057 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, to, ERROR_THRESHOLD); 1058 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1059 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1060 } 1061 1062 TEST(XFormTest, VerifyBlendForRotationAboutY) { 1063 Transform from; 1064 from.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 0.0); 1065 1066 Transform to; 1067 1068 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0); 1069 to.Blend(from, 0.0); 1070 EXPECT_EQ(from, to); 1071 1072 double expectedRotationAngle = 22.5 * M_PI / 180.0; 1073 to = Transform(); 1074 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0); 1075 to.Blend(from, 0.25); 1076 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle), 1077 0.0, 1078 std::sin(expectedRotationAngle), 1079 0.0, 1080 to, 1081 ERROR_THRESHOLD); 1082 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1083 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle), 1084 0.0, 1085 std::cos(expectedRotationAngle), 1086 0.0, 1087 to, 1088 ERROR_THRESHOLD); 1089 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1090 1091 expectedRotationAngle = 45.0 * M_PI / 180.0; 1092 to = Transform(); 1093 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0); 1094 to.Blend(from, 0.5); 1095 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle), 1096 0.0, 1097 std::sin(expectedRotationAngle), 1098 0.0, 1099 to, 1100 ERROR_THRESHOLD); 1101 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1102 EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle), 1103 0.0, 1104 std::cos(expectedRotationAngle), 1105 0.0, 1106 to, 1107 ERROR_THRESHOLD); 1108 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1109 1110 to = Transform(); 1111 to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0); 1112 to.Blend(from, 1.0); 1113 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD); 1114 EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1115 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1116 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1117 } 1118 1119 TEST(XFormTest, VerifyBlendForRotationAboutZ) { 1120 Transform from; 1121 from.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 0.0); 1122 1123 Transform to; 1124 1125 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0); 1126 to.Blend(from, 0.0); 1127 EXPECT_EQ(from, to); 1128 1129 double expectedRotationAngle = 22.5 * M_PI / 180.0; 1130 to = Transform(); 1131 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0); 1132 to.Blend(from, 0.25); 1133 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle), 1134 -std::sin(expectedRotationAngle), 1135 0.0, 1136 0.0, 1137 to, 1138 ERROR_THRESHOLD); 1139 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle), 1140 std::cos(expectedRotationAngle), 1141 0.0, 1142 0.0, 1143 to, 1144 ERROR_THRESHOLD); 1145 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD); 1146 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1147 1148 expectedRotationAngle = 45.0 * M_PI / 180.0; 1149 to = Transform(); 1150 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0); 1151 to.Blend(from, 0.5); 1152 EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle), 1153 -std::sin(expectedRotationAngle), 1154 0.0, 1155 0.0, 1156 to, 1157 ERROR_THRESHOLD); 1158 EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle), 1159 std::cos(expectedRotationAngle), 1160 0.0, 1161 0.0, 1162 to, 1163 ERROR_THRESHOLD); 1164 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD); 1165 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1166 1167 to = Transform(); 1168 to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0); 1169 to.Blend(from, 1.0); 1170 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1171 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD); 1172 EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD); 1173 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to); 1174 } 1175 1176 TEST(XFormTest, VerifyBlendForCompositeTransform) { 1177 // Verify that the.Blending was done with a decomposition in correct order 1178 // by blending a composite transform. Using matrix x vector notation 1179 // (Ax = b, where x is column vector), the ordering should be: 1180 // perspective * translation * rotation * skew * scale 1181 // 1182 // It is not as important (or meaningful) to check intermediate 1183 // interpolations; order of operations will be tested well enough by the 1184 // end cases that are easier to specify. 1185 1186 Transform from; 1187 Transform to; 1188 1189 Transform expectedEndOfAnimation; 1190 expectedEndOfAnimation.ApplyPerspectiveDepth(1.0); 1191 expectedEndOfAnimation.Translate3d(10.0, 20.0, 30.0); 1192 expectedEndOfAnimation.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 25.0); 1193 expectedEndOfAnimation.SkewY(45.0); 1194 expectedEndOfAnimation.Scale3d(6.0, 7.0, 8.0); 1195 1196 to = expectedEndOfAnimation; 1197 to.Blend(from, 0.0); 1198 EXPECT_EQ(from, to); 1199 1200 to = expectedEndOfAnimation; 1201 // We short circuit if blend is >= 1, so to check the numerics, we will 1202 // check that we get close to what we expect when we're nearly done 1203 // interpolating. 1204 to.Blend(from, .99999); 1205 1206 // Recomposing the matrix results in a normalized matrix, so to verify we 1207 // need to normalize the expectedEndOfAnimation before comparing elements. 1208 // Normalizing means dividing everything by expectedEndOfAnimation.m44(). 1209 Transform normalizedExpectedEndOfAnimation = expectedEndOfAnimation; 1210 Transform normalizationMatrix; 1211 normalizationMatrix.matrix().set( 1212 0.0, 1213 0.0, 1214 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0))); 1215 normalizationMatrix.matrix().set( 1216 1.0, 1217 1.0, 1218 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0))); 1219 normalizationMatrix.matrix().set( 1220 2.0, 1221 2.0, 1222 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0))); 1223 normalizationMatrix.matrix().set( 1224 3.0, 1225 3.0, 1226 SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0))); 1227 normalizedExpectedEndOfAnimation.PreconcatTransform(normalizationMatrix); 1228 1229 EXPECT_TRUE(MatricesAreNearlyEqual(normalizedExpectedEndOfAnimation, to)); 1230 } 1231 1232 TEST(XFormTest, DecomposedTransformCtor) { 1233 DecomposedTransform decomp; 1234 for (int i = 0; i < 3; ++i) { 1235 EXPECT_EQ(0.0, decomp.translate[i]); 1236 EXPECT_EQ(1.0, decomp.scale[i]); 1237 EXPECT_EQ(0.0, decomp.skew[i]); 1238 EXPECT_EQ(0.0, decomp.quaternion[i]); 1239 EXPECT_EQ(0.0, decomp.perspective[i]); 1240 } 1241 EXPECT_EQ(1.0, decomp.quaternion[3]); 1242 EXPECT_EQ(1.0, decomp.perspective[3]); 1243 Transform identity; 1244 Transform composed = ComposeTransform(decomp); 1245 EXPECT_TRUE(MatricesAreNearlyEqual(identity, composed)); 1246 } 1247 1248 TEST(XFormTest, FactorTRS) { 1249 for (int degrees = 0; degrees < 180; ++degrees) { 1250 // build a transformation matrix. 1251 gfx::Transform transform; 1252 transform.Translate(degrees * 2, -degrees * 3); 1253 transform.Rotate(degrees); 1254 transform.Scale(degrees + 1, 2 * degrees + 1); 1255 1256 // factor the matrix 1257 DecomposedTransform decomp; 1258 bool success = DecomposeTransform(&decomp, transform); 1259 EXPECT_TRUE(success); 1260 EXPECT_FLOAT_EQ(decomp.translate[0], degrees * 2); 1261 EXPECT_FLOAT_EQ(decomp.translate[1], -degrees * 3); 1262 double rotation = std::acos(decomp.quaternion[3]) * 360.0 / M_PI; 1263 while (rotation < 0.0) 1264 rotation += 360.0; 1265 while (rotation > 360.0) 1266 rotation -= 360.0; 1267 EXPECT_FLOAT_EQ(rotation, degrees); 1268 EXPECT_FLOAT_EQ(decomp.scale[0], degrees + 1); 1269 EXPECT_FLOAT_EQ(decomp.scale[1], 2 * degrees + 1); 1270 } 1271 } 1272 1273 TEST(XFormTest, IntegerTranslation) { 1274 gfx::Transform transform; 1275 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation()); 1276 1277 transform.Translate3d(1, 2, 3); 1278 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation()); 1279 1280 transform.MakeIdentity(); 1281 transform.Translate3d(-1, -2, -3); 1282 EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation()); 1283 1284 transform.MakeIdentity(); 1285 transform.Translate3d(4.5, 0, 0); 1286 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation()); 1287 1288 transform.MakeIdentity(); 1289 transform.Translate3d(0, -6.7, 0); 1290 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation()); 1291 1292 transform.MakeIdentity(); 1293 transform.Translate3d(0, 0, 8.9); 1294 EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation()); 1295 } 1296 1297 TEST(XFormTest, verifyMatrixInversion) { 1298 { 1299 // Invert a translation 1300 gfx::Transform translation; 1301 translation.Translate3d(2.0, 3.0, 4.0); 1302 EXPECT_TRUE(translation.IsInvertible()); 1303 1304 gfx::Transform inverse_translation; 1305 bool is_invertible = translation.GetInverse(&inverse_translation); 1306 EXPECT_TRUE(is_invertible); 1307 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, -2.0f, inverse_translation); 1308 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, -3.0f, inverse_translation); 1309 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, -4.0f, inverse_translation); 1310 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_translation); 1311 } 1312 1313 { 1314 // Invert a non-uniform scale 1315 gfx::Transform scale; 1316 scale.Scale3d(4.0, 10.0, 100.0); 1317 EXPECT_TRUE(scale.IsInvertible()); 1318 1319 gfx::Transform inverse_scale; 1320 bool is_invertible = scale.GetInverse(&inverse_scale); 1321 EXPECT_TRUE(is_invertible); 1322 EXPECT_ROW1_EQ(0.25f, 0.0f, 0.0f, 0.0f, inverse_scale); 1323 EXPECT_ROW2_EQ(0.0f, 0.1f, 0.0f, 0.0f, inverse_scale); 1324 EXPECT_ROW3_EQ(0.0f, 0.0f, 0.01f, 0.0f, inverse_scale); 1325 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_scale); 1326 } 1327 1328 { 1329 // Try to invert a matrix that is not invertible. 1330 // The inverse() function should reset the output matrix to identity. 1331 gfx::Transform uninvertible; 1332 uninvertible.matrix().setDouble(0, 0, 0.0); 1333 uninvertible.matrix().setDouble(1, 1, 0.0); 1334 uninvertible.matrix().setDouble(2, 2, 0.0); 1335 uninvertible.matrix().setDouble(3, 3, 0.0); 1336 EXPECT_FALSE(uninvertible.IsInvertible()); 1337 1338 gfx::Transform inverse_of_uninvertible; 1339 1340 // Add a scale just to more easily ensure that inverse_of_uninvertible is 1341 // reset to identity. 1342 inverse_of_uninvertible.Scale3d(4.0, 10.0, 100.0); 1343 1344 bool is_invertible = uninvertible.GetInverse(&inverse_of_uninvertible); 1345 EXPECT_FALSE(is_invertible); 1346 EXPECT_TRUE(inverse_of_uninvertible.IsIdentity()); 1347 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, inverse_of_uninvertible); 1348 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, inverse_of_uninvertible); 1349 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, inverse_of_uninvertible); 1350 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_of_uninvertible); 1351 } 1352 } 1353 1354 TEST(XFormTest, verifyBackfaceVisibilityBasicCases) { 1355 Transform transform; 1356 1357 transform.MakeIdentity(); 1358 EXPECT_FALSE(transform.IsBackFaceVisible()); 1359 1360 transform.MakeIdentity(); 1361 transform.RotateAboutYAxis(80.0); 1362 EXPECT_FALSE(transform.IsBackFaceVisible()); 1363 1364 transform.MakeIdentity(); 1365 transform.RotateAboutYAxis(100.0); 1366 EXPECT_TRUE(transform.IsBackFaceVisible()); 1367 1368 // Edge case, 90 degree rotation should return false. 1369 transform.MakeIdentity(); 1370 transform.RotateAboutYAxis(90.0); 1371 EXPECT_FALSE(transform.IsBackFaceVisible()); 1372 } 1373 1374 TEST(XFormTest, verifyBackfaceVisibilityForPerspective) { 1375 Transform layer_space_to_projection_plane; 1376 1377 // This tests if IsBackFaceVisible works properly under perspective 1378 // transforms. Specifically, layers that may have their back face visible in 1379 // orthographic projection, may not actually have back face visible under 1380 // perspective projection. 1381 1382 // Case 1: Layer is rotated by slightly more than 90 degrees, at the center 1383 // of the prespective projection. In this case, the layer's back-side 1384 // is visible to the camera. 1385 layer_space_to_projection_plane.MakeIdentity(); 1386 layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0); 1387 layer_space_to_projection_plane.Translate3d(0.0, 0.0, 0.0); 1388 layer_space_to_projection_plane.RotateAboutYAxis(100.0); 1389 EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible()); 1390 1391 // Case 2: Layer is rotated by slightly more than 90 degrees, but shifted off 1392 // to the side of the camera. Because of the wide field-of-view, the 1393 // layer's front side is still visible. 1394 // 1395 // |<-- front side of layer is visible to camera 1396 // \ | / 1397 // \ | / 1398 // \| / 1399 // | / 1400 // |\ /<-- camera field of view 1401 // | \ / 1402 // back side of layer -->| \ / 1403 // \./ <-- camera origin 1404 // 1405 layer_space_to_projection_plane.MakeIdentity(); 1406 layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0); 1407 layer_space_to_projection_plane.Translate3d(-10.0, 0.0, 0.0); 1408 layer_space_to_projection_plane.RotateAboutYAxis(100.0); 1409 EXPECT_FALSE(layer_space_to_projection_plane.IsBackFaceVisible()); 1410 1411 // Case 3: Additionally rotating the layer by 180 degrees should of course 1412 // show the opposite result of case 2. 1413 layer_space_to_projection_plane.RotateAboutYAxis(180.0); 1414 EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible()); 1415 } 1416 1417 TEST(XFormTest, verifyDefaultConstructorCreatesIdentityMatrix) { 1418 Transform A; 1419 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A); 1420 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A); 1421 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1422 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1423 EXPECT_TRUE(A.IsIdentity()); 1424 } 1425 1426 TEST(XFormTest, verifyCopyConstructor) { 1427 Transform A; 1428 InitializeTestMatrix(&A); 1429 1430 // Copy constructor should produce exact same elements as matrix A. 1431 Transform B(A); 1432 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B); 1433 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B); 1434 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B); 1435 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B); 1436 } 1437 1438 TEST(XFormTest, verifyConstructorFor16Elements) { 1439 Transform transform(1.0, 2.0, 3.0, 4.0, 1440 5.0, 6.0, 7.0, 8.0, 1441 9.0, 10.0, 11.0, 12.0, 1442 13.0, 14.0, 15.0, 16.0); 1443 1444 EXPECT_ROW1_EQ(1.0f, 2.0f, 3.0f, 4.0f, transform); 1445 EXPECT_ROW2_EQ(5.0f, 6.0f, 7.0f, 8.0f, transform); 1446 EXPECT_ROW3_EQ(9.0f, 10.0f, 11.0f, 12.0f, transform); 1447 EXPECT_ROW4_EQ(13.0f, 14.0f, 15.0f, 16.0f, transform); 1448 } 1449 1450 TEST(XFormTest, verifyConstructorFor2dElements) { 1451 Transform transform(1.0, 2.0, 3.0, 4.0, 5.0, 6.0); 1452 1453 EXPECT_ROW1_EQ(1.0f, 2.0f, 0.0f, 5.0f, transform); 1454 EXPECT_ROW2_EQ(3.0f, 4.0f, 0.0f, 6.0f, transform); 1455 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, transform); 1456 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, transform); 1457 } 1458 1459 1460 TEST(XFormTest, verifyAssignmentOperator) { 1461 Transform A; 1462 InitializeTestMatrix(&A); 1463 Transform B; 1464 InitializeTestMatrix2(&B); 1465 Transform C; 1466 InitializeTestMatrix2(&C); 1467 C = B = A; 1468 1469 // Both B and C should now have been re-assigned to the value of A. 1470 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B); 1471 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B); 1472 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B); 1473 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B); 1474 1475 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, C); 1476 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, C); 1477 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, C); 1478 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, C); 1479 } 1480 1481 TEST(XFormTest, verifyEqualsBooleanOperator) { 1482 Transform A; 1483 InitializeTestMatrix(&A); 1484 1485 Transform B; 1486 InitializeTestMatrix(&B); 1487 EXPECT_TRUE(A == B); 1488 1489 // Modifying multiple elements should cause equals operator to return false. 1490 Transform C; 1491 InitializeTestMatrix2(&C); 1492 EXPECT_FALSE(A == C); 1493 1494 // Modifying any one individual element should cause equals operator to 1495 // return false. 1496 Transform D; 1497 D = A; 1498 D.matrix().setDouble(0, 0, 0.0); 1499 EXPECT_FALSE(A == D); 1500 1501 D = A; 1502 D.matrix().setDouble(1, 0, 0.0); 1503 EXPECT_FALSE(A == D); 1504 1505 D = A; 1506 D.matrix().setDouble(2, 0, 0.0); 1507 EXPECT_FALSE(A == D); 1508 1509 D = A; 1510 D.matrix().setDouble(3, 0, 0.0); 1511 EXPECT_FALSE(A == D); 1512 1513 D = A; 1514 D.matrix().setDouble(0, 1, 0.0); 1515 EXPECT_FALSE(A == D); 1516 1517 D = A; 1518 D.matrix().setDouble(1, 1, 0.0); 1519 EXPECT_FALSE(A == D); 1520 1521 D = A; 1522 D.matrix().setDouble(2, 1, 0.0); 1523 EXPECT_FALSE(A == D); 1524 1525 D = A; 1526 D.matrix().setDouble(3, 1, 0.0); 1527 EXPECT_FALSE(A == D); 1528 1529 D = A; 1530 D.matrix().setDouble(0, 2, 0.0); 1531 EXPECT_FALSE(A == D); 1532 1533 D = A; 1534 D.matrix().setDouble(1, 2, 0.0); 1535 EXPECT_FALSE(A == D); 1536 1537 D = A; 1538 D.matrix().setDouble(2, 2, 0.0); 1539 EXPECT_FALSE(A == D); 1540 1541 D = A; 1542 D.matrix().setDouble(3, 2, 0.0); 1543 EXPECT_FALSE(A == D); 1544 1545 D = A; 1546 D.matrix().setDouble(0, 3, 0.0); 1547 EXPECT_FALSE(A == D); 1548 1549 D = A; 1550 D.matrix().setDouble(1, 3, 0.0); 1551 EXPECT_FALSE(A == D); 1552 1553 D = A; 1554 D.matrix().setDouble(2, 3, 0.0); 1555 EXPECT_FALSE(A == D); 1556 1557 D = A; 1558 D.matrix().setDouble(3, 3, 0.0); 1559 EXPECT_FALSE(A == D); 1560 } 1561 1562 TEST(XFormTest, verifyMultiplyOperator) { 1563 Transform A; 1564 InitializeTestMatrix(&A); 1565 1566 Transform B; 1567 InitializeTestMatrix2(&B); 1568 1569 Transform C = A * B; 1570 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, C); 1571 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, C); 1572 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, C); 1573 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, C); 1574 1575 // Just an additional sanity check; matrix multiplication is not commutative. 1576 EXPECT_FALSE(A * B == B * A); 1577 } 1578 1579 TEST(XFormTest, verifyMultiplyAndAssignOperator) { 1580 Transform A; 1581 InitializeTestMatrix(&A); 1582 1583 Transform B; 1584 InitializeTestMatrix2(&B); 1585 1586 A *= B; 1587 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A); 1588 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A); 1589 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A); 1590 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A); 1591 1592 // Just an additional sanity check; matrix multiplication is not commutative. 1593 Transform C = A; 1594 C *= B; 1595 Transform D = B; 1596 D *= A; 1597 EXPECT_FALSE(C == D); 1598 } 1599 1600 TEST(XFormTest, verifyMatrixMultiplication) { 1601 Transform A; 1602 InitializeTestMatrix(&A); 1603 1604 Transform B; 1605 InitializeTestMatrix2(&B); 1606 1607 A.PreconcatTransform(B); 1608 EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A); 1609 EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A); 1610 EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A); 1611 EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A); 1612 } 1613 1614 TEST(XFormTest, verifyMakeIdentiy) { 1615 Transform A; 1616 InitializeTestMatrix(&A); 1617 A.MakeIdentity(); 1618 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A); 1619 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A); 1620 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1621 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1622 EXPECT_TRUE(A.IsIdentity()); 1623 } 1624 1625 TEST(XFormTest, verifyTranslate) { 1626 Transform A; 1627 A.Translate(2.0, 3.0); 1628 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A); 1629 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A); 1630 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1631 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1632 1633 // Verify that Translate() post-multiplies the existing matrix. 1634 A.MakeIdentity(); 1635 A.Scale(5.0, 5.0); 1636 A.Translate(2.0, 3.0); 1637 EXPECT_ROW1_EQ(5.0f, 0.0f, 0.0f, 10.0f, A); 1638 EXPECT_ROW2_EQ(0.0f, 5.0f, 0.0f, 15.0f, A); 1639 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1640 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1641 } 1642 1643 TEST(XFormTest, verifyTranslate3d) { 1644 Transform A; 1645 A.Translate3d(2.0, 3.0, 4.0); 1646 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A); 1647 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A); 1648 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A); 1649 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1650 1651 // Verify that Translate3d() post-multiplies the existing matrix. 1652 A.MakeIdentity(); 1653 A.Scale3d(6.0, 7.0, 8.0); 1654 A.Translate3d(2.0, 3.0, 4.0); 1655 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 12.0f, A); 1656 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 21.0f, A); 1657 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 32.0f, A); 1658 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1659 } 1660 1661 TEST(XFormTest, verifyScale) { 1662 Transform A; 1663 A.Scale(6.0, 7.0); 1664 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A); 1665 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A); 1666 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1667 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1668 1669 // Verify that Scale() post-multiplies the existing matrix. 1670 A.MakeIdentity(); 1671 A.Translate3d(2.0, 3.0, 4.0); 1672 A.Scale(6.0, 7.0); 1673 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A); 1674 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A); 1675 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A); 1676 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1677 } 1678 1679 TEST(XFormTest, verifyScale3d) { 1680 Transform A; 1681 A.Scale3d(6.0, 7.0, 8.0); 1682 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A); 1683 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A); 1684 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A); 1685 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1686 1687 // Verify that scale3d() post-multiplies the existing matrix. 1688 A.MakeIdentity(); 1689 A.Translate3d(2.0, 3.0, 4.0); 1690 A.Scale3d(6.0, 7.0, 8.0); 1691 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A); 1692 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A); 1693 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 4.0f, A); 1694 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1695 } 1696 1697 TEST(XFormTest, verifyRotate) { 1698 Transform A; 1699 A.Rotate(90.0); 1700 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1701 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1702 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1703 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1704 1705 // Verify that Rotate() post-multiplies the existing matrix. 1706 A.MakeIdentity(); 1707 A.Scale3d(6.0, 7.0, 8.0); 1708 A.Rotate(90.0); 1709 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1710 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1711 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A); 1712 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1713 } 1714 1715 TEST(XFormTest, verifyRotateAboutXAxis) { 1716 Transform A; 1717 double sin45 = 0.5 * sqrt(2.0); 1718 double cos45 = sin45; 1719 1720 A.MakeIdentity(); 1721 A.RotateAboutXAxis(90.0); 1722 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A); 1723 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD); 1724 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1725 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1726 1727 A.MakeIdentity(); 1728 A.RotateAboutXAxis(45.0); 1729 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A); 1730 EXPECT_ROW2_NEAR(0.0, cos45, -sin45, 0.0, A, ERROR_THRESHOLD); 1731 EXPECT_ROW3_NEAR(0.0, sin45, cos45, 0.0, A, ERROR_THRESHOLD); 1732 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1733 1734 // Verify that RotateAboutXAxis(angle) post-multiplies the existing matrix. 1735 A.MakeIdentity(); 1736 A.Scale3d(6.0, 7.0, 8.0); 1737 A.RotateAboutXAxis(90.0); 1738 EXPECT_ROW1_NEAR(6.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1739 EXPECT_ROW2_NEAR(0.0, 0.0, -7.0, 0.0, A, ERROR_THRESHOLD); 1740 EXPECT_ROW3_NEAR(0.0, 8.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1741 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1742 } 1743 1744 TEST(XFormTest, verifyRotateAboutYAxis) { 1745 Transform A; 1746 double sin45 = 0.5 * sqrt(2.0); 1747 double cos45 = sin45; 1748 1749 // Note carefully, the expected pattern is inverted compared to rotating 1750 // about x axis or z axis. 1751 A.MakeIdentity(); 1752 A.RotateAboutYAxis(90.0); 1753 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD); 1754 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A); 1755 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1756 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1757 1758 A.MakeIdentity(); 1759 A.RotateAboutYAxis(45.0); 1760 EXPECT_ROW1_NEAR(cos45, 0.0, sin45, 0.0, A, ERROR_THRESHOLD); 1761 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A); 1762 EXPECT_ROW3_NEAR(-sin45, 0.0, cos45, 0.0, A, ERROR_THRESHOLD); 1763 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1764 1765 // Verify that RotateAboutYAxis(angle) post-multiplies the existing matrix. 1766 A.MakeIdentity(); 1767 A.Scale3d(6.0, 7.0, 8.0); 1768 A.RotateAboutYAxis(90.0); 1769 EXPECT_ROW1_NEAR(0.0, 0.0, 6.0, 0.0, A, ERROR_THRESHOLD); 1770 EXPECT_ROW2_NEAR(0.0, 7.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1771 EXPECT_ROW3_NEAR(-8.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1772 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1773 } 1774 1775 TEST(XFormTest, verifyRotateAboutZAxis) { 1776 Transform A; 1777 double sin45 = 0.5 * sqrt(2.0); 1778 double cos45 = sin45; 1779 1780 A.MakeIdentity(); 1781 A.RotateAboutZAxis(90.0); 1782 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1783 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1784 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1785 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1786 1787 A.MakeIdentity(); 1788 A.RotateAboutZAxis(45.0); 1789 EXPECT_ROW1_NEAR(cos45, -sin45, 0.0, 0.0, A, ERROR_THRESHOLD); 1790 EXPECT_ROW2_NEAR(sin45, cos45, 0.0, 0.0, A, ERROR_THRESHOLD); 1791 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1792 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1793 1794 // Verify that RotateAboutZAxis(angle) post-multiplies the existing matrix. 1795 A.MakeIdentity(); 1796 A.Scale3d(6.0, 7.0, 8.0); 1797 A.RotateAboutZAxis(90.0); 1798 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1799 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1800 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A); 1801 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1802 } 1803 1804 TEST(XFormTest, verifyRotateAboutForAlignedAxes) { 1805 Transform A; 1806 1807 // Check rotation about z-axis 1808 A.MakeIdentity(); 1809 A.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0); 1810 EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1811 EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1812 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1813 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1814 1815 // Check rotation about x-axis 1816 A.MakeIdentity(); 1817 A.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0); 1818 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A); 1819 EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD); 1820 EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1821 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1822 1823 // Check rotation about y-axis. Note carefully, the expected pattern is 1824 // inverted compared to rotating about x axis or z axis. 1825 A.MakeIdentity(); 1826 A.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0); 1827 EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD); 1828 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A); 1829 EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1830 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1831 1832 // Verify that rotate3d(axis, angle) post-multiplies the existing matrix. 1833 A.MakeIdentity(); 1834 A.Scale3d(6.0, 7.0, 8.0); 1835 A.RotateAboutZAxis(90.0); 1836 EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1837 EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD); 1838 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A); 1839 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1840 } 1841 1842 TEST(XFormTest, verifyRotateAboutForArbitraryAxis) { 1843 // Check rotation about an arbitrary non-axis-aligned vector. 1844 Transform A; 1845 A.RotateAbout(Vector3dF(1.0, 1.0, 1.0), 90.0); 1846 EXPECT_ROW1_NEAR(0.3333333333333334258519187, 1847 -0.2440169358562924717404030, 1848 0.9106836025229592124219380, 1849 0.0, A, ERROR_THRESHOLD); 1850 EXPECT_ROW2_NEAR(0.9106836025229592124219380, 1851 0.3333333333333334258519187, 1852 -0.2440169358562924717404030, 1853 0.0, A, ERROR_THRESHOLD); 1854 EXPECT_ROW3_NEAR(-0.2440169358562924717404030, 1855 0.9106836025229592124219380, 1856 0.3333333333333334258519187, 1857 0.0, A, ERROR_THRESHOLD); 1858 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1859 } 1860 1861 TEST(XFormTest, verifyRotateAboutForDegenerateAxis) { 1862 // Check rotation about a degenerate zero vector. 1863 // It is expected to skip applying the rotation. 1864 Transform A; 1865 1866 A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 45.0); 1867 // Verify that A remains unchanged. 1868 EXPECT_TRUE(A.IsIdentity()); 1869 1870 InitializeTestMatrix(&A); 1871 A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 35.0); 1872 1873 // Verify that A remains unchanged. 1874 EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, A); 1875 EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, A); 1876 EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, A); 1877 EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, A); 1878 } 1879 1880 TEST(XFormTest, verifySkewX) { 1881 Transform A; 1882 A.SkewX(45.0); 1883 EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, A); 1884 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A); 1885 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1886 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1887 1888 // Verify that skewX() post-multiplies the existing matrix. Row 1, column 2, 1889 // would incorrectly have value "7" if the matrix is pre-multiplied instead 1890 // of post-multiplied. 1891 A.MakeIdentity(); 1892 A.Scale3d(6.0, 7.0, 8.0); 1893 A.SkewX(45.0); 1894 EXPECT_ROW1_EQ(6.0f, 6.0f, 0.0f, 0.0f, A); 1895 EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A); 1896 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A); 1897 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1898 } 1899 1900 TEST(XFormTest, verifySkewY) { 1901 Transform A; 1902 A.SkewY(45.0); 1903 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A); 1904 EXPECT_ROW2_EQ(1.0f, 1.0f, 0.0f, 0.0f, A); 1905 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1906 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1907 1908 // Verify that skewY() post-multiplies the existing matrix. Row 2, column 1 , 1909 // would incorrectly have value "6" if the matrix is pre-multiplied instead 1910 // of post-multiplied. 1911 A.MakeIdentity(); 1912 A.Scale3d(6.0, 7.0, 8.0); 1913 A.SkewY(45.0); 1914 EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A); 1915 EXPECT_ROW2_EQ(7.0f, 7.0f, 0.0f, 0.0f, A); 1916 EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A); 1917 EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A); 1918 } 1919 1920 TEST(XFormTest, verifyPerspectiveDepth) { 1921 Transform A; 1922 A.ApplyPerspectiveDepth(1.0); 1923 EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A); 1924 EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A); 1925 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 1926 EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A); 1927 1928 // Verify that PerspectiveDepth() post-multiplies the existing matrix. 1929 A.MakeIdentity(); 1930 A.Translate3d(2.0, 3.0, 4.0); 1931 A.ApplyPerspectiveDepth(1.0); 1932 EXPECT_ROW1_EQ(1.0f, 0.0f, -2.0f, 2.0f, A); 1933 EXPECT_ROW2_EQ(0.0f, 1.0f, -3.0f, 3.0f, A); 1934 EXPECT_ROW3_EQ(0.0f, 0.0f, -3.0f, 4.0f, A); 1935 EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A); 1936 } 1937 1938 TEST(XFormTest, verifyHasPerspective) { 1939 Transform A; 1940 A.ApplyPerspectiveDepth(1.0); 1941 EXPECT_TRUE(A.HasPerspective()); 1942 1943 A.MakeIdentity(); 1944 A.ApplyPerspectiveDepth(0.0); 1945 EXPECT_FALSE(A.HasPerspective()); 1946 1947 A.MakeIdentity(); 1948 A.matrix().setDouble(3, 0, -1.0); 1949 EXPECT_TRUE(A.HasPerspective()); 1950 1951 A.MakeIdentity(); 1952 A.matrix().setDouble(3, 1, -1.0); 1953 EXPECT_TRUE(A.HasPerspective()); 1954 1955 A.MakeIdentity(); 1956 A.matrix().setDouble(3, 2, -0.3); 1957 EXPECT_TRUE(A.HasPerspective()); 1958 1959 A.MakeIdentity(); 1960 A.matrix().setDouble(3, 3, 0.5); 1961 EXPECT_TRUE(A.HasPerspective()); 1962 1963 A.MakeIdentity(); 1964 A.matrix().setDouble(3, 3, 0.0); 1965 EXPECT_TRUE(A.HasPerspective()); 1966 } 1967 1968 TEST(XFormTest, verifyIsInvertible) { 1969 Transform A; 1970 1971 // Translations, rotations, scales, skews and arbitrary combinations of them 1972 // are invertible. 1973 A.MakeIdentity(); 1974 EXPECT_TRUE(A.IsInvertible()); 1975 1976 A.MakeIdentity(); 1977 A.Translate3d(2.0, 3.0, 4.0); 1978 EXPECT_TRUE(A.IsInvertible()); 1979 1980 A.MakeIdentity(); 1981 A.Scale3d(6.0, 7.0, 8.0); 1982 EXPECT_TRUE(A.IsInvertible()); 1983 1984 A.MakeIdentity(); 1985 A.RotateAboutXAxis(10.0); 1986 A.RotateAboutYAxis(20.0); 1987 A.RotateAboutZAxis(30.0); 1988 EXPECT_TRUE(A.IsInvertible()); 1989 1990 A.MakeIdentity(); 1991 A.SkewX(45.0); 1992 EXPECT_TRUE(A.IsInvertible()); 1993 1994 // A perspective matrix (projection plane at z=0) is invertible. The 1995 // intuitive explanation is that perspective is eqivalent to a skew of the 1996 // w-axis; skews are invertible. 1997 A.MakeIdentity(); 1998 A.ApplyPerspectiveDepth(1.0); 1999 EXPECT_TRUE(A.IsInvertible()); 2000 2001 // A "pure" perspective matrix derived by similar triangles, with m44() set 2002 // to zero (i.e. camera positioned at the origin), is not invertible. 2003 A.MakeIdentity(); 2004 A.ApplyPerspectiveDepth(1.0); 2005 A.matrix().setDouble(3, 3, 0.0); 2006 EXPECT_FALSE(A.IsInvertible()); 2007 2008 // Adding more to a non-invertible matrix will not make it invertible in the 2009 // general case. 2010 A.MakeIdentity(); 2011 A.ApplyPerspectiveDepth(1.0); 2012 A.matrix().setDouble(3, 3, 0.0); 2013 A.Scale3d(6.0, 7.0, 8.0); 2014 A.RotateAboutXAxis(10.0); 2015 A.RotateAboutYAxis(20.0); 2016 A.RotateAboutZAxis(30.0); 2017 A.Translate3d(6.0, 7.0, 8.0); 2018 EXPECT_FALSE(A.IsInvertible()); 2019 2020 // A degenerate matrix of all zeros is not invertible. 2021 A.MakeIdentity(); 2022 A.matrix().setDouble(0, 0, 0.0); 2023 A.matrix().setDouble(1, 1, 0.0); 2024 A.matrix().setDouble(2, 2, 0.0); 2025 A.matrix().setDouble(3, 3, 0.0); 2026 EXPECT_FALSE(A.IsInvertible()); 2027 } 2028 2029 TEST(XFormTest, verifyIsIdentity) { 2030 Transform A; 2031 2032 InitializeTestMatrix(&A); 2033 EXPECT_FALSE(A.IsIdentity()); 2034 2035 A.MakeIdentity(); 2036 EXPECT_TRUE(A.IsIdentity()); 2037 2038 // Modifying any one individual element should cause the matrix to no longer 2039 // be identity. 2040 A.MakeIdentity(); 2041 A.matrix().setDouble(0, 0, 2.0); 2042 EXPECT_FALSE(A.IsIdentity()); 2043 2044 A.MakeIdentity(); 2045 A.matrix().setDouble(1, 0, 2.0); 2046 EXPECT_FALSE(A.IsIdentity()); 2047 2048 A.MakeIdentity(); 2049 A.matrix().setDouble(2, 0, 2.0); 2050 EXPECT_FALSE(A.IsIdentity()); 2051 2052 A.MakeIdentity(); 2053 A.matrix().setDouble(3, 0, 2.0); 2054 EXPECT_FALSE(A.IsIdentity()); 2055 2056 A.MakeIdentity(); 2057 A.matrix().setDouble(0, 1, 2.0); 2058 EXPECT_FALSE(A.IsIdentity()); 2059 2060 A.MakeIdentity(); 2061 A.matrix().setDouble(1, 1, 2.0); 2062 EXPECT_FALSE(A.IsIdentity()); 2063 2064 A.MakeIdentity(); 2065 A.matrix().setDouble(2, 1, 2.0); 2066 EXPECT_FALSE(A.IsIdentity()); 2067 2068 A.MakeIdentity(); 2069 A.matrix().setDouble(3, 1, 2.0); 2070 EXPECT_FALSE(A.IsIdentity()); 2071 2072 A.MakeIdentity(); 2073 A.matrix().setDouble(0, 2, 2.0); 2074 EXPECT_FALSE(A.IsIdentity()); 2075 2076 A.MakeIdentity(); 2077 A.matrix().setDouble(1, 2, 2.0); 2078 EXPECT_FALSE(A.IsIdentity()); 2079 2080 A.MakeIdentity(); 2081 A.matrix().setDouble(2, 2, 2.0); 2082 EXPECT_FALSE(A.IsIdentity()); 2083 2084 A.MakeIdentity(); 2085 A.matrix().setDouble(3, 2, 2.0); 2086 EXPECT_FALSE(A.IsIdentity()); 2087 2088 A.MakeIdentity(); 2089 A.matrix().setDouble(0, 3, 2.0); 2090 EXPECT_FALSE(A.IsIdentity()); 2091 2092 A.MakeIdentity(); 2093 A.matrix().setDouble(1, 3, 2.0); 2094 EXPECT_FALSE(A.IsIdentity()); 2095 2096 A.MakeIdentity(); 2097 A.matrix().setDouble(2, 3, 2.0); 2098 EXPECT_FALSE(A.IsIdentity()); 2099 2100 A.MakeIdentity(); 2101 A.matrix().setDouble(3, 3, 2.0); 2102 EXPECT_FALSE(A.IsIdentity()); 2103 } 2104 2105 TEST(XFormTest, verifyIsIdentityOrTranslation) { 2106 Transform A; 2107 2108 InitializeTestMatrix(&A); 2109 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2110 2111 A.MakeIdentity(); 2112 EXPECT_TRUE(A.IsIdentityOrTranslation()); 2113 2114 // Modifying any non-translation components should cause 2115 // IsIdentityOrTranslation() to return false. NOTE: (0, 3), (1, 3), and 2116 // (2, 3) are the translation components, so modifying them should still 2117 // return true. 2118 A.MakeIdentity(); 2119 A.matrix().setDouble(0, 0, 2.0); 2120 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2121 2122 A.MakeIdentity(); 2123 A.matrix().setDouble(1, 0, 2.0); 2124 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2125 2126 A.MakeIdentity(); 2127 A.matrix().setDouble(2, 0, 2.0); 2128 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2129 2130 A.MakeIdentity(); 2131 A.matrix().setDouble(3, 0, 2.0); 2132 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2133 2134 A.MakeIdentity(); 2135 A.matrix().setDouble(0, 1, 2.0); 2136 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2137 2138 A.MakeIdentity(); 2139 A.matrix().setDouble(1, 1, 2.0); 2140 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2141 2142 A.MakeIdentity(); 2143 A.matrix().setDouble(2, 1, 2.0); 2144 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2145 2146 A.MakeIdentity(); 2147 A.matrix().setDouble(3, 1, 2.0); 2148 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2149 2150 A.MakeIdentity(); 2151 A.matrix().setDouble(0, 2, 2.0); 2152 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2153 2154 A.MakeIdentity(); 2155 A.matrix().setDouble(1, 2, 2.0); 2156 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2157 2158 A.MakeIdentity(); 2159 A.matrix().setDouble(2, 2, 2.0); 2160 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2161 2162 A.MakeIdentity(); 2163 A.matrix().setDouble(3, 2, 2.0); 2164 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2165 2166 // Note carefully - expecting true here. 2167 A.MakeIdentity(); 2168 A.matrix().setDouble(0, 3, 2.0); 2169 EXPECT_TRUE(A.IsIdentityOrTranslation()); 2170 2171 // Note carefully - expecting true here. 2172 A.MakeIdentity(); 2173 A.matrix().setDouble(1, 3, 2.0); 2174 EXPECT_TRUE(A.IsIdentityOrTranslation()); 2175 2176 // Note carefully - expecting true here. 2177 A.MakeIdentity(); 2178 A.matrix().setDouble(2, 3, 2.0); 2179 EXPECT_TRUE(A.IsIdentityOrTranslation()); 2180 2181 A.MakeIdentity(); 2182 A.matrix().setDouble(3, 3, 2.0); 2183 EXPECT_FALSE(A.IsIdentityOrTranslation()); 2184 } 2185 2186 TEST(XFormTest, verifyIsScaleOrTranslation) { 2187 Transform A; 2188 2189 InitializeTestMatrix(&A); 2190 EXPECT_FALSE(A.IsScaleOrTranslation()); 2191 2192 A.MakeIdentity(); 2193 EXPECT_TRUE(A.IsScaleOrTranslation()); 2194 2195 // Modifying any non-scale or non-translation components should cause 2196 // IsScaleOrTranslation() to return false. (0, 0), (1, 1), (2, 2), (0, 3), 2197 // (1, 3), and (2, 3) are the scale and translation components, so 2198 // modifying them should still return true. 2199 2200 // Note carefully - expecting true here. 2201 A.MakeIdentity(); 2202 A.matrix().setDouble(0, 0, 2.0); 2203 EXPECT_TRUE(A.IsScaleOrTranslation()); 2204 2205 A.MakeIdentity(); 2206 A.matrix().setDouble(1, 0, 2.0); 2207 EXPECT_FALSE(A.IsScaleOrTranslation()); 2208 2209 A.MakeIdentity(); 2210 A.matrix().setDouble(2, 0, 2.0); 2211 EXPECT_FALSE(A.IsScaleOrTranslation()); 2212 2213 A.MakeIdentity(); 2214 A.matrix().setDouble(3, 0, 2.0); 2215 EXPECT_FALSE(A.IsScaleOrTranslation()); 2216 2217 A.MakeIdentity(); 2218 A.matrix().setDouble(0, 1, 2.0); 2219 EXPECT_FALSE(A.IsScaleOrTranslation()); 2220 2221 // Note carefully - expecting true here. 2222 A.MakeIdentity(); 2223 A.matrix().setDouble(1, 1, 2.0); 2224 EXPECT_TRUE(A.IsScaleOrTranslation()); 2225 2226 A.MakeIdentity(); 2227 A.matrix().setDouble(2, 1, 2.0); 2228 EXPECT_FALSE(A.IsScaleOrTranslation()); 2229 2230 A.MakeIdentity(); 2231 A.matrix().setDouble(3, 1, 2.0); 2232 EXPECT_FALSE(A.IsScaleOrTranslation()); 2233 2234 A.MakeIdentity(); 2235 A.matrix().setDouble(0, 2, 2.0); 2236 EXPECT_FALSE(A.IsScaleOrTranslation()); 2237 2238 A.MakeIdentity(); 2239 A.matrix().setDouble(1, 2, 2.0); 2240 EXPECT_FALSE(A.IsScaleOrTranslation()); 2241 2242 // Note carefully - expecting true here. 2243 A.MakeIdentity(); 2244 A.matrix().setDouble(2, 2, 2.0); 2245 EXPECT_TRUE(A.IsScaleOrTranslation()); 2246 2247 A.MakeIdentity(); 2248 A.matrix().setDouble(3, 2, 2.0); 2249 EXPECT_FALSE(A.IsScaleOrTranslation()); 2250 2251 // Note carefully - expecting true here. 2252 A.MakeIdentity(); 2253 A.matrix().setDouble(0, 3, 2.0); 2254 EXPECT_TRUE(A.IsScaleOrTranslation()); 2255 2256 // Note carefully - expecting true here. 2257 A.MakeIdentity(); 2258 A.matrix().setDouble(1, 3, 2.0); 2259 EXPECT_TRUE(A.IsScaleOrTranslation()); 2260 2261 // Note carefully - expecting true here. 2262 A.MakeIdentity(); 2263 A.matrix().setDouble(2, 3, 2.0); 2264 EXPECT_TRUE(A.IsScaleOrTranslation()); 2265 2266 A.MakeIdentity(); 2267 A.matrix().setDouble(3, 3, 2.0); 2268 EXPECT_FALSE(A.IsScaleOrTranslation()); 2269 } 2270 2271 TEST(XFormTest, verifyFlattenTo2d) { 2272 Transform A; 2273 InitializeTestMatrix(&A); 2274 2275 A.FlattenTo2d(); 2276 EXPECT_ROW1_EQ(10.0f, 14.0f, 0.0f, 22.0f, A); 2277 EXPECT_ROW2_EQ(11.0f, 15.0f, 0.0f, 23.0f, A); 2278 EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A); 2279 EXPECT_ROW4_EQ(13.0f, 17.0f, 0.0f, 25.0f, A); 2280 } 2281 2282 // Another implementation of Preserves2dAxisAlignment that isn't as fast, 2283 // good for testing the faster implementation. 2284 static bool EmpiricallyPreserves2dAxisAlignment(const Transform& transform) { 2285 Point3F p1(5.0f, 5.0f, 0.0f); 2286 Point3F p2(10.0f, 5.0f, 0.0f); 2287 Point3F p3(10.0f, 20.0f, 0.0f); 2288 Point3F p4(5.0f, 20.0f, 0.0f); 2289 2290 QuadF test_quad(PointF(p1.x(), p1.y()), 2291 PointF(p2.x(), p2.y()), 2292 PointF(p3.x(), p3.y()), 2293 PointF(p4.x(), p4.y())); 2294 EXPECT_TRUE(test_quad.IsRectilinear()); 2295 2296 transform.TransformPoint(p1); 2297 transform.TransformPoint(p2); 2298 transform.TransformPoint(p3); 2299 transform.TransformPoint(p4); 2300 2301 QuadF transformedQuad(PointF(p1.x(), p1.y()), 2302 PointF(p2.x(), p2.y()), 2303 PointF(p3.x(), p3.y()), 2304 PointF(p4.x(), p4.y())); 2305 return transformedQuad.IsRectilinear(); 2306 } 2307 2308 TEST(XFormTest, Preserves2dAxisAlignment) { 2309 static const struct TestCase { 2310 double a; // row 1, column 1 2311 double b; // row 1, column 2 2312 double c; // row 2, column 1 2313 double d; // row 2, column 2 2314 bool expected; 2315 } test_cases[] = { 2316 { 3.0, 0.0, 2317 0.0, 4.0, true }, // basic case 2318 { 0.0, 4.0, 2319 3.0, 0.0, true }, // rotate by 90 2320 { 0.0, 0.0, 2321 0.0, 4.0, true }, // degenerate x 2322 { 3.0, 0.0, 2323 0.0, 0.0, true }, // degenerate y 2324 { 0.0, 0.0, 2325 3.0, 0.0, true }, // degenerate x + rotate by 90 2326 { 0.0, 4.0, 2327 0.0, 0.0, true }, // degenerate y + rotate by 90 2328 { 3.0, 4.0, 2329 0.0, 0.0, false }, 2330 { 0.0, 0.0, 2331 3.0, 4.0, false }, 2332 { 0.0, 3.0, 2333 0.0, 4.0, false }, 2334 { 3.0, 0.0, 2335 4.0, 0.0, false }, 2336 { 3.0, 4.0, 2337 5.0, 0.0, false }, 2338 { 3.0, 4.0, 2339 0.0, 5.0, false }, 2340 { 3.0, 0.0, 2341 4.0, 5.0, false }, 2342 { 0.0, 3.0, 2343 4.0, 5.0, false }, 2344 { 2.0, 3.0, 2345 4.0, 5.0, false }, 2346 }; 2347 2348 Transform transform; 2349 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 2350 const TestCase& value = test_cases[i]; 2351 transform.MakeIdentity(); 2352 transform.matrix().setDouble(0, 0, value.a); 2353 transform.matrix().setDouble(0, 1, value.b); 2354 transform.matrix().setDouble(1, 0, value.c); 2355 transform.matrix().setDouble(1, 1, value.d); 2356 2357 if (value.expected) { 2358 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2359 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2360 } else { 2361 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform)); 2362 EXPECT_FALSE(transform.Preserves2dAxisAlignment()); 2363 } 2364 } 2365 2366 // Try the same test cases again, but this time make sure that other matrix 2367 // elements (except perspective) have entries, to test that they are ignored. 2368 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 2369 const TestCase& value = test_cases[i]; 2370 transform.MakeIdentity(); 2371 transform.matrix().setDouble(0, 0, value.a); 2372 transform.matrix().setDouble(0, 1, value.b); 2373 transform.matrix().setDouble(1, 0, value.c); 2374 transform.matrix().setDouble(1, 1, value.d); 2375 2376 transform.matrix().setDouble(0, 2, 1.0); 2377 transform.matrix().setDouble(0, 3, 2.0); 2378 transform.matrix().setDouble(1, 2, 3.0); 2379 transform.matrix().setDouble(1, 3, 4.0); 2380 transform.matrix().setDouble(2, 0, 5.0); 2381 transform.matrix().setDouble(2, 1, 6.0); 2382 transform.matrix().setDouble(2, 2, 7.0); 2383 transform.matrix().setDouble(2, 3, 8.0); 2384 2385 if (value.expected) { 2386 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2387 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2388 } else { 2389 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform)); 2390 EXPECT_FALSE(transform.Preserves2dAxisAlignment()); 2391 } 2392 } 2393 2394 // Try the same test cases again, but this time add perspective which is 2395 // always assumed to not-preserve axis alignment. 2396 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 2397 const TestCase& value = test_cases[i]; 2398 transform.MakeIdentity(); 2399 transform.matrix().setDouble(0, 0, value.a); 2400 transform.matrix().setDouble(0, 1, value.b); 2401 transform.matrix().setDouble(1, 0, value.c); 2402 transform.matrix().setDouble(1, 1, value.d); 2403 2404 transform.matrix().setDouble(0, 2, 1.0); 2405 transform.matrix().setDouble(0, 3, 2.0); 2406 transform.matrix().setDouble(1, 2, 3.0); 2407 transform.matrix().setDouble(1, 3, 4.0); 2408 transform.matrix().setDouble(2, 0, 5.0); 2409 transform.matrix().setDouble(2, 1, 6.0); 2410 transform.matrix().setDouble(2, 2, 7.0); 2411 transform.matrix().setDouble(2, 3, 8.0); 2412 transform.matrix().setDouble(3, 0, 9.0); 2413 transform.matrix().setDouble(3, 1, 10.0); 2414 transform.matrix().setDouble(3, 2, 11.0); 2415 transform.matrix().setDouble(3, 3, 12.0); 2416 2417 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform)); 2418 EXPECT_FALSE(transform.Preserves2dAxisAlignment()); 2419 } 2420 2421 // Try a few more practical situations to check precision 2422 transform.MakeIdentity(); 2423 transform.RotateAboutZAxis(90.0); 2424 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2425 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2426 2427 transform.MakeIdentity(); 2428 transform.RotateAboutZAxis(180.0); 2429 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2430 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2431 2432 transform.MakeIdentity(); 2433 transform.RotateAboutZAxis(270.0); 2434 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2435 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2436 2437 transform.MakeIdentity(); 2438 transform.RotateAboutYAxis(90.0); 2439 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2440 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2441 2442 transform.MakeIdentity(); 2443 transform.RotateAboutXAxis(90.0); 2444 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2445 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2446 2447 transform.MakeIdentity(); 2448 transform.RotateAboutZAxis(90.0); 2449 transform.RotateAboutYAxis(90.0); 2450 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2451 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2452 2453 transform.MakeIdentity(); 2454 transform.RotateAboutZAxis(90.0); 2455 transform.RotateAboutXAxis(90.0); 2456 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2457 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2458 2459 transform.MakeIdentity(); 2460 transform.RotateAboutYAxis(90.0); 2461 transform.RotateAboutZAxis(90.0); 2462 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2463 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2464 2465 transform.MakeIdentity(); 2466 transform.RotateAboutZAxis(45.0); 2467 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform)); 2468 EXPECT_FALSE(transform.Preserves2dAxisAlignment()); 2469 2470 // 3-d case; In 2d after an orthographic projection, this case does 2471 // preserve 2d axis alignment. But in 3d, it does not preserve axis 2472 // alignment. 2473 transform.MakeIdentity(); 2474 transform.RotateAboutYAxis(45.0); 2475 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2476 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2477 2478 transform.MakeIdentity(); 2479 transform.RotateAboutXAxis(45.0); 2480 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2481 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2482 2483 // Perspective cases. 2484 transform.MakeIdentity(); 2485 transform.ApplyPerspectiveDepth(10.0); 2486 transform.RotateAboutYAxis(45.0); 2487 EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform)); 2488 EXPECT_FALSE(transform.Preserves2dAxisAlignment()); 2489 2490 transform.MakeIdentity(); 2491 transform.ApplyPerspectiveDepth(10.0); 2492 transform.RotateAboutZAxis(90.0); 2493 EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); 2494 EXPECT_TRUE(transform.Preserves2dAxisAlignment()); 2495 } 2496 2497 } // namespace 2498 2499 } // namespace gfx 2500