1 #include <cxxtest/TestSuite.h>
3 #include <libnr/nr-matrix.h>
4 #include <libnr/nr-matrix-fns.h>
5 #include <libnr/nr-matrix-ops.h>
6 #include <libnr/nr-matrix-rotate-ops.h>
7 #include <libnr/nr-matrix-scale-ops.h>
8 #include <libnr/nr-point-matrix-ops.h>
9 #include <libnr/nr-rotate.h>
10 #include <libnr/nr-rotate-ops.h>
11 #include <libnr/nr-scale-ops.h>
12 #include <libnr/nr-scale-translate-ops.h>
13 #include <libnr/nr-translate.h>
14 #include <libnr/nr-translate-ops.h>
15 #include <libnr/nr-translate-scale-ops.h>
17 inline bool point_equalp(NR::Point const &a, NR::Point const &b)
18 {
19 return ( NR_DF_TEST_CLOSE(a[NR::X], b[NR::X], 1e-5) &&
20 NR_DF_TEST_CLOSE(a[NR::Y], b[NR::Y], 1e-5) );
21 }
23 class NrMatrixTest : public CxxTest::TestSuite
24 {
25 public:
27 NrMatrixTest() :
28 m_id( NR::identity() ),
29 r_id( NR::Point(1, 0) ),
30 t_id( 0, 0 ),
31 c16( 1.0, 2.0,
32 3.0, 4.0,
33 5.0, 6.0),
34 r86( NR::Point(.8, .6) ),
35 mr86( r86 ),
36 t23( 2.0, 3.0 ),
37 s_id( 1.0, 1.0 )
38 {
39 }
40 virtual ~NrMatrixTest() {}
42 // createSuite and destroySuite get us per-suite setup and teardown
43 // without us having to worry about static initialization order, etc.
44 static NrMatrixTest *createSuite() { return new NrMatrixTest(); }
45 static void destroySuite( NrMatrixTest *suite ) { delete suite; }
47 NR::Matrix const m_id;
48 NR::rotate const r_id;
49 NR::translate const t_id;
50 NR::Matrix const c16;
51 NR::rotate const r86;
52 NR::Matrix const mr86;
53 NR::translate const t23;
54 NR::scale const s_id;
59 void testCtorsAssignmentOp(void)
60 {
61 NR::Matrix const c16_copy(c16);
62 NR::Matrix c16_eq(m_id);
63 c16_eq = c16;
64 for(unsigned i = 0; i < 6; ++i) {
65 TS_ASSERT_EQUALS( c16[i], 1.0 + i );
66 TS_ASSERT_EQUALS( c16[i], c16_copy[i] );
67 TS_ASSERT_EQUALS( c16[i], c16_eq[i] );
68 TS_ASSERT_EQUALS( m_id[i], double( i == 0 || i == 3 ) );
69 }
70 }
72 void testScaleCtor(void)
73 {
74 NR::scale const s(2.0, 3.0);
75 NR::Matrix const ms(s);
76 NR::Point const p(5.0, 7.0);
77 TS_ASSERT_EQUALS( p * s, NR::Point(10.0, 21.0) );
78 TS_ASSERT_EQUALS( p * ms, NR::Point(10.0, 21.0) );
79 }
81 void testRotateCtor(void)
82 {
83 NR::Point const p0(1.0, 0.0);
84 NR::Point const p90(0.0, 1.0);
85 TS_ASSERT_EQUALS( p0 * r86, NR::Point(.8, .6) );
86 TS_ASSERT_EQUALS( p0 * mr86, NR::Point(.8, .6) );
87 TS_ASSERT_EQUALS( p90 * r86, NR::Point(-.6, .8) );
88 TS_ASSERT_EQUALS( p90 * mr86, NR::Point(-.6, .8) );
89 TS_ASSERT( matrix_equalp(NR::Matrix( r86 * r86 ),
90 mr86 * mr86,
91 1e-14) );
92 }
94 void testTranslateCtor(void)
95 {
96 NR::Matrix const mt23(t23);
97 NR::Point const b(-2.0, 3.0);
98 TS_ASSERT_EQUALS( b * t23, b * mt23 );
99 }
101 void testIdentity(void)
102 {
103 TS_ASSERT( m_id.test_identity() );
104 TS_ASSERT( NR::Matrix(t_id).test_identity() );
105 TS_ASSERT( !(NR::Matrix(NR::translate(-2, 3)).test_identity()) );
106 TS_ASSERT( NR::Matrix(r_id).test_identity() );
107 NR::rotate const rot180(NR::Point(-1, 0));
108 TS_ASSERT( !(NR::Matrix(rot180).test_identity()) );
109 TS_ASSERT( NR::Matrix(s_id).test_identity() );
110 TS_ASSERT( !(NR::Matrix(NR::scale(1.0, 0.0)).test_identity()) );
111 TS_ASSERT( !(NR::Matrix(NR::scale(0.0, 1.0)).test_identity()) );
112 TS_ASSERT( !(NR::Matrix(NR::scale(1.0, -1.0)).test_identity()) );
113 TS_ASSERT( !(NR::Matrix(NR::scale(-1.0, -1.0)).test_identity()) );
114 }
116 void testInverse(void)
117 {
118 TS_ASSERT_EQUALS( m_id.inverse(), m_id );
119 TS_ASSERT_EQUALS( NR::Matrix(t23).inverse(), NR::Matrix(NR::translate(-2.0, -3.0)) );
120 NR::scale const s2(-4.0, 2.0);
121 NR::scale const sp5(-.25, .5);
122 TS_ASSERT_EQUALS( NR::Matrix(s2).inverse(), NR::Matrix(sp5) );
123 TS_ASSERT_EQUALS( NR::Matrix(sp5).inverse(), NR::Matrix(s2) );
124 }
126 void testEllipticQuadraticForm(void)
127 {
128 NR::Matrix const aff(1.0, 1.0,
129 0.0, 1.0,
130 5.0, 6.0);
131 NR::Matrix const invaff = aff.inverse();
132 TS_ASSERT_EQUALS( invaff[1], -1.0 );
134 NR::Matrix const ef(elliptic_quadratic_form(invaff));
135 NR::Matrix const exp_ef(2, -1,
136 -1, 1,
137 0, 0);
138 TS_ASSERT_EQUALS( ef, exp_ef );
139 }
141 void testMatrixStarRotate(void)
142 {
143 NR::Matrix const ma(2.0, -1.0,
144 4.0, 4.0,
145 -0.5, 2.0);
146 NR::Matrix const a_r86( ma * r86 );
147 NR::Matrix const ma1( a_r86 * r86.inverse() );
148 TS_ASSERT( matrix_equalp(ma1, ma, 1e-12) );
149 NR::Matrix const exp_a_r86( 2*.8 + -1*-.6, 2*.6 + -1*.8,
150 4*.8 + 4*-.6, 4*.6 + 4*.8,
151 -.5*.8 + 2*-.6, -.5*.6 + 2*.8 );
152 TS_ASSERT( matrix_equalp(a_r86, exp_a_r86, 1e-12) );
153 }
155 void testTranslateStarScale_ScaleStarTranslate(void)
156 {
157 NR::translate const t2n4(2, -4);
158 NR::scale const sn2_8(-2, 8);
159 NR::Matrix const exp_ts(-2, 0,
160 0, 8,
161 -4, -32);
162 NR::Matrix const exp_st(-2, 0,
163 0, 8,
164 2, -4);
165 TS_ASSERT_EQUALS( exp_ts, t2n4 * sn2_8 );
166 TS_ASSERT_EQUALS( exp_st, sn2_8 * t2n4 );
167 }
169 void testMatrixStarScale(void)
170 {
171 NR::Matrix const ma(2.0, -1.0,
172 4.0, 4.0,
173 -0.5, 2.0);
174 NR::scale const sn2_8(-2, 8);
175 NR::Matrix const exp_as(-4, -8,
176 -8, 32,
177 1, 16);
178 TS_ASSERT_EQUALS( ma * sn2_8, exp_as );
179 }
180 };
182 /*
183 Local Variables:
184 mode:c++
185 c-file-style:"stroustrup"
186 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
187 indent-tabs-mode:nil
188 fill-column:99
189 End:
190 */
191 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :