OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2006-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 #include "base/basictypes.h" |
| 6 #include "testing/gtest/include/gtest/gtest.h" |
| 7 #include "third_party/eigen/Eigen/Geometry" |
| 8 #include "ui/gfx/transform.h" |
| 9 #include "ui/gfx/point3.h" |
| 10 #include <iostream> |
| 11 #include <limits> |
| 12 |
| 13 typedef testing::Test XFormTest; |
| 14 |
| 15 namespace { |
| 16 bool PointsAreNearlyEqual(const gfx::Point3f& lhs, |
| 17 const gfx::Point3f& rhs) { |
| 18 float epsilon = 0.0001f; |
| 19 return lhs.Dist2(rhs) < epsilon; |
| 20 } |
| 21 } |
| 22 |
| 23 #ifdef NDEBUG |
| 24 TEST(XFormTest, MatrixMultStressTest) { |
| 25 ui::Transform xform; |
| 26 for (int i = 0; i < 1000000; ++i) { |
| 27 xform.ConcatRotate(3.0f); |
| 28 xform.ConcatScale(2.0f, 2.0f); |
| 29 xform.ConcatTranslate(1.0f, 2.0f); |
| 30 xform.ConcatScale(0.5f, 0.5f); |
| 31 } |
| 32 } |
| 33 #endif |
| 34 |
| 35 TEST(XFormTest, ConcatTranslate) { |
| 36 static const struct TestCase { |
| 37 int x1; |
| 38 int y1; |
| 39 float tx; |
| 40 float ty; |
| 41 int x2; |
| 42 int y2; |
| 43 } test_cases[] = { |
| 44 { 0, 0, 10.0f, 20.0f, 10, 20 }, |
| 45 { 0, 0, -10.0f, -20.0f, 0, 0 }, |
| 46 { 0, 0, -10.0f, -20.0f, -10, -20 }, |
| 47 { 0, 0, |
| 48 std::numeric_limits<float>::quiet_NaN(), |
| 49 std::numeric_limits<float>::quiet_NaN(), |
| 50 10, 20 }, |
| 51 }; |
| 52 |
| 53 ui::Transform xform; |
| 54 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { |
| 55 const TestCase& value = test_cases[i]; |
| 56 xform.ConcatTranslate(value.tx, value.ty); |
| 57 gfx::Point3f p1(value.x1, value.y1, 0); |
| 58 gfx::Point3f p2(value.x2, value.y2, 0); |
| 59 xform.TransformPoint(p1); |
| 60 if (value.tx == value.tx && |
| 61 value.ty == value.ty) { |
| 62 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2)); |
| 63 } |
| 64 } |
| 65 } |
| 66 |
| 67 TEST(XFormTest, ConcatScale) { |
| 68 static const struct TestCase { |
| 69 int before; |
| 70 float scale; |
| 71 int after; |
| 72 } test_cases[] = { |
| 73 { 1, 10.0f, 10 }, |
| 74 { 1, .1f, 1 }, |
| 75 { 1, 100.0f, 100 }, |
| 76 { 1, -1.0f, -100 }, |
| 77 { 1, std::numeric_limits<float>::quiet_NaN(), 1 } |
| 78 }; |
| 79 |
| 80 ui::Transform xform; |
| 81 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { |
| 82 const TestCase& value = test_cases[i]; |
| 83 xform.ConcatScale(value.scale, value.scale); |
| 84 gfx::Point3f p1(value.before, value.before, 0); |
| 85 gfx::Point3f p2(value.after, value.after, 0); |
| 86 xform.TransformPoint(p1); |
| 87 if (value.scale == value.scale) { |
| 88 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2)); |
| 89 } |
| 90 } |
| 91 } |
| 92 |
| 93 TEST(XFormTest, ConcatRotate) { |
| 94 static const struct TestCase { |
| 95 int x1; |
| 96 int y1; |
| 97 float degrees; |
| 98 int x2; |
| 99 int y2; |
| 100 } test_cases[] = { |
| 101 { 1, 0, 90.0f, 0, 1 }, |
| 102 { 1, 0, -90.0f, 1, 0 }, |
| 103 { 1, 0, 90.0f, 0, 1 }, |
| 104 { 1, 0, 360.0f, 0, 1 }, |
| 105 { 1, 0, 0.0f, 0, 1 }, |
| 106 { 1, 0, std::numeric_limits<float>::quiet_NaN(), 1, 0 } |
| 107 }; |
| 108 |
| 109 ui::Transform xform; |
| 110 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { |
| 111 const TestCase& value = test_cases[i]; |
| 112 xform.ConcatRotate(value.degrees); |
| 113 gfx::Point3f p1(value.x1, value.y1, 0); |
| 114 gfx::Point3f p2(value.x2, value.y2, 0); |
| 115 xform.TransformPoint(p1); |
| 116 if (value.degrees == value.degrees) { |
| 117 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2)); |
| 118 } |
| 119 } |
| 120 } |
| 121 |
| 122 TEST(XFormTest, SetTranslate) { |
| 123 static const struct TestCase { |
| 124 int x1; int y1; |
| 125 float tx; float ty; |
| 126 int x2; int y2; |
| 127 } test_cases[] = { |
| 128 { 0, 0, 10.0f, 20.0f, 10, 20 }, |
| 129 { 10, 20, 10.0f, 20.0f, 20, 40 }, |
| 130 { 10, 20, 0.0f, 0.0f, 10, 20 }, |
| 131 { 0, 0, |
| 132 std::numeric_limits<float>::quiet_NaN(), |
| 133 std::numeric_limits<float>::quiet_NaN(), |
| 134 0, 0 } |
| 135 }; |
| 136 |
| 137 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { |
| 138 const TestCase& value = test_cases[i]; |
| 139 for (int k = 0; k < 3; ++k) { |
| 140 gfx::Point3f p0, p1, p2; |
| 141 ui::Transform xform; |
| 142 switch (k) { |
| 143 case 0: |
| 144 p1.SetPoint(value.x1, 0, 0); |
| 145 p2.SetPoint(value.x2, 0, 0); |
| 146 xform.SetTranslateX(value.tx); |
| 147 break; |
| 148 case 1: |
| 149 p1.SetPoint(0, value.y1, 0); |
| 150 p2.SetPoint(0, value.y2, 0); |
| 151 xform.SetTranslateY(value.ty); |
| 152 break; |
| 153 case 2: |
| 154 p1.SetPoint(value.x1, value.y1, 0); |
| 155 p2.SetPoint(value.x2, value.y2, 0); |
| 156 xform.SetTranslate(value.tx, value.ty); |
| 157 break; |
| 158 } |
| 159 p0.SetPoint(p1); |
| 160 xform.TransformPoint(p1); |
| 161 if (value.tx == value.tx && |
| 162 value.ty == value.ty) { |
| 163 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2)); |
| 164 xform.TransformPointReverse(p1); |
| 165 EXPECT_TRUE(PointsAreNearlyEqual(p1, p0)); |
| 166 } |
| 167 } |
| 168 } |
| 169 } |
| 170 |
| 171 TEST(XFormTest, SetScale) { |
| 172 static const struct TestCase { |
| 173 int before; |
| 174 float s; |
| 175 int after; |
| 176 } test_cases[] = { |
| 177 { 1, 10.0f, 10 }, |
| 178 { 1, 1.0f, 1 }, |
| 179 { 1, 0.0f, 0 }, |
| 180 { 0, 10.0f, 0 }, |
| 181 { 1, std::numeric_limits<float>::quiet_NaN(), 0 }, |
| 182 }; |
| 183 |
| 184 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { |
| 185 const TestCase& value = test_cases[i]; |
| 186 for (int k = 0; k < 3; ++k) { |
| 187 gfx::Point3f p0, p1, p2; |
| 188 ui::Transform xform; |
| 189 switch (k) { |
| 190 case 0: |
| 191 p1.SetPoint(value.before, 0, 0); |
| 192 p2.SetPoint(value.after, 0, 0); |
| 193 xform.SetScaleX(value.s); |
| 194 break; |
| 195 case 1: |
| 196 p1.SetPoint(0, value.before, 0); |
| 197 p2.SetPoint(0, value.after, 0); |
| 198 xform.SetScaleY(value.s); |
| 199 break; |
| 200 case 2: |
| 201 p1.SetPoint(value.before, value.before, 0); |
| 202 p2.SetPoint(value.after, value.after, 0); |
| 203 xform.SetScale(value.s, value.s); |
| 204 break; |
| 205 } |
| 206 p0.SetPoint(p1); |
| 207 xform.TransformPoint(p1); |
| 208 if (value.s == value.s) { |
| 209 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2)); |
| 210 if (value.s != 0.0f) { |
| 211 xform.TransformPointReverse(p1); |
| 212 EXPECT_TRUE(PointsAreNearlyEqual(p1, p0)); |
| 213 } |
| 214 } |
| 215 } |
| 216 } |
| 217 } |
| 218 |
| 219 TEST(XFormTest, SetRotate) { |
| 220 static const struct SetRotateCase { |
| 221 int x; |
| 222 int y; |
| 223 float degree; |
| 224 int xprime; |
| 225 int yprime; |
| 226 } set_rotate_cases[] = { |
| 227 { 100, 0, 90.0f, 0, 100 }, |
| 228 { 0, 0, 90.0f, 0, 0 }, |
| 229 { 0, 100, 90.0f, -100, 0 }, |
| 230 { 0, 1, -90.0f, 1, 0 }, |
| 231 { 100, 0, 0.0f, 100, 0 }, |
| 232 { 0, 0, 0.0f, 0, 0 }, |
| 233 { 0, 0, std::numeric_limits<float>::quiet_NaN(), 0, 0 }, |
| 234 { 100, 0, 360.0f, 100, 0 } |
| 235 }; |
| 236 |
| 237 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(set_rotate_cases); ++i) { |
| 238 const SetRotateCase& value = set_rotate_cases[i]; |
| 239 gfx::Point3f p0; |
| 240 gfx::Point3f p1(value.x, value.y, 0); |
| 241 gfx::Point3f p2(value.xprime, value.yprime, 0); |
| 242 p0.SetPoint(p1); |
| 243 ui::Transform xform; |
| 244 xform.SetRotate(value.degree); |
| 245 // just want to make sure that we don't crash in the case of NaN. |
| 246 if (value.degree == value.degree) { |
| 247 xform.TransformPoint(p1); |
| 248 EXPECT_TRUE(PointsAreNearlyEqual(p1, p2)); |
| 249 xform.TransformPointReverse(p1); |
| 250 EXPECT_TRUE(PointsAreNearlyEqual(p1, p0)); |
| 251 } |
| 252 } |
| 253 } |
| 254 |
| 255 // 2D tests |
| 256 TEST(XFormTest, ConcatTranslate2D) { |
| 257 static const struct TestCase { |
| 258 int x1; |
| 259 int y1; |
| 260 float tx; |
| 261 float ty; |
| 262 int x2; |
| 263 int y2; |
| 264 } test_cases[] = { |
| 265 { 0, 0, 10.0f, 20.0f, 10, 20}, |
| 266 { 0, 0, -10.0f, -20.0f, 0, 0}, |
| 267 { 0, 0, -10.0f, -20.0f, -10, -20}, |
| 268 { 0, 0, |
| 269 std::numeric_limits<float>::quiet_NaN(), |
| 270 std::numeric_limits<float>::quiet_NaN(), |
| 271 10, 20}, |
| 272 }; |
| 273 |
| 274 ui::Transform xform; |
| 275 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { |
| 276 const TestCase& value = test_cases[i]; |
| 277 xform.ConcatTranslate(value.tx, value.ty); |
| 278 gfx::Point p1(value.x1, value.y1); |
| 279 gfx::Point p2(value.x2, value.y2); |
| 280 xform.TransformPoint(p1); |
| 281 if (value.tx == value.tx && |
| 282 value.ty == value.ty) { |
| 283 EXPECT_EQ(p1.x(), p2.x()); |
| 284 EXPECT_EQ(p1.y(), p2.y()); |
| 285 } |
| 286 } |
| 287 } |
| 288 |
| 289 TEST(XFormTest, ConcatScale2D) { |
| 290 static const struct TestCase { |
| 291 int before; |
| 292 float scale; |
| 293 int after; |
| 294 } test_cases[] = { |
| 295 { 1, 10.0f, 10}, |
| 296 { 1, .1f, 1}, |
| 297 { 1, 100.0f, 100}, |
| 298 { 1, -1.0f, -100}, |
| 299 { 1, std::numeric_limits<float>::quiet_NaN(), 1} |
| 300 }; |
| 301 |
| 302 ui::Transform xform; |
| 303 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { |
| 304 const TestCase& value = test_cases[i]; |
| 305 xform.ConcatScale(value.scale, value.scale); |
| 306 gfx::Point p1(value.before, value.before); |
| 307 gfx::Point p2(value.after, value.after); |
| 308 xform.TransformPoint(p1); |
| 309 if (value.scale == value.scale) { |
| 310 EXPECT_EQ(p1.x(), p2.x()); |
| 311 EXPECT_EQ(p1.y(), p2.y()); |
| 312 } |
| 313 } |
| 314 } |
| 315 |
| 316 TEST(XFormTest, ConcatRotate2D) { |
| 317 static const struct TestCase { |
| 318 int x1; |
| 319 int y1; |
| 320 float degrees; |
| 321 int x2; |
| 322 int y2; |
| 323 } test_cases[] = { |
| 324 { 1, 0, 90.0f, 0, 1}, |
| 325 { 1, 0, -90.0f, 1, 0}, |
| 326 { 1, 0, 90.0f, 0, 1}, |
| 327 { 1, 0, 360.0f, 0, 1}, |
| 328 { 1, 0, 0.0f, 0, 1}, |
| 329 { 1, 0, std::numeric_limits<float>::quiet_NaN(), 1, 0} |
| 330 }; |
| 331 |
| 332 ui::Transform xform; |
| 333 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { |
| 334 const TestCase& value = test_cases[i]; |
| 335 xform.ConcatRotate(value.degrees); |
| 336 gfx::Point p1(value.x1, value.y1); |
| 337 gfx::Point p2(value.x2, value.y2); |
| 338 xform.TransformPoint(p1); |
| 339 if (value.degrees == value.degrees) { |
| 340 EXPECT_EQ(p1.x(), p2.x()); |
| 341 EXPECT_EQ(p1.y(), p2.y()); |
| 342 } |
| 343 } |
| 344 } |
| 345 |
| 346 TEST(XFormTest, SetTranslate2D) { |
| 347 static const struct TestCase { |
| 348 int x1; int y1; |
| 349 float tx; float ty; |
| 350 int x2; int y2; |
| 351 } test_cases[] = { |
| 352 { 0, 0, 10.0f, 20.0f, 10, 20}, |
| 353 { 10, 20, 10.0f, 20.0f, 20, 40}, |
| 354 { 10, 20, 0.0f, 0.0f, 10, 20}, |
| 355 { 0, 0, |
| 356 std::numeric_limits<float>::quiet_NaN(), |
| 357 std::numeric_limits<float>::quiet_NaN(), |
| 358 0, 0} |
| 359 }; |
| 360 |
| 361 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { |
| 362 const TestCase& value = test_cases[i]; |
| 363 for (int j = -1; j < 2; ++j) { |
| 364 for (int k = 0; k < 3; ++k) { |
| 365 float epsilon = 0.0001f; |
| 366 gfx::Point p0, p1, p2; |
| 367 ui::Transform xform; |
| 368 switch (k) { |
| 369 case 0: |
| 370 p1.SetPoint(value.x1, 0); |
| 371 p2.SetPoint(value.x2, 0); |
| 372 xform.SetTranslateX(value.tx + j * epsilon); |
| 373 break; |
| 374 case 1: |
| 375 p1.SetPoint(0, value.y1); |
| 376 p2.SetPoint(0, value.y2); |
| 377 xform.SetTranslateY(value.ty + j * epsilon); |
| 378 break; |
| 379 case 2: |
| 380 p1.SetPoint(value.x1, value.y1); |
| 381 p2.SetPoint(value.x2, value.y2); |
| 382 xform.SetTranslate(value.tx + j * epsilon, |
| 383 value.ty + j * epsilon); |
| 384 break; |
| 385 } |
| 386 p0 = p1; |
| 387 xform.TransformPoint(p1); |
| 388 if (value.tx == value.tx && |
| 389 value.ty == value.ty) { |
| 390 EXPECT_EQ(p1.x(), p2.x()); |
| 391 EXPECT_EQ(p1.y(), p2.y()); |
| 392 xform.TransformPointReverse(p1); |
| 393 EXPECT_EQ(p1.x(), p0.x()); |
| 394 EXPECT_EQ(p1.y(), p0.y()); |
| 395 } |
| 396 } |
| 397 } |
| 398 } |
| 399 } |
| 400 |
| 401 TEST(XFormTest, SetScale2D) { |
| 402 static const struct TestCase { |
| 403 int before; |
| 404 float s; |
| 405 int after; |
| 406 } test_cases[] = { |
| 407 { 1, 10.0f, 10}, |
| 408 { 1, 1.0f, 1}, |
| 409 { 1, 0.0f, 0}, |
| 410 { 0, 10.0f, 0}, |
| 411 { 1, std::numeric_limits<float>::quiet_NaN(), 0}, |
| 412 }; |
| 413 |
| 414 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { |
| 415 const TestCase& value = test_cases[i]; |
| 416 for (int j = -1; j < 2; ++j) { |
| 417 for (int k = 0; k < 3; ++k) { |
| 418 float epsilon = 0.0001f; |
| 419 gfx::Point p0, p1, p2; |
| 420 ui::Transform xform; |
| 421 switch (k) { |
| 422 case 0: |
| 423 p1.SetPoint(value.before, 0); |
| 424 p2.SetPoint(value.after, 0); |
| 425 xform.SetScaleX(value.s + j * epsilon); |
| 426 break; |
| 427 case 1: |
| 428 p1.SetPoint(0, value.before); |
| 429 p2.SetPoint(0, value.after); |
| 430 xform.SetScaleY(value.s + j * epsilon); |
| 431 break; |
| 432 case 2: |
| 433 p1.SetPoint(value.before, |
| 434 value.before); |
| 435 p2.SetPoint(value.after, |
| 436 value.after); |
| 437 xform.SetScale(value.s + j * epsilon, |
| 438 value.s + j * epsilon); |
| 439 break; |
| 440 } |
| 441 p0 = p1; |
| 442 xform.TransformPoint(p1); |
| 443 if (value.s == value.s) { |
| 444 EXPECT_EQ(p1.x(), p2.x()); |
| 445 EXPECT_EQ(p1.y(), p2.y()); |
| 446 if (value.s != 0.0f) { |
| 447 xform.TransformPointReverse(p1); |
| 448 EXPECT_EQ(p1.x(), p0.x()); |
| 449 EXPECT_EQ(p1.y(), p0.y()); |
| 450 } |
| 451 } |
| 452 } |
| 453 } |
| 454 } |
| 455 } |
| 456 |
| 457 TEST(XFormTest, SetRotate2D) { |
| 458 static const struct SetRotateCase { |
| 459 int x; |
| 460 int y; |
| 461 float degree; |
| 462 int xprime; |
| 463 int yprime; |
| 464 } set_rotate_cases[] = { |
| 465 { 100, 0, 90.0f, 0, 100}, |
| 466 { 0, 0, 90.0f, 0, 0}, |
| 467 { 0, 100, 90.0f, -100, 0}, |
| 468 { 0, 1, -90.0f, 1, 0}, |
| 469 { 100, 0, 0.0f, 100, 0}, |
| 470 { 0, 0, 0.0f, 0, 0}, |
| 471 { 0, 0, std::numeric_limits<float>::quiet_NaN(), 0, 0}, |
| 472 { 100, 0, 360.0f, 100, 0} |
| 473 }; |
| 474 |
| 475 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(set_rotate_cases); ++i) { |
| 476 const SetRotateCase& value = set_rotate_cases[i]; |
| 477 for (int j = 1; j >= -1; --j) { |
| 478 float epsilon = 0.1f; |
| 479 gfx::Point pt(value.x, value.y); |
| 480 ui::Transform xform; |
| 481 // should be invariant to small floating point errors. |
| 482 xform.SetRotate(value.degree + j * epsilon); |
| 483 // just want to make sure that we don't crash in the case of NaN. |
| 484 if (value.degree == value.degree) { |
| 485 xform.TransformPoint(pt); |
| 486 EXPECT_EQ(value.xprime, pt.x()); |
| 487 EXPECT_EQ(value.yprime, pt.y()); |
| 488 xform.TransformPointReverse(pt); |
| 489 EXPECT_EQ(pt.x(), value.x); |
| 490 EXPECT_EQ(pt.y(), value.y); |
| 491 } |
| 492 } |
| 493 } |
| 494 } |
OLD | NEW |