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