blob: ed8770ae6cec61169cf9ac33e793cc6504a4d502 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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 */
reed@google.com7d683352012-12-03 21:19:52 +00007
reed@google.com125002a2011-06-09 19:13:41 +00008#include "Test.h"
9#include "SkMatrix44.h"
10
vollick@chromium.org3959a762012-11-13 15:08:22 +000011static 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
reed@google.comda9fac02011-06-13 14:46:52 +000019static bool nearly_equal_scalar(SkMScalar a, SkMScalar b) {
reed@google.com125002a2011-06-09 19:13:41 +000020 // 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 SkScalarAbs(a - b) <= tolerance;
29}
30
reed@google.comda9fac02011-06-13 14:46:52 +000031template <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
reed@google.com125002a2011-06-09 19:13:41 +000057static 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))) {
reed@google.comda9fac02011-06-13 14:46:52 +000061 printf("not equal %g %g\n", a.get(i, j), b.get(i, j));
reed@google.com125002a2011-06-09 19:13:41 +000062 return false;
63 }
64 }
65 }
66 return true;
67}
68
69static bool is_identity(const SkMatrix44& m) {
70 SkMatrix44 identity;
71 identity.reset();
72 return nearly_equal(m, identity);
73}
74
reed@google.com7d683352012-12-03 21:19:52 +000075static void test_gettype(skiatest::Reporter* reporter) {
76 SkMatrix44 matrix;
77
78 REPORTER_ASSERT(reporter, matrix.isIdentity());
79 REPORTER_ASSERT(reporter, SkMatrix44::kIdentity_Mask == matrix.getType());
80
81 int expectedMask;
82
83 matrix.set(1, 1, 0);
84 expectedMask = SkMatrix44::kScale_Mask;
85 REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
86
87 matrix.set(0, 3, 1); // translate-x
88 expectedMask |= SkMatrix44::kTranslate_Mask;
89 REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
90
91 matrix.set(2, 0, 1);
92 expectedMask |= SkMatrix44::kAffine_Mask;
93 REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
94
95 matrix.set(3, 2, 1);
96 REPORTER_ASSERT(reporter, matrix.getType() & SkMatrix44::kPerspective_Mask);
97}
98
reed@google.com6f2b44d2011-06-24 18:13:39 +000099static void test_common_angles(skiatest::Reporter* reporter) {
100 SkMatrix44 rot;
101 // Test precision of rotation in common cases
102 int common_angles[] = { 0, 90, -90, 180, -180, 270, -270, 360, -360 };
103 for (int i = 0; i < 9; ++i) {
robertphillips@google.com09042b82012-04-06 20:01:46 +0000104 rot.setRotateDegreesAbout(0, 0, -1, SkIntToScalar(common_angles[i]));
reed@google.com6f2b44d2011-06-24 18:13:39 +0000105
106 SkMatrix rot3x3 = rot;
107 REPORTER_ASSERT(reporter, rot3x3.rectStaysRect());
108 }
109}
110
reed@google.com80b577e2012-11-09 21:25:06 +0000111static void test_concat(skiatest::Reporter* reporter) {
112 int i;
113 SkMatrix44 a, b, c, d;
114
115 a.setTranslate(10, 10, 10);
116 b.setScale(2, 2, 2);
117
118 SkScalar src[8] = {
119 0, 0, 0, 1,
120 1, 1, 1, 1
121 };
122 SkScalar dst[8];
123
124 c.setConcat(a, b);
125
126 d = a;
127 d.preConcat(b);
128 REPORTER_ASSERT(reporter, d == c);
skia.committer@gmail.com453995e2012-11-10 02:01:26 +0000129
reed@google.com1ea95be2012-11-09 21:39:48 +0000130 c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
reed@google.com80b577e2012-11-09 21:25:06 +0000131 for (i = 0; i < 3; ++i) {
132 REPORTER_ASSERT(reporter, 10 == dst[i]);
133 REPORTER_ASSERT(reporter, 12 == dst[i + 4]);
134 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +0000135
reed@google.com80b577e2012-11-09 21:25:06 +0000136 c.setConcat(b, a);
137
138 d = a;
139 d.postConcat(b);
140 REPORTER_ASSERT(reporter, d == c);
141
reed@google.com1ea95be2012-11-09 21:39:48 +0000142 c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
reed@google.com80b577e2012-11-09 21:25:06 +0000143 for (i = 0; i < 3; ++i) {
144 REPORTER_ASSERT(reporter, 20 == dst[i]);
145 REPORTER_ASSERT(reporter, 22 == dst[i + 4]);
146 }
147}
148
vollick@chromium.org3959a762012-11-13 15:08:22 +0000149static void test_determinant(skiatest::Reporter* reporter) {
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000150 SkMatrix44 a;
151 REPORTER_ASSERT(reporter, nearly_equal_double(1, a.determinant()));
reed@google.com7d683352012-12-03 21:19:52 +0000152 a.set(1, 1, 2);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000153 REPORTER_ASSERT(reporter, nearly_equal_double(2, a.determinant()));
154 SkMatrix44 b;
155 REPORTER_ASSERT(reporter, a.invert(&b));
156 REPORTER_ASSERT(reporter, nearly_equal_double(0.5, b.determinant()));
157 SkMatrix44 c = b = a;
reed@google.com7d683352012-12-03 21:19:52 +0000158 c.set(0, 1, 4);
159 b.set(1, 0, 4);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000160 REPORTER_ASSERT(reporter,
161 nearly_equal_double(a.determinant(),
162 b.determinant()));
163 SkMatrix44 d = a;
reed@google.com7d683352012-12-03 21:19:52 +0000164 d.set(0, 0, 8);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000165 REPORTER_ASSERT(reporter, nearly_equal_double(16, d.determinant()));
vollick@chromium.org3959a762012-11-13 15:08:22 +0000166
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000167 SkMatrix44 e = a;
168 e.postConcat(d);
169 REPORTER_ASSERT(reporter, nearly_equal_double(32, e.determinant()));
reed@google.com7d683352012-12-03 21:19:52 +0000170 e.set(0, 0, 0);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000171 REPORTER_ASSERT(reporter, nearly_equal_double(0, e.determinant()));
vollick@chromium.org3959a762012-11-13 15:08:22 +0000172}
173
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000174static void test_transpose(skiatest::Reporter* reporter) {
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000175 SkMatrix44 a;
176 SkMatrix44 b;
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000177
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000178 int i = 0;
179 for (int row = 0; row < 4; ++row) {
180 for (int col = 0; col < 4; ++col) {
181 a.setDouble(row, col, i);
182 b.setDouble(col, row, i++);
183 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000184 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000185
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000186 a.transpose();
187 REPORTER_ASSERT(reporter, nearly_equal(a, b));
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000188}
189
190static void test_get_set_double(skiatest::Reporter* reporter) {
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000191 SkMatrix44 a;
192 for (int row = 0; row < 4; ++row) {
193 for (int col = 0; col < 4; ++col) {
194 a.setDouble(row, col, 3.141592653589793);
195 REPORTER_ASSERT(reporter,
196 nearly_equal_double(3.141592653589793,
197 a.getDouble(row, col)));
198 a.setDouble(row, col, 0);
199 REPORTER_ASSERT(reporter,
200 nearly_equal_double(0, a.getDouble(row, col)));
201 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000202 }
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000203}
204
205static void test_set_row_col_major(skiatest::Reporter* reporter) {
206 SkMatrix44 a, b, c, d;
reed@google.com7d683352012-12-03 21:19:52 +0000207 for (int row = 0; row < 4; ++row) {
208 for (int col = 0; col < 4; ++col) {
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000209 a.setDouble(row, col, row * 4 + col);
reed@google.com7d683352012-12-03 21:19:52 +0000210 }
211 }
212
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000213 double bufferd[16];
214 float bufferf[16];
215 a.asColMajord(bufferd);
216 b.setColMajord(bufferd);
217 REPORTER_ASSERT(reporter, nearly_equal(a, b));
218 b.setRowMajord(bufferd);
219 b.transpose();
220 REPORTER_ASSERT(reporter, nearly_equal(a, b));
221 a.asColMajorf(bufferf);
222 b.setColMajorf(bufferf);
223 REPORTER_ASSERT(reporter, nearly_equal(a, b));
224 b.setRowMajorf(bufferf);
225 b.transpose();
226 REPORTER_ASSERT(reporter, nearly_equal(a, b));
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000227}
228
caryclark@google.com42639cd2012-06-06 12:03:39 +0000229static void TestMatrix44(skiatest::Reporter* reporter) {
reed@google.com125002a2011-06-09 19:13:41 +0000230 SkMatrix44 mat, inverse, iden1, iden2, rot;
231
232 mat.reset();
reed@google.com7d683352012-12-03 21:19:52 +0000233 mat.setTranslate(1, 1, 1);
reed@google.com125002a2011-06-09 19:13:41 +0000234 mat.invert(&inverse);
235 iden1.setConcat(mat, inverse);
236 REPORTER_ASSERT(reporter, is_identity(iden1));
237
reed@google.com7d683352012-12-03 21:19:52 +0000238 mat.setScale(2, 2, 2);
reed@google.com125002a2011-06-09 19:13:41 +0000239 mat.invert(&inverse);
240 iden1.setConcat(mat, inverse);
241 REPORTER_ASSERT(reporter, is_identity(iden1));
242
reed@google.com7d683352012-12-03 21:19:52 +0000243 mat.setScale(SK_MScalar1/2, SK_MScalar1/2, SK_MScalar1/2);
reed@google.com125002a2011-06-09 19:13:41 +0000244 mat.invert(&inverse);
245 iden1.setConcat(mat, inverse);
246 REPORTER_ASSERT(reporter, is_identity(iden1));
247
reed@google.com7d683352012-12-03 21:19:52 +0000248 mat.setScale(3, 3, 3);
249 rot.setRotateDegreesAbout(0, 0, -1, 90);
reed@google.com125002a2011-06-09 19:13:41 +0000250 mat.postConcat(rot);
251 REPORTER_ASSERT(reporter, mat.invert(NULL));
252 mat.invert(&inverse);
253 iden1.setConcat(mat, inverse);
254 REPORTER_ASSERT(reporter, is_identity(iden1));
255 iden2.setConcat(inverse, mat);
256 REPORTER_ASSERT(reporter, is_identity(iden2));
reed@google.comda9fac02011-06-13 14:46:52 +0000257
258 // test rol/col Major getters
259 {
260 mat.setTranslate(2, 3, 4);
261 float dataf[16];
262 double datad[16];
rmistry@google.comd6176b02012-08-23 18:14:13 +0000263
reed@google.comda9fac02011-06-13 14:46:52 +0000264 mat.asColMajorf(dataf);
265 assert16<float>(reporter, dataf,
266 1, 0, 0, 0,
267 0, 1, 0, 0,
268 0, 0, 1, 0,
269 2, 3, 4, 1);
270 mat.asColMajord(datad);
271 assert16<double>(reporter, datad, 1, 0, 0, 0,
272 0, 1, 0, 0,
273 0, 0, 1, 0,
274 2, 3, 4, 1);
275 mat.asRowMajorf(dataf);
276 assert16<float>(reporter, dataf, 1, 0, 0, 2,
277 0, 1, 0, 3,
278 0, 0, 1, 4,
279 0, 0, 0, 1);
280 mat.asRowMajord(datad);
281 assert16<double>(reporter, datad, 1, 0, 0, 2,
282 0, 1, 0, 3,
283 0, 0, 1, 4,
284 0, 0, 0, 1);
285 }
reed@google.com6f2b44d2011-06-24 18:13:39 +0000286
reed@google.com80b577e2012-11-09 21:25:06 +0000287 test_concat(reporter);
288
caryclark@google.com42639cd2012-06-06 12:03:39 +0000289 if (false) { // avoid bit rot, suppress warning (working on making this pass)
290 test_common_angles(reporter);
291 }
vollick@chromium.org3959a762012-11-13 15:08:22 +0000292
reed@google.com7d683352012-12-03 21:19:52 +0000293 test_gettype(reporter);
vollick@chromium.org3959a762012-11-13 15:08:22 +0000294 test_determinant(reporter);
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000295 test_transpose(reporter);
296 test_get_set_double(reporter);
reed@google.com7d683352012-12-03 21:19:52 +0000297 test_set_row_col_major(reporter);
reed@google.com125002a2011-06-09 19:13:41 +0000298}
299
300#include "TestClassDef.h"
301DEFINE_TESTCLASS("Matrix44", Matrix44TestClass, TestMatrix44)