• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "Test.h"
9 #include "SkMatrix44.h"
10 
nearly_equal_double(double a,double b)11 static bool nearly_equal_double(double a, double b) {
12     const double tolerance = 1e-7;
13     double diff = a - b;
14     if (diff < 0)
15         diff = -diff;
16     return diff <= tolerance;
17 }
18 
nearly_equal_scalar(SkMScalar a,SkMScalar b)19 static bool nearly_equal_scalar(SkMScalar a, SkMScalar b) {
20     // Note that we get more compounded error for multiple operations when
21     // SK_SCALAR_IS_FIXED.
22 #ifdef SK_SCALAR_IS_FLOAT
23     const SkScalar tolerance = SK_Scalar1 / 200000;
24 #else
25     const SkScalar tolerance = SK_Scalar1 / 1024;
26 #endif
27 
28     return SkTAbs<SkMScalar>(a - b) <= tolerance;
29 }
30 
assert16(skiatest::Reporter * reporter,const T data[],T m0,T m1,T m2,T m3,T m4,T m5,T m6,T m7,T m8,T m9,T m10,T m11,T m12,T m13,T m14,T m15)31 template <typename T> void assert16(skiatest::Reporter* reporter, const T data[],
32                                     T m0,  T m1,  T m2,  T m3,
33                                     T m4,  T m5,  T m6,  T m7,
34                                     T m8,  T m9,  T m10, T m11,
35                                     T m12, T m13, T m14, T m15) {
36     REPORTER_ASSERT(reporter, data[0] == m0);
37     REPORTER_ASSERT(reporter, data[1] == m1);
38     REPORTER_ASSERT(reporter, data[2] == m2);
39     REPORTER_ASSERT(reporter, data[3] == m3);
40 
41     REPORTER_ASSERT(reporter, data[4] == m4);
42     REPORTER_ASSERT(reporter, data[5] == m5);
43     REPORTER_ASSERT(reporter, data[6] == m6);
44     REPORTER_ASSERT(reporter, data[7] == m7);
45 
46     REPORTER_ASSERT(reporter, data[8] == m8);
47     REPORTER_ASSERT(reporter, data[9] == m9);
48     REPORTER_ASSERT(reporter, data[10] == m10);
49     REPORTER_ASSERT(reporter, data[11] == m11);
50 
51     REPORTER_ASSERT(reporter, data[12] == m12);
52     REPORTER_ASSERT(reporter, data[13] == m13);
53     REPORTER_ASSERT(reporter, data[14] == m14);
54     REPORTER_ASSERT(reporter, data[15] == m15);
55 }
56 
nearly_equal(const SkMatrix44 & a,const SkMatrix44 & b)57 static bool nearly_equal(const SkMatrix44& a, const SkMatrix44& b) {
58     for (int i = 0; i < 4; ++i) {
59         for (int j = 0; j < 4; ++j) {
60             if (!nearly_equal_scalar(a.get(i, j), b.get(i, j))) {
61                 printf("not equal %g %g\n", a.get(i, j), b.get(i, j));
62                 return false;
63             }
64         }
65     }
66     return true;
67 }
68 
is_identity(const SkMatrix44 & m)69 static bool is_identity(const SkMatrix44& m) {
70     SkMatrix44 identity;
71     identity.reset();
72     return nearly_equal(m, identity);
73 }
74 
75 ///////////////////////////////////////////////////////////////////////////////
bits_isonly(int value,int mask)76 static bool bits_isonly(int value, int mask) {
77     return 0 == (value & ~mask);
78 }
79 
test_constructor(skiatest::Reporter * reporter)80 static void test_constructor(skiatest::Reporter* reporter) {
81     // Allocate a matrix on the heap
82     SkMatrix44* placeholderMatrix = new SkMatrix44();
83     for (int row = 0; row < 4; ++row) {
84         for (int col = 0; col < 4; ++col) {
85             placeholderMatrix->setDouble(row, col, row * col);
86         }
87     }
88 
89     // Use placement-new syntax to trigger the constructor on top of the heap
90     // address we already initialized. This allows us to check that the
91     // constructor did avoid initializing the matrix contents.
92     SkMatrix44* testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kUninitialized_Constructor);
93     REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
94     REPORTER_ASSERT(reporter, !testMatrix->isIdentity());
95     for (int row = 0; row < 4; ++row) {
96         for (int col = 0; col < 4; ++col) {
97             REPORTER_ASSERT(reporter, nearly_equal_double(row * col, testMatrix->getDouble(row, col)));
98         }
99     }
100 
101     // Verify that kIdentity_Constructor really does initialize to an identity matrix.
102     testMatrix = 0;
103     testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kIdentity_Constructor);
104     REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
105     REPORTER_ASSERT(reporter, testMatrix->isIdentity());
106     REPORTER_ASSERT(reporter, *testMatrix == SkMatrix44::I());
107 }
108 
test_translate(skiatest::Reporter * reporter)109 static void test_translate(skiatest::Reporter* reporter) {
110     SkMatrix44 mat, inverse;
111 
112     mat.setTranslate(0, 0, 0);
113     REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
114     mat.setTranslate(1, 2, 3);
115     REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kTranslate_Mask));
116     REPORTER_ASSERT(reporter, mat.invert(&inverse));
117     REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kTranslate_Mask));
118 
119     SkMatrix44 a, b, c;
120     a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
121     b.setTranslate(10, 11, 12);
122 
123     c.setConcat(a, b);
124     mat = a;
125     mat.preTranslate(10, 11, 12);
126     REPORTER_ASSERT(reporter, mat == c);
127 
128     c.setConcat(b, a);
129     mat = a;
130     mat.postTranslate(10, 11, 12);
131     REPORTER_ASSERT(reporter, mat == c);
132 }
133 
test_scale(skiatest::Reporter * reporter)134 static void test_scale(skiatest::Reporter* reporter) {
135     SkMatrix44 mat, inverse;
136 
137     mat.setScale(1, 1, 1);
138     REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
139     mat.setScale(1, 2, 3);
140     REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kScale_Mask));
141     REPORTER_ASSERT(reporter, mat.invert(&inverse));
142     REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kScale_Mask));
143 
144     SkMatrix44 a, b, c;
145     a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
146     b.setScale(10, 11, 12);
147 
148     c.setConcat(a, b);
149     mat = a;
150     mat.preScale(10, 11, 12);
151     REPORTER_ASSERT(reporter, mat == c);
152 
153     c.setConcat(b, a);
154     mat = a;
155     mat.postScale(10, 11, 12);
156     REPORTER_ASSERT(reporter, mat == c);
157 }
158 
make_i(SkMatrix44 * mat)159 static void make_i(SkMatrix44* mat) { mat->setIdentity(); }
make_t(SkMatrix44 * mat)160 static void make_t(SkMatrix44* mat) { mat->setTranslate(1, 2, 3); }
make_s(SkMatrix44 * mat)161 static void make_s(SkMatrix44* mat) { mat->setScale(1, 2, 3); }
make_st(SkMatrix44 * mat)162 static void make_st(SkMatrix44* mat) {
163     mat->setScale(1, 2, 3);
164     mat->postTranslate(1, 2, 3);
165 }
make_a(SkMatrix44 * mat)166 static void make_a(SkMatrix44* mat) {
167     mat->setRotateDegreesAbout(1, 2, 3, 45);
168 }
make_p(SkMatrix44 * mat)169 static void make_p(SkMatrix44* mat) {
170     SkMScalar data[] = {
171         1, 2, 3, 4, 5, 6, 7, 8,
172         1, 2, 3, 4, 5, 6, 7, 8,
173     };
174     mat->setRowMajor(data);
175 }
176 
177 typedef void (*Make44Proc)(SkMatrix44*);
178 
179 static const Make44Proc gMakeProcs[] = {
180     make_i, make_t, make_s, make_st, make_a, make_p
181 };
182 
test_map2(skiatest::Reporter * reporter,const SkMatrix44 & mat)183 static void test_map2(skiatest::Reporter* reporter, const SkMatrix44& mat) {
184     SkMScalar src2[] = { 1, 2 };
185     SkMScalar src4[] = { src2[0], src2[1], 0, 1 };
186     SkMScalar dstA[4], dstB[4];
187 
188     for (int i = 0; i < 4; ++i) {
189         dstA[i] = 123456789;
190         dstB[i] = 987654321;
191     }
192 
193     mat.map2(src2, 1, dstA);
194     mat.mapMScalars(src4, dstB);
195 
196     for (int i = 0; i < 4; ++i) {
197         REPORTER_ASSERT(reporter, dstA[i] == dstB[i]);
198     }
199 }
200 
test_map2(skiatest::Reporter * reporter)201 static void test_map2(skiatest::Reporter* reporter) {
202     SkMatrix44 mat;
203 
204     for (size_t i = 0; i < SK_ARRAY_COUNT(gMakeProcs); ++i) {
205         gMakeProcs[i](&mat);
206         test_map2(reporter, mat);
207     }
208 }
209 
test_gettype(skiatest::Reporter * reporter)210 static void test_gettype(skiatest::Reporter* reporter) {
211     SkMatrix44 matrix;
212 
213     REPORTER_ASSERT(reporter, matrix.isIdentity());
214     REPORTER_ASSERT(reporter, SkMatrix44::kIdentity_Mask == matrix.getType());
215 
216     int expectedMask;
217 
218     matrix.set(1, 1, 0);
219     expectedMask = SkMatrix44::kScale_Mask;
220     REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
221 
222     matrix.set(0, 3, 1);    // translate-x
223     expectedMask |= SkMatrix44::kTranslate_Mask;
224     REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
225 
226     matrix.set(2, 0, 1);
227     expectedMask |= SkMatrix44::kAffine_Mask;
228     REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
229 
230     matrix.set(3, 2, 1);
231     REPORTER_ASSERT(reporter, matrix.getType() & SkMatrix44::kPerspective_Mask);
232 }
233 
test_common_angles(skiatest::Reporter * reporter)234 static void test_common_angles(skiatest::Reporter* reporter) {
235     SkMatrix44 rot;
236     // Test precision of rotation in common cases
237     int common_angles[] = { 0, 90, -90, 180, -180, 270, -270, 360, -360 };
238     for (int i = 0; i < 9; ++i) {
239         rot.setRotateDegreesAbout(0, 0, -1, SkIntToScalar(common_angles[i]));
240 
241         SkMatrix rot3x3 = rot;
242         REPORTER_ASSERT(reporter, rot3x3.rectStaysRect());
243     }
244 }
245 
test_concat(skiatest::Reporter * reporter)246 static void test_concat(skiatest::Reporter* reporter) {
247     int i;
248     SkMatrix44 a, b, c, d;
249 
250     a.setTranslate(10, 10, 10);
251     b.setScale(2, 2, 2);
252 
253     SkScalar src[8] = {
254         0, 0, 0, 1,
255         1, 1, 1, 1
256     };
257     SkScalar dst[8];
258 
259     c.setConcat(a, b);
260 
261     d = a;
262     d.preConcat(b);
263     REPORTER_ASSERT(reporter, d == c);
264 
265     c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
266     for (i = 0; i < 3; ++i) {
267         REPORTER_ASSERT(reporter, 10 == dst[i]);
268         REPORTER_ASSERT(reporter, 12 == dst[i + 4]);
269     }
270 
271     c.setConcat(b, a);
272 
273     d = a;
274     d.postConcat(b);
275     REPORTER_ASSERT(reporter, d == c);
276 
277     c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
278     for (i = 0; i < 3; ++i) {
279         REPORTER_ASSERT(reporter, 20 == dst[i]);
280         REPORTER_ASSERT(reporter, 22 == dst[i + 4]);
281     }
282 }
283 
test_determinant(skiatest::Reporter * reporter)284 static void test_determinant(skiatest::Reporter* reporter) {
285     SkMatrix44 a;
286     REPORTER_ASSERT(reporter, nearly_equal_double(1, a.determinant()));
287     a.set(1, 1, 2);
288     REPORTER_ASSERT(reporter, nearly_equal_double(2, a.determinant()));
289     SkMatrix44 b;
290     REPORTER_ASSERT(reporter, a.invert(&b));
291     REPORTER_ASSERT(reporter, nearly_equal_double(0.5, b.determinant()));
292     SkMatrix44 c = b = a;
293     c.set(0, 1, 4);
294     b.set(1, 0, 4);
295     REPORTER_ASSERT(reporter,
296                     nearly_equal_double(a.determinant(),
297                                         b.determinant()));
298     SkMatrix44 d = a;
299     d.set(0, 0, 8);
300     REPORTER_ASSERT(reporter, nearly_equal_double(16, d.determinant()));
301 
302     SkMatrix44 e = a;
303     e.postConcat(d);
304     REPORTER_ASSERT(reporter, nearly_equal_double(32, e.determinant()));
305     e.set(0, 0, 0);
306     REPORTER_ASSERT(reporter, nearly_equal_double(0, e.determinant()));
307 }
308 
test_transpose(skiatest::Reporter * reporter)309 static void test_transpose(skiatest::Reporter* reporter) {
310     SkMatrix44 a;
311     SkMatrix44 b;
312 
313     int i = 0;
314     for (int row = 0; row < 4; ++row) {
315         for (int col = 0; col < 4; ++col) {
316             a.setDouble(row, col, i);
317             b.setDouble(col, row, i++);
318         }
319     }
320 
321     a.transpose();
322     REPORTER_ASSERT(reporter, nearly_equal(a, b));
323 }
324 
test_get_set_double(skiatest::Reporter * reporter)325 static void test_get_set_double(skiatest::Reporter* reporter) {
326     SkMatrix44 a;
327     for (int row = 0; row < 4; ++row) {
328         for (int col = 0; col < 4; ++col) {
329             a.setDouble(row, col, 3.141592653589793);
330             REPORTER_ASSERT(reporter,
331                             nearly_equal_double(3.141592653589793,
332                                                 a.getDouble(row, col)));
333             a.setDouble(row, col, 0);
334             REPORTER_ASSERT(reporter,
335                             nearly_equal_double(0, a.getDouble(row, col)));
336         }
337     }
338 }
339 
test_set_row_col_major(skiatest::Reporter * reporter)340 static void test_set_row_col_major(skiatest::Reporter* reporter) {
341     SkMatrix44 a, b, c, d;
342     for (int row = 0; row < 4; ++row) {
343         for (int col = 0; col < 4; ++col) {
344             a.setDouble(row, col, row * 4 + col);
345         }
346     }
347 
348     double bufferd[16];
349     float bufferf[16];
350     a.asColMajord(bufferd);
351     b.setColMajord(bufferd);
352     REPORTER_ASSERT(reporter, nearly_equal(a, b));
353     b.setRowMajord(bufferd);
354     b.transpose();
355     REPORTER_ASSERT(reporter, nearly_equal(a, b));
356     a.asColMajorf(bufferf);
357     b.setColMajorf(bufferf);
358     REPORTER_ASSERT(reporter, nearly_equal(a, b));
359     b.setRowMajorf(bufferf);
360     b.transpose();
361     REPORTER_ASSERT(reporter, nearly_equal(a, b));
362 }
363 
TestMatrix44(skiatest::Reporter * reporter)364 static void TestMatrix44(skiatest::Reporter* reporter) {
365     SkMatrix44 mat, inverse, iden1, iden2, rot;
366 
367     mat.reset();
368     mat.setTranslate(1, 1, 1);
369     mat.invert(&inverse);
370     iden1.setConcat(mat, inverse);
371     REPORTER_ASSERT(reporter, is_identity(iden1));
372 
373     mat.setScale(2, 2, 2);
374     mat.invert(&inverse);
375     iden1.setConcat(mat, inverse);
376     REPORTER_ASSERT(reporter, is_identity(iden1));
377 
378     mat.setScale(SK_MScalar1/2, SK_MScalar1/2, SK_MScalar1/2);
379     mat.invert(&inverse);
380     iden1.setConcat(mat, inverse);
381     REPORTER_ASSERT(reporter, is_identity(iden1));
382 
383     mat.setScale(3, 3, 3);
384     rot.setRotateDegreesAbout(0, 0, -1, 90);
385     mat.postConcat(rot);
386     REPORTER_ASSERT(reporter, mat.invert(NULL));
387     mat.invert(&inverse);
388     iden1.setConcat(mat, inverse);
389     REPORTER_ASSERT(reporter, is_identity(iden1));
390     iden2.setConcat(inverse, mat);
391     REPORTER_ASSERT(reporter, is_identity(iden2));
392 
393     // test rol/col Major getters
394     {
395         mat.setTranslate(2, 3, 4);
396         float dataf[16];
397         double datad[16];
398 
399         mat.asColMajorf(dataf);
400         assert16<float>(reporter, dataf,
401                  1, 0, 0, 0,
402                  0, 1, 0, 0,
403                  0, 0, 1, 0,
404                  2, 3, 4, 1);
405         mat.asColMajord(datad);
406         assert16<double>(reporter, datad, 1, 0, 0, 0,
407                         0, 1, 0, 0,
408                         0, 0, 1, 0,
409                         2, 3, 4, 1);
410         mat.asRowMajorf(dataf);
411         assert16<float>(reporter, dataf, 1, 0, 0, 2,
412                         0, 1, 0, 3,
413                         0, 0, 1, 4,
414                         0, 0, 0, 1);
415         mat.asRowMajord(datad);
416         assert16<double>(reporter, datad, 1, 0, 0, 2,
417                         0, 1, 0, 3,
418                         0, 0, 1, 4,
419                         0, 0, 0, 1);
420     }
421 
422     test_concat(reporter);
423 
424     if (false) { // avoid bit rot, suppress warning (working on making this pass)
425         test_common_angles(reporter);
426     }
427 
428     test_constructor(reporter);
429     test_gettype(reporter);
430     test_determinant(reporter);
431     test_transpose(reporter);
432     test_get_set_double(reporter);
433     test_set_row_col_major(reporter);
434     test_translate(reporter);
435     test_scale(reporter);
436     test_map2(reporter);
437 }
438 
439 #include "TestClassDef.h"
440 DEFINE_TESTCLASS("Matrix44", Matrix44TestClass, TestMatrix44)
441