OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkMatrix44.h" | 8 #include "SkMatrix44.h" |
9 #include "Test.h" | 9 #include "Test.h" |
10 | 10 |
(...skipping 532 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
543 | 543 |
544 transform.reset(); | 544 transform.reset(); |
545 transform.set(3, 3, 0.5); | 545 transform.set(3, 3, 0.5); |
546 REPORTER_ASSERT(reporter, transform.hasPerspective()); | 546 REPORTER_ASSERT(reporter, transform.hasPerspective()); |
547 | 547 |
548 transform.reset(); | 548 transform.reset(); |
549 transform.set(3, 3, 0.0); | 549 transform.set(3, 3, 0.0); |
550 REPORTER_ASSERT(reporter, transform.hasPerspective()); | 550 REPORTER_ASSERT(reporter, transform.hasPerspective()); |
551 } | 551 } |
552 | 552 |
| 553 static bool is_rectilinear (SkVector4& p1, SkVector4& p2, SkVector4& p3, SkVecto
r4& p4) { |
| 554 return (SkScalarNearlyEqual(p1.fData[0], p2.fData[0]) && |
| 555 SkScalarNearlyEqual(p2.fData[1], p3.fData[1]) && |
| 556 SkScalarNearlyEqual(p3.fData[0], p4.fData[0]) && |
| 557 SkScalarNearlyEqual(p4.fData[1], p1.fData[1])) || |
| 558 (SkScalarNearlyEqual(p1.fData[1], p2.fData[1]) && |
| 559 SkScalarNearlyEqual(p2.fData[0], p3.fData[0]) && |
| 560 SkScalarNearlyEqual(p3.fData[1], p4.fData[1]) && |
| 561 SkScalarNearlyEqual(p4.fData[0], p1.fData[0])); |
| 562 } |
| 563 |
| 564 static SkVector4 mul_with_persp_divide(const SkMatrix44& transform, const SkVect
or4& target) { |
| 565 SkVector4 result = transform * target; |
| 566 if (result.fData[3] != 0.0f && result.fData[3] != SK_Scalar1) { |
| 567 float wInverse = SK_Scalar1 / result.fData[3]; |
| 568 result.set(result.fData[0] * wInverse, |
| 569 result.fData[1] * wInverse, |
| 570 result.fData[2] * wInverse, |
| 571 SK_Scalar1); |
| 572 } |
| 573 return result; |
| 574 } |
| 575 |
| 576 static bool empirically_preserves_2d_axis_alignment(skiatest::Reporter* reporter
, |
| 577 const SkMatrix44& transform)
{ |
| 578 SkVector4 p1(5.0f, 5.0f, 0.0f); |
| 579 SkVector4 p2(10.0f, 5.0f, 0.0f); |
| 580 SkVector4 p3(10.0f, 20.0f, 0.0f); |
| 581 SkVector4 p4(5.0f, 20.0f, 0.0f); |
| 582 |
| 583 REPORTER_ASSERT(reporter, is_rectilinear(p1, p2, p3, p4)); |
| 584 |
| 585 p1 = mul_with_persp_divide(transform, p1); |
| 586 p2 = mul_with_persp_divide(transform, p2); |
| 587 p3 = mul_with_persp_divide(transform, p3); |
| 588 p4 = mul_with_persp_divide(transform, p4); |
| 589 |
| 590 return is_rectilinear(p1, p2, p3, p4); |
| 591 } |
| 592 |
| 593 static void test(bool expected, skiatest::Reporter* reporter, const SkMatrix44&
transform) { |
| 594 if (expected) { |
| 595 REPORTER_ASSERT(reporter, empirically_preserves_2d_axis_alignment(report
er, transform)); |
| 596 REPORTER_ASSERT(reporter, transform.preserves2dAxisAlignment()); |
| 597 } else { |
| 598 REPORTER_ASSERT(reporter, !empirically_preserves_2d_axis_alignment(repor
ter, transform)); |
| 599 REPORTER_ASSERT(reporter, !transform.preserves2dAxisAlignment()); |
| 600 } |
| 601 } |
| 602 |
| 603 static void test_preserves_2d_axis_alignment(skiatest::Reporter* reporter) { |
| 604 SkMatrix44 transform(SkMatrix44::kUninitialized_Constructor); |
| 605 SkMatrix44 transform2(SkMatrix44::kUninitialized_Constructor); |
| 606 |
| 607 static const struct TestCase { |
| 608 SkMScalar a; // row 1, column 1 |
| 609 SkMScalar b; // row 1, column 2 |
| 610 SkMScalar c; // row 2, column 1 |
| 611 SkMScalar d; // row 2, column 2 |
| 612 bool expected; |
| 613 } test_cases[] = { |
| 614 { 3.f, 0.f, |
| 615 0.f, 4.f, true }, // basic case |
| 616 { 0.f, 4.f, |
| 617 3.f, 0.f, true }, // rotate by 90 |
| 618 { 0.f, 0.f, |
| 619 0.f, 4.f, true }, // degenerate x |
| 620 { 3.f, 0.f, |
| 621 0.f, 0.f, true }, // degenerate y |
| 622 { 0.f, 0.f, |
| 623 3.f, 0.f, true }, // degenerate x + rotate by 90 |
| 624 { 0.f, 4.f, |
| 625 0.f, 0.f, true }, // degenerate y + rotate by 90 |
| 626 { 3.f, 4.f, |
| 627 0.f, 0.f, false }, |
| 628 { 0.f, 0.f, |
| 629 3.f, 4.f, false }, |
| 630 { 0.f, 3.f, |
| 631 0.f, 4.f, false }, |
| 632 { 3.f, 0.f, |
| 633 4.f, 0.f, false }, |
| 634 { 3.f, 4.f, |
| 635 5.f, 0.f, false }, |
| 636 { 3.f, 4.f, |
| 637 0.f, 5.f, false }, |
| 638 { 3.f, 0.f, |
| 639 4.f, 5.f, false }, |
| 640 { 0.f, 3.f, |
| 641 4.f, 5.f, false }, |
| 642 { 2.f, 3.f, |
| 643 4.f, 5.f, false }, |
| 644 }; |
| 645 |
| 646 for (size_t i = 0; i < sizeof(test_cases)/sizeof(TestCase); ++i) { |
| 647 const TestCase& value = test_cases[i]; |
| 648 transform.setIdentity(); |
| 649 transform.set(0, 0, value.a); |
| 650 transform.set(0, 1, value.b); |
| 651 transform.set(1, 0, value.c); |
| 652 transform.set(1, 1, value.d); |
| 653 |
| 654 test(value.expected, reporter, transform); |
| 655 } |
| 656 |
| 657 // Try the same test cases again, but this time make sure that other matrix |
| 658 // elements (except perspective) have entries, to test that they are ignored. |
| 659 for (size_t i = 0; i < sizeof(test_cases)/sizeof(TestCase); ++i) { |
| 660 const TestCase& value = test_cases[i]; |
| 661 transform.setIdentity(); |
| 662 transform.set(0, 0, value.a); |
| 663 transform.set(0, 1, value.b); |
| 664 transform.set(1, 0, value.c); |
| 665 transform.set(1, 1, value.d); |
| 666 |
| 667 transform.set(0, 2, 1.f); |
| 668 transform.set(0, 3, 2.f); |
| 669 transform.set(1, 2, 3.f); |
| 670 transform.set(1, 3, 4.f); |
| 671 transform.set(2, 0, 5.f); |
| 672 transform.set(2, 1, 6.f); |
| 673 transform.set(2, 2, 7.f); |
| 674 transform.set(2, 3, 8.f); |
| 675 |
| 676 test(value.expected, reporter, transform); |
| 677 } |
| 678 |
| 679 // Try the same test cases again, but this time add perspective which is |
| 680 // always assumed to not-preserve axis alignment. |
| 681 for (size_t i = 0; i < sizeof(test_cases)/sizeof(TestCase); ++i) { |
| 682 const TestCase& value = test_cases[i]; |
| 683 transform.setIdentity(); |
| 684 transform.set(0, 0, value.a); |
| 685 transform.set(0, 1, value.b); |
| 686 transform.set(1, 0, value.c); |
| 687 transform.set(1, 1, value.d); |
| 688 |
| 689 transform.set(0, 2, 1.f); |
| 690 transform.set(0, 3, 2.f); |
| 691 transform.set(1, 2, 3.f); |
| 692 transform.set(1, 3, 4.f); |
| 693 transform.set(2, 0, 5.f); |
| 694 transform.set(2, 1, 6.f); |
| 695 transform.set(2, 2, 7.f); |
| 696 transform.set(2, 3, 8.f); |
| 697 transform.set(3, 0, 9.f); |
| 698 transform.set(3, 1, 10.f); |
| 699 transform.set(3, 2, 11.f); |
| 700 transform.set(3, 3, 12.f); |
| 701 |
| 702 test(false, reporter, transform); |
| 703 } |
| 704 |
| 705 // Try a few more practical situations to check precision |
| 706 // Reuse TestCase (a, b, c, d) as (x, y, z, degrees) axis to rotate about. |
| 707 TestCase rotation_tests[] = { |
| 708 { 0.0, 0.0, 1.0, 90.0, true }, |
| 709 { 0.0, 0.0, 1.0, 180.0, true }, |
| 710 { 0.0, 0.0, 1.0, 270.0, true }, |
| 711 { 0.0, 1.0, 0.0, 90.0, true }, |
| 712 { 1.0, 0.0, 0.0, 90.0, true }, |
| 713 { 0.0, 0.0, 1.0, 45.0, false }, |
| 714 // In 3d these next two are non-preserving, but we're testing in 2d after |
| 715 // orthographic projection, where they are. |
| 716 { 0.0, 1.0, 0.0, 45.0, true }, |
| 717 { 1.0, 0.0, 0.0, 45.0, true }, |
| 718 }; |
| 719 |
| 720 for (size_t i = 0; i < sizeof(rotation_tests)/sizeof(TestCase); ++i) { |
| 721 const TestCase& value = rotation_tests[i]; |
| 722 transform.setRotateDegreesAbout(value.a, value.b, value.c, value.d); |
| 723 test(value.expected, reporter, transform); |
| 724 } |
| 725 |
| 726 static const struct DoubleRotationCase { |
| 727 SkMScalar x1; |
| 728 SkMScalar y1; |
| 729 SkMScalar z1; |
| 730 SkMScalar degrees1; |
| 731 SkMScalar x2; |
| 732 SkMScalar y2; |
| 733 SkMScalar z2; |
| 734 SkMScalar degrees2; |
| 735 bool expected; |
| 736 } double_rotation_tests[] = { |
| 737 { 0.0, 0.0, 1.0, 90.0, 0.0, 1.0, 0.0, 90.0, true }, |
| 738 { 0.0, 0.0, 1.0, 90.0, 1.0, 0.0, 0.0, 90.0, true }, |
| 739 { 0.0, 1.0, 0.0, 90.0, 0.0, 0.0, 1.0, 90.0, true }, |
| 740 }; |
| 741 |
| 742 for (size_t i = 0; i < sizeof(double_rotation_tests)/sizeof(DoubleRotationCase
); ++i) { |
| 743 const DoubleRotationCase& value = double_rotation_tests[i]; |
| 744 transform.setRotateDegreesAbout(value.x1, value.y1, value.z1, value.degrees1
); |
| 745 transform2.setRotateDegreesAbout(value.x2, value.y2, value.z2, value.degrees
2); |
| 746 transform.postConcat(transform2); |
| 747 test(value.expected, reporter, transform); |
| 748 } |
| 749 |
| 750 // Perspective cases. |
| 751 transform.setIdentity(); |
| 752 transform.set(3, 2, -0.1); // Perspective depth 10 |
| 753 transform2.setRotateDegreesAbout(0.0, 1.0, 0.0, 45.0); |
| 754 transform.preConcat(transform2); |
| 755 test(false, reporter, transform); |
| 756 |
| 757 transform.setIdentity(); |
| 758 transform.set(3, 2, -0.1); // Perspective depth 10 |
| 759 transform2.setRotateDegreesAbout(0.0, 0.0, 1.0, 90.0); |
| 760 transform.preConcat(transform2); |
| 761 test(true, reporter, transform); |
| 762 } |
| 763 |
| 764 |
553 DEF_TEST(Matrix44, reporter) { | 765 DEF_TEST(Matrix44, reporter) { |
554 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); | 766 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); |
555 SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor); | 767 SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor); |
556 SkMatrix44 iden1(SkMatrix44::kUninitialized_Constructor); | 768 SkMatrix44 iden1(SkMatrix44::kUninitialized_Constructor); |
557 SkMatrix44 iden2(SkMatrix44::kUninitialized_Constructor); | 769 SkMatrix44 iden2(SkMatrix44::kUninitialized_Constructor); |
558 SkMatrix44 rot(SkMatrix44::kUninitialized_Constructor); | 770 SkMatrix44 rot(SkMatrix44::kUninitialized_Constructor); |
559 | 771 |
560 mat.setTranslate(1, 1, 1); | 772 mat.setTranslate(1, 1, 1); |
561 mat.invert(&inverse); | 773 mat.invert(&inverse); |
562 iden1.setConcat(mat, inverse); | 774 iden1.setConcat(mat, inverse); |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
649 test_determinant(reporter); | 861 test_determinant(reporter); |
650 test_invert(reporter); | 862 test_invert(reporter); |
651 test_transpose(reporter); | 863 test_transpose(reporter); |
652 test_get_set_double(reporter); | 864 test_get_set_double(reporter); |
653 test_set_row_col_major(reporter); | 865 test_set_row_col_major(reporter); |
654 test_translate(reporter); | 866 test_translate(reporter); |
655 test_scale(reporter); | 867 test_scale(reporter); |
656 test_map2(reporter); | 868 test_map2(reporter); |
657 test_3x3_conversion(reporter); | 869 test_3x3_conversion(reporter); |
658 test_has_perspective(reporter); | 870 test_has_perspective(reporter); |
| 871 test_preserves_2d_axis_alignment(reporter); |
659 } | 872 } |
OLD | NEW |