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_preserves_2d_axis_alignment(skiatest::Reporter* reporter) { | |
594 SkMatrix44 transform(SkMatrix44::kUninitialized_Constructor); | |
595 SkMatrix44 transform2(SkMatrix44::kUninitialized_Constructor); | |
596 | |
597 static const struct TestCase { | |
598 SkMScalar a; // row 1, column 1 | |
599 SkMScalar b; // row 1, column 2 | |
600 SkMScalar c; // row 2, column 1 | |
601 SkMScalar d; // row 2, column 2 | |
602 bool expected; | |
603 } test_cases[] = { | |
604 { 3.f, 0.f, | |
605 0.f, 4.f, true }, // basic case | |
606 { 0.f, 4.f, | |
607 3.f, 0.f, true }, // rotate by 90 | |
608 { 0.f, 0.f, | |
609 0.f, 4.f, true }, // degenerate x | |
610 { 3.f, 0.f, | |
611 0.f, 0.f, true }, // degenerate y | |
612 { 0.f, 0.f, | |
613 3.f, 0.f, true }, // degenerate x + rotate by 90 | |
614 { 0.f, 4.f, | |
615 0.f, 0.f, true }, // degenerate y + rotate by 90 | |
616 { 3.f, 4.f, | |
617 0.f, 0.f, false }, | |
618 { 0.f, 0.f, | |
619 3.f, 4.f, false }, | |
620 { 0.f, 3.f, | |
621 0.f, 4.f, false }, | |
622 { 3.f, 0.f, | |
623 4.f, 0.f, false }, | |
624 { 3.f, 4.f, | |
625 5.f, 0.f, false }, | |
626 { 3.f, 4.f, | |
627 0.f, 5.f, false }, | |
628 { 3.f, 0.f, | |
629 4.f, 5.f, false }, | |
630 { 0.f, 3.f, | |
631 4.f, 5.f, false }, | |
632 { 2.f, 3.f, | |
633 4.f, 5.f, false }, | |
634 }; | |
635 | |
636 for (size_t i = 0; i < sizeof(test_cases)/sizeof(TestCase); ++i) { | |
637 const TestCase& value = test_cases[i]; | |
638 transform.setIdentity(); | |
639 transform.set(0, 0, value.a); | |
640 transform.set(0, 1, value.b); | |
641 transform.set(1, 0, value.c); | |
642 transform.set(1, 1, value.d); | |
643 | |
644 if (value.expected) { | |
645 REPORTER_ASSERT(reporter, empirically_preserves_2d_axis_alignment(reporter , transform)); | |
646 REPORTER_ASSERT(reporter, transform.preserves2dAxisAlignment()); | |
647 } else { | |
648 REPORTER_ASSERT(reporter, !empirically_preserves_2d_axis_alignment(reporte r, transform)); | |
649 REPORTER_ASSERT(reporter, !transform.preserves2dAxisAlignment()); | |
650 } | |
651 } | |
652 | |
653 // Try the same test cases again, but this time make sure that other matrix | |
654 // elements (except perspective) have entries, to test that they are ignored. | |
655 for (size_t i = 0; i < sizeof(test_cases)/sizeof(TestCase); ++i) { | |
656 const TestCase& value = test_cases[i]; | |
657 transform.setIdentity(); | |
658 transform.set(0, 0, value.a); | |
659 transform.set(0, 1, value.b); | |
660 transform.set(1, 0, value.c); | |
661 transform.set(1, 1, value.d); | |
662 | |
663 transform.set(0, 2, 1.f); | |
664 transform.set(0, 3, 2.f); | |
665 transform.set(1, 2, 3.f); | |
666 transform.set(1, 3, 4.f); | |
667 transform.set(2, 0, 5.f); | |
668 transform.set(2, 1, 6.f); | |
669 transform.set(2, 2, 7.f); | |
670 transform.set(2, 3, 8.f); | |
671 | |
672 if (value.expected) { | |
673 REPORTER_ASSERT(reporter, empirically_preserves_2d_axis_alignment(reporter , transform)); | |
674 REPORTER_ASSERT(reporter, transform.preserves2dAxisAlignment()); | |
675 } else { | |
676 REPORTER_ASSERT(reporter, !empirically_preserves_2d_axis_alignment(reporte r, transform)); | |
677 REPORTER_ASSERT(reporter, !transform.preserves2dAxisAlignment()); | |
678 } | |
679 } | |
680 | |
681 // Try the same test cases again, but this time add perspective which is | |
682 // always assumed to not-preserve axis alignment. | |
683 for (size_t i = 0; i < sizeof(test_cases)/sizeof(TestCase); ++i) { | |
684 const TestCase& value = test_cases[i]; | |
685 transform.setIdentity(); | |
686 transform.set(0, 0, value.a); | |
687 transform.set(0, 1, value.b); | |
688 transform.set(1, 0, value.c); | |
689 transform.set(1, 1, value.d); | |
690 | |
691 transform.set(0, 2, 1.f); | |
692 transform.set(0, 3, 2.f); | |
693 transform.set(1, 2, 3.f); | |
694 transform.set(1, 3, 4.f); | |
695 transform.set(2, 0, 5.f); | |
696 transform.set(2, 1, 6.f); | |
697 transform.set(2, 2, 7.f); | |
698 transform.set(2, 3, 8.f); | |
699 transform.set(3, 0, 9.f); | |
700 transform.set(3, 1, 10.f); | |
701 transform.set(3, 2, 11.f); | |
702 transform.set(3, 3, 12.f); | |
703 | |
704 REPORTER_ASSERT(reporter, !empirically_preserves_2d_axis_alignment(reporter, transform)); | |
705 REPORTER_ASSERT(reporter, !transform.preserves2dAxisAlignment()); | |
706 } | |
707 | |
708 // Try a few more practical situations to check precision | |
reed1
2014/09/19 16:45:14
can these be refactored into some sort of table? A
tomhudson
2014/09/19 18:21:19
Done.
Doesn't save much line count, but should be
| |
709 transform.setRotateDegreesAbout(0.0, 0.0, 1.0, 90.0); | |
710 REPORTER_ASSERT(reporter, empirically_preserves_2d_axis_alignment(reporter, tr ansform)); | |
711 REPORTER_ASSERT(reporter, transform.preserves2dAxisAlignment()); | |
712 | |
713 transform.setRotateDegreesAbout(0.0, 0.0, 1.0, 180.0); | |
714 REPORTER_ASSERT(reporter, empirically_preserves_2d_axis_alignment(reporter, tr ansform)); | |
715 REPORTER_ASSERT(reporter, transform.preserves2dAxisAlignment()); | |
716 | |
717 transform.setRotateDegreesAbout(0.0, 0.0, 1.0, 270.0); | |
718 REPORTER_ASSERT(reporter, empirically_preserves_2d_axis_alignment(reporter, tr ansform)); | |
719 REPORTER_ASSERT(reporter, transform.preserves2dAxisAlignment()); | |
720 | |
721 transform.setRotateDegreesAbout(0.0, 1.0, 0.0, 90.0); | |
722 REPORTER_ASSERT(reporter, empirically_preserves_2d_axis_alignment(reporter, tr ansform)); | |
723 REPORTER_ASSERT(reporter, transform.preserves2dAxisAlignment()); | |
724 | |
725 transform.setRotateDegreesAbout(1.0, 0.0, 0.0, 90.0); | |
726 REPORTER_ASSERT(reporter, empirically_preserves_2d_axis_alignment(reporter, tr ansform)); | |
727 REPORTER_ASSERT(reporter, transform.preserves2dAxisAlignment()); | |
728 | |
729 transform.setRotateDegreesAbout(0.0, 0.0, 1.0, 90.0); | |
730 transform2.setRotateDegreesAbout(0.0, 1.0, 0.0, 90.0); | |
731 transform.postConcat(transform2); | |
732 REPORTER_ASSERT(reporter, empirically_preserves_2d_axis_alignment(reporter, tr ansform)); | |
733 REPORTER_ASSERT(reporter, transform.preserves2dAxisAlignment()); | |
734 | |
735 transform.setRotateDegreesAbout(0.0, 0.0, 1.0, 90.0); | |
736 transform2.setRotateDegreesAbout(1.0, 0.0, 0.0, 90.0); | |
737 transform.postConcat(transform2); | |
738 REPORTER_ASSERT(reporter, empirically_preserves_2d_axis_alignment(reporter, tr ansform)); | |
739 REPORTER_ASSERT(reporter, transform.preserves2dAxisAlignment()); | |
740 | |
741 transform.setRotateDegreesAbout(0.0, 1.0, 0.0, 90.0); | |
742 transform2.setRotateDegreesAbout(0.0, 0.0, 1.0, 90.0); | |
743 transform.postConcat(transform2); | |
744 REPORTER_ASSERT(reporter, empirically_preserves_2d_axis_alignment(reporter, tr ansform)); | |
745 REPORTER_ASSERT(reporter, transform.preserves2dAxisAlignment()); | |
746 | |
747 transform.setRotateDegreesAbout(0.0, 0.0, 1.0, 45.0); | |
748 REPORTER_ASSERT(reporter, !empirically_preserves_2d_axis_alignment(reporter, t ransform)); | |
749 REPORTER_ASSERT(reporter, !transform.preserves2dAxisAlignment()); | |
750 | |
751 // 3-d case; In 2d after an orthographic projection, this case does | |
752 // preserve 2d axis alignment. But in 3d, it does not preserve axis | |
753 // alignment. | |
754 transform.setRotateDegreesAbout(0.0, 1.0, 0.0, 45.0); | |
755 REPORTER_ASSERT(reporter, empirically_preserves_2d_axis_alignment(reporter, tr ansform)); | |
756 REPORTER_ASSERT(reporter, transform.preserves2dAxisAlignment()); | |
757 | |
758 transform.setRotateDegreesAbout(1.0, 0.0, 0.0, 45.0); | |
759 REPORTER_ASSERT(reporter, empirically_preserves_2d_axis_alignment(reporter, tr ansform)); | |
760 REPORTER_ASSERT(reporter, transform.preserves2dAxisAlignment()); | |
761 | |
762 // Perspective cases. | |
763 transform.setIdentity(); | |
764 transform.set(3, 2, -0.1); | |
danakj
2014/09/19 16:29:47
can you "// Perspective depth 10" here?
tomhudson
2014/09/19 18:21:19
Done.
| |
765 transform2.setRotateDegreesAbout(0.0, 1.0, 0.0, 45.0); | |
766 transform.preConcat(transform2); | |
767 REPORTER_ASSERT(reporter, !empirically_preserves_2d_axis_alignment(reporter, t ransform)); | |
768 REPORTER_ASSERT(reporter, !transform.preserves2dAxisAlignment()); | |
769 | |
770 transform.setIdentity(); | |
771 transform.set(3, 2, -0.1); | |
danakj
2014/09/19 16:29:47
and here?
tomhudson
2014/09/19 18:21:19
Done.
| |
772 transform2.setRotateDegreesAbout(0.0, 0.0, 1.0, 90.0); | |
773 transform.preConcat(transform2); | |
774 REPORTER_ASSERT(reporter, empirically_preserves_2d_axis_alignment(reporter, tr ansform)); | |
775 REPORTER_ASSERT(reporter, transform.preserves2dAxisAlignment()); | |
776 } | |
777 | |
778 | |
553 DEF_TEST(Matrix44, reporter) { | 779 DEF_TEST(Matrix44, reporter) { |
554 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); | 780 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); |
555 SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor); | 781 SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor); |
556 SkMatrix44 iden1(SkMatrix44::kUninitialized_Constructor); | 782 SkMatrix44 iden1(SkMatrix44::kUninitialized_Constructor); |
557 SkMatrix44 iden2(SkMatrix44::kUninitialized_Constructor); | 783 SkMatrix44 iden2(SkMatrix44::kUninitialized_Constructor); |
558 SkMatrix44 rot(SkMatrix44::kUninitialized_Constructor); | 784 SkMatrix44 rot(SkMatrix44::kUninitialized_Constructor); |
559 | 785 |
560 mat.setTranslate(1, 1, 1); | 786 mat.setTranslate(1, 1, 1); |
561 mat.invert(&inverse); | 787 mat.invert(&inverse); |
562 iden1.setConcat(mat, inverse); | 788 iden1.setConcat(mat, inverse); |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
649 test_determinant(reporter); | 875 test_determinant(reporter); |
650 test_invert(reporter); | 876 test_invert(reporter); |
651 test_transpose(reporter); | 877 test_transpose(reporter); |
652 test_get_set_double(reporter); | 878 test_get_set_double(reporter); |
653 test_set_row_col_major(reporter); | 879 test_set_row_col_major(reporter); |
654 test_translate(reporter); | 880 test_translate(reporter); |
655 test_scale(reporter); | 881 test_scale(reporter); |
656 test_map2(reporter); | 882 test_map2(reporter); |
657 test_3x3_conversion(reporter); | 883 test_3x3_conversion(reporter); |
658 test_has_perspective(reporter); | 884 test_has_perspective(reporter); |
885 test_preserves_2d_axis_alignment(reporter); | |
659 } | 886 } |
OLD | NEW |