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