blob: 51a6e7f9503b5eb79ecec11fe00efa111bb11cc4 [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
commit-bot@chromium.org722555b2013-10-05 01:16:30 +000019static bool nearly_equal_mscalar(SkMScalar a, SkMScalar b) {
20 const SkMScalar tolerance = SK_MScalar1 / 200000;
21
22 return SkTAbs<SkMScalar>(a - b) <= tolerance;
23}
24
25static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
reed@google.com125002a2011-06-09 19:13:41 +000026 // Note that we get more compounded error for multiple operations when
27 // SK_SCALAR_IS_FIXED.
28#ifdef SK_SCALAR_IS_FLOAT
29 const SkScalar tolerance = SK_Scalar1 / 200000;
30#else
31 const SkScalar tolerance = SK_Scalar1 / 1024;
32#endif
33
commit-bot@chromium.org722555b2013-10-05 01:16:30 +000034 return SkScalarAbs(a - b) <= tolerance;
reed@google.com125002a2011-06-09 19:13:41 +000035}
36
reed@google.comda9fac02011-06-13 14:46:52 +000037template <typename T> void assert16(skiatest::Reporter* reporter, const T data[],
38 T m0, T m1, T m2, T m3,
39 T m4, T m5, T m6, T m7,
40 T m8, T m9, T m10, T m11,
41 T m12, T m13, T m14, T m15) {
42 REPORTER_ASSERT(reporter, data[0] == m0);
43 REPORTER_ASSERT(reporter, data[1] == m1);
44 REPORTER_ASSERT(reporter, data[2] == m2);
45 REPORTER_ASSERT(reporter, data[3] == m3);
46
47 REPORTER_ASSERT(reporter, data[4] == m4);
48 REPORTER_ASSERT(reporter, data[5] == m5);
49 REPORTER_ASSERT(reporter, data[6] == m6);
50 REPORTER_ASSERT(reporter, data[7] == m7);
51
52 REPORTER_ASSERT(reporter, data[8] == m8);
53 REPORTER_ASSERT(reporter, data[9] == m9);
54 REPORTER_ASSERT(reporter, data[10] == m10);
55 REPORTER_ASSERT(reporter, data[11] == m11);
56
57 REPORTER_ASSERT(reporter, data[12] == m12);
58 REPORTER_ASSERT(reporter, data[13] == m13);
59 REPORTER_ASSERT(reporter, data[14] == m14);
60 REPORTER_ASSERT(reporter, data[15] == m15);
61}
62
reed@google.com125002a2011-06-09 19:13:41 +000063static bool nearly_equal(const SkMatrix44& a, const SkMatrix44& b) {
64 for (int i = 0; i < 4; ++i) {
65 for (int j = 0; j < 4; ++j) {
commit-bot@chromium.org722555b2013-10-05 01:16:30 +000066 if (!nearly_equal_mscalar(a.get(i, j), b.get(i, j))) {
bungeman@google.comfab44db2013-10-11 18:50:45 +000067 SkDebugf("not equal %g %g\n", a.get(i, j), b.get(i, j));
reed@google.com125002a2011-06-09 19:13:41 +000068 return false;
69 }
70 }
71 }
72 return true;
73}
74
75static bool is_identity(const SkMatrix44& m) {
reed@google.com44699382013-10-31 17:28:30 +000076 SkMatrix44 identity(SkMatrix44::kIdentity_Constructor);
reed@google.com125002a2011-06-09 19:13:41 +000077 return nearly_equal(m, identity);
78}
79
reed@google.com99b5c7f2012-12-05 22:13:59 +000080///////////////////////////////////////////////////////////////////////////////
81static bool bits_isonly(int value, int mask) {
82 return 0 == (value & ~mask);
83}
84
vollick@chromium.org57a54e32012-12-10 20:16:10 +000085static void test_constructor(skiatest::Reporter* reporter) {
86 // Allocate a matrix on the heap
reed@google.com44699382013-10-31 17:28:30 +000087 SkMatrix44* placeholderMatrix = new SkMatrix44(SkMatrix44::kUninitialized_Constructor);
robertphillips@google.com35300c42013-03-21 17:38:49 +000088 SkAutoTDelete<SkMatrix44> deleteMe(placeholderMatrix);
89
vollick@chromium.org57a54e32012-12-10 20:16:10 +000090 for (int row = 0; row < 4; ++row) {
91 for (int col = 0; col < 4; ++col) {
92 placeholderMatrix->setDouble(row, col, row * col);
93 }
94 }
95
96 // Use placement-new syntax to trigger the constructor on top of the heap
97 // address we already initialized. This allows us to check that the
98 // constructor did avoid initializing the matrix contents.
99 SkMatrix44* testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kUninitialized_Constructor);
100 REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
101 REPORTER_ASSERT(reporter, !testMatrix->isIdentity());
102 for (int row = 0; row < 4; ++row) {
103 for (int col = 0; col < 4; ++col) {
104 REPORTER_ASSERT(reporter, nearly_equal_double(row * col, testMatrix->getDouble(row, col)));
105 }
106 }
107
108 // Verify that kIdentity_Constructor really does initialize to an identity matrix.
109 testMatrix = 0;
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000110 testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kIdentity_Constructor);
vollick@chromium.org57a54e32012-12-10 20:16:10 +0000111 REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
112 REPORTER_ASSERT(reporter, testMatrix->isIdentity());
113 REPORTER_ASSERT(reporter, *testMatrix == SkMatrix44::I());
114}
115
reed@google.com99b5c7f2012-12-05 22:13:59 +0000116static void test_translate(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000117 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
118 SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000119
120 mat.setTranslate(0, 0, 0);
121 REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
122 mat.setTranslate(1, 2, 3);
123 REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kTranslate_Mask));
124 REPORTER_ASSERT(reporter, mat.invert(&inverse));
125 REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kTranslate_Mask));
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000126
reed@google.com44699382013-10-31 17:28:30 +0000127 SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
128 SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
129 SkMatrix44 c(SkMatrix44::kUninitialized_Constructor);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000130 a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
131 b.setTranslate(10, 11, 12);
132
133 c.setConcat(a, b);
134 mat = a;
135 mat.preTranslate(10, 11, 12);
136 REPORTER_ASSERT(reporter, mat == c);
137
138 c.setConcat(b, a);
139 mat = a;
140 mat.postTranslate(10, 11, 12);
141 REPORTER_ASSERT(reporter, mat == c);
142}
143
144static void test_scale(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000145 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
146 SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor);
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000147
reed@google.com99b5c7f2012-12-05 22:13:59 +0000148 mat.setScale(1, 1, 1);
149 REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
150 mat.setScale(1, 2, 3);
151 REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kScale_Mask));
152 REPORTER_ASSERT(reporter, mat.invert(&inverse));
153 REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kScale_Mask));
154
reed@google.com44699382013-10-31 17:28:30 +0000155 SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
156 SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
157 SkMatrix44 c(SkMatrix44::kUninitialized_Constructor);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000158 a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
159 b.setScale(10, 11, 12);
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000160
reed@google.com99b5c7f2012-12-05 22:13:59 +0000161 c.setConcat(a, b);
162 mat = a;
163 mat.preScale(10, 11, 12);
164 REPORTER_ASSERT(reporter, mat == c);
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000165
reed@google.com99b5c7f2012-12-05 22:13:59 +0000166 c.setConcat(b, a);
167 mat = a;
168 mat.postScale(10, 11, 12);
169 REPORTER_ASSERT(reporter, mat == c);
170}
171
172static void make_i(SkMatrix44* mat) { mat->setIdentity(); }
173static void make_t(SkMatrix44* mat) { mat->setTranslate(1, 2, 3); }
174static void make_s(SkMatrix44* mat) { mat->setScale(1, 2, 3); }
175static void make_st(SkMatrix44* mat) {
176 mat->setScale(1, 2, 3);
177 mat->postTranslate(1, 2, 3);
178}
179static void make_a(SkMatrix44* mat) {
180 mat->setRotateDegreesAbout(1, 2, 3, 45);
181}
182static void make_p(SkMatrix44* mat) {
183 SkMScalar data[] = {
184 1, 2, 3, 4, 5, 6, 7, 8,
185 1, 2, 3, 4, 5, 6, 7, 8,
186 };
187 mat->setRowMajor(data);
188}
189
190typedef void (*Make44Proc)(SkMatrix44*);
191
192static const Make44Proc gMakeProcs[] = {
193 make_i, make_t, make_s, make_st, make_a, make_p
194};
195
196static void test_map2(skiatest::Reporter* reporter, const SkMatrix44& mat) {
197 SkMScalar src2[] = { 1, 2 };
198 SkMScalar src4[] = { src2[0], src2[1], 0, 1 };
199 SkMScalar dstA[4], dstB[4];
200
201 for (int i = 0; i < 4; ++i) {
202 dstA[i] = 123456789;
203 dstB[i] = 987654321;
204 }
205
206 mat.map2(src2, 1, dstA);
207 mat.mapMScalars(src4, dstB);
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000208
reed@google.com99b5c7f2012-12-05 22:13:59 +0000209 for (int i = 0; i < 4; ++i) {
210 REPORTER_ASSERT(reporter, dstA[i] == dstB[i]);
211 }
212}
213
214static void test_map2(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000215 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000216
217 for (size_t i = 0; i < SK_ARRAY_COUNT(gMakeProcs); ++i) {
218 gMakeProcs[i](&mat);
219 test_map2(reporter, mat);
220 }
221}
222
reed@google.com7d683352012-12-03 21:19:52 +0000223static void test_gettype(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000224 SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor);
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000225
reed@google.com7d683352012-12-03 21:19:52 +0000226 REPORTER_ASSERT(reporter, matrix.isIdentity());
227 REPORTER_ASSERT(reporter, SkMatrix44::kIdentity_Mask == matrix.getType());
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000228
reed@google.com7d683352012-12-03 21:19:52 +0000229 int expectedMask;
230
231 matrix.set(1, 1, 0);
232 expectedMask = SkMatrix44::kScale_Mask;
233 REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
234
235 matrix.set(0, 3, 1); // translate-x
236 expectedMask |= SkMatrix44::kTranslate_Mask;
237 REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
238
239 matrix.set(2, 0, 1);
240 expectedMask |= SkMatrix44::kAffine_Mask;
241 REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000242
reed@google.com7d683352012-12-03 21:19:52 +0000243 matrix.set(3, 2, 1);
244 REPORTER_ASSERT(reporter, matrix.getType() & SkMatrix44::kPerspective_Mask);
reed@google.com87f99cb2013-04-19 12:25:00 +0000245
246 // ensure that negative zero is treated as zero
247 SkMScalar dx = 0;
248 SkMScalar dy = 0;
249 SkMScalar dz = 0;
250 matrix.setTranslate(-dx, -dy, -dz);
251 REPORTER_ASSERT(reporter, matrix.isIdentity());
252 matrix.preTranslate(-dx, -dy, -dz);
253 REPORTER_ASSERT(reporter, matrix.isIdentity());
254 matrix.postTranslate(-dx, -dy, -dz);
255 REPORTER_ASSERT(reporter, matrix.isIdentity());
reed@google.com7d683352012-12-03 21:19:52 +0000256}
257
reed@google.com6f2b44d2011-06-24 18:13:39 +0000258static void test_common_angles(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000259 SkMatrix44 rot(SkMatrix44::kUninitialized_Constructor);
reed@google.com6f2b44d2011-06-24 18:13:39 +0000260 // Test precision of rotation in common cases
261 int common_angles[] = { 0, 90, -90, 180, -180, 270, -270, 360, -360 };
262 for (int i = 0; i < 9; ++i) {
robertphillips@google.com09042b82012-04-06 20:01:46 +0000263 rot.setRotateDegreesAbout(0, 0, -1, SkIntToScalar(common_angles[i]));
reed@google.com6f2b44d2011-06-24 18:13:39 +0000264
265 SkMatrix rot3x3 = rot;
266 REPORTER_ASSERT(reporter, rot3x3.rectStaysRect());
267 }
268}
269
reed@google.com80b577e2012-11-09 21:25:06 +0000270static void test_concat(skiatest::Reporter* reporter) {
271 int i;
reed@google.com44699382013-10-31 17:28:30 +0000272 SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
273 SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
274 SkMatrix44 c(SkMatrix44::kUninitialized_Constructor);
275 SkMatrix44 d(SkMatrix44::kUninitialized_Constructor);
reed@google.com80b577e2012-11-09 21:25:06 +0000276
277 a.setTranslate(10, 10, 10);
278 b.setScale(2, 2, 2);
279
280 SkScalar src[8] = {
281 0, 0, 0, 1,
282 1, 1, 1, 1
283 };
284 SkScalar dst[8];
285
286 c.setConcat(a, b);
287
288 d = a;
289 d.preConcat(b);
290 REPORTER_ASSERT(reporter, d == c);
skia.committer@gmail.com453995e2012-11-10 02:01:26 +0000291
reed@google.com1ea95be2012-11-09 21:39:48 +0000292 c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
reed@google.com80b577e2012-11-09 21:25:06 +0000293 for (i = 0; i < 3; ++i) {
294 REPORTER_ASSERT(reporter, 10 == dst[i]);
295 REPORTER_ASSERT(reporter, 12 == dst[i + 4]);
296 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +0000297
reed@google.com80b577e2012-11-09 21:25:06 +0000298 c.setConcat(b, a);
299
300 d = a;
301 d.postConcat(b);
302 REPORTER_ASSERT(reporter, d == c);
303
reed@google.com1ea95be2012-11-09 21:39:48 +0000304 c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
reed@google.com80b577e2012-11-09 21:25:06 +0000305 for (i = 0; i < 3; ++i) {
306 REPORTER_ASSERT(reporter, 20 == dst[i]);
307 REPORTER_ASSERT(reporter, 22 == dst[i + 4]);
308 }
309}
310
vollick@chromium.org3959a762012-11-13 15:08:22 +0000311static void test_determinant(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000312 SkMatrix44 a(SkMatrix44::kIdentity_Constructor);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000313 REPORTER_ASSERT(reporter, nearly_equal_double(1, a.determinant()));
reed@google.com7d683352012-12-03 21:19:52 +0000314 a.set(1, 1, 2);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000315 REPORTER_ASSERT(reporter, nearly_equal_double(2, a.determinant()));
reed@google.com44699382013-10-31 17:28:30 +0000316 SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000317 REPORTER_ASSERT(reporter, a.invert(&b));
318 REPORTER_ASSERT(reporter, nearly_equal_double(0.5, b.determinant()));
319 SkMatrix44 c = b = a;
reed@google.com7d683352012-12-03 21:19:52 +0000320 c.set(0, 1, 4);
321 b.set(1, 0, 4);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000322 REPORTER_ASSERT(reporter,
323 nearly_equal_double(a.determinant(),
324 b.determinant()));
325 SkMatrix44 d = a;
reed@google.com7d683352012-12-03 21:19:52 +0000326 d.set(0, 0, 8);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000327 REPORTER_ASSERT(reporter, nearly_equal_double(16, d.determinant()));
vollick@chromium.org3959a762012-11-13 15:08:22 +0000328
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000329 SkMatrix44 e = a;
330 e.postConcat(d);
331 REPORTER_ASSERT(reporter, nearly_equal_double(32, e.determinant()));
reed@google.com7d683352012-12-03 21:19:52 +0000332 e.set(0, 0, 0);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000333 REPORTER_ASSERT(reporter, nearly_equal_double(0, e.determinant()));
vollick@chromium.org3959a762012-11-13 15:08:22 +0000334}
335
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000336static void test_invert(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000337 SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000338 double inverseData[16];
339
reed@google.com44699382013-10-31 17:28:30 +0000340 SkMatrix44 identity(SkMatrix44::kIdentity_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000341 identity.invert(&inverse);
342 inverse.asRowMajord(inverseData);
343 assert16<double>(reporter, inverseData,
344 1, 0, 0, 0,
345 0, 1, 0, 0,
346 0, 0, 1, 0,
347 0, 0, 0, 1);
348
reed@google.com44699382013-10-31 17:28:30 +0000349 SkMatrix44 translation(SkMatrix44::kUninitialized_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000350 translation.setTranslate(2, 3, 4);
351 translation.invert(&inverse);
352 inverse.asRowMajord(inverseData);
353 assert16<double>(reporter, inverseData,
354 1, 0, 0, -2,
355 0, 1, 0, -3,
356 0, 0, 1, -4,
357 0, 0, 0, 1);
358
reed@google.com44699382013-10-31 17:28:30 +0000359 SkMatrix44 scale(SkMatrix44::kUninitialized_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000360 scale.setScale(2, 4, 8);
361 scale.invert(&inverse);
362 inverse.asRowMajord(inverseData);
363 assert16<double>(reporter, inverseData,
364 0.5, 0, 0, 0,
365 0, 0.25, 0, 0,
366 0, 0, 0.125, 0,
367 0, 0, 0, 1);
368
reed@google.com44699382013-10-31 17:28:30 +0000369 SkMatrix44 scaleTranslation(SkMatrix44::kUninitialized_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000370 scaleTranslation.setScale(10, 100, 1000);
371 scaleTranslation.preTranslate(2, 3, 4);
372 scaleTranslation.invert(&inverse);
373 inverse.asRowMajord(inverseData);
374 assert16<double>(reporter, inverseData,
375 0.1, 0, 0, -2,
376 0, 0.01, 0, -3,
377 0, 0, 0.001, -4,
378 0, 0, 0, 1);
379
reed@google.com44699382013-10-31 17:28:30 +0000380 SkMatrix44 rotation(SkMatrix44::kUninitialized_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000381 rotation.setRotateDegreesAbout(0, 0, 1, 90);
382 rotation.invert(&inverse);
reed@google.com44699382013-10-31 17:28:30 +0000383 SkMatrix44 expected(SkMatrix44::kUninitialized_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000384 double expectedInverseRotation[16] =
385 {0, 1, 0, 0,
386 -1, 0, 0, 0,
387 0, 0, 1, 0,
388 0, 0, 0, 1};
389 expected.setRowMajord(expectedInverseRotation);
390 REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
skia.committer@gmail.comb74bdf02013-08-21 07:01:29 +0000391
reed@google.com44699382013-10-31 17:28:30 +0000392 SkMatrix44 affine(SkMatrix44::kUninitialized_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000393 affine.setRotateDegreesAbout(0, 0, 1, 90);
394 affine.preScale(10, 20, 100);
395 affine.preTranslate(2, 3, 4);
396 affine.invert(&inverse);
397 double expectedInverseAffine[16] =
398 {0, 0.1, 0, -2,
399 -0.05, 0, 0, -3,
400 0, 0, 0.01, -4,
401 0, 0, 0, 1};
402 expected.setRowMajord(expectedInverseAffine);
403 REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
404
reed@google.com44699382013-10-31 17:28:30 +0000405 SkMatrix44 perspective(SkMatrix44::kIdentity_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000406 perspective.setDouble(3, 2, 1.0);
407 perspective.invert(&inverse);
408 double expectedInversePerspective[16] =
409 {1, 0, 0, 0,
410 0, 1, 0, 0,
411 0, 0, 1, 0,
412 0, 0, -1, 1};
413 expected.setRowMajord(expectedInversePerspective);
414 REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
415
reed@google.com44699382013-10-31 17:28:30 +0000416 SkMatrix44 affineAndPerspective(SkMatrix44::kIdentity_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000417 affineAndPerspective.setDouble(3, 2, 1.0);
418 affineAndPerspective.preScale(10, 20, 100);
419 affineAndPerspective.preTranslate(2, 3, 4);
420 affineAndPerspective.invert(&inverse);
421 double expectedInverseAffineAndPerspective[16] =
422 {0.1, 0, 2, -2,
423 0, 0.05, 3, -3,
424 0, 0, 4.01, -4,
425 0, 0, -1, 1};
426 expected.setRowMajord(expectedInverseAffineAndPerspective);
427 REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
428}
429
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000430static void test_transpose(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000431 SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
432 SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000433
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000434 int i = 0;
435 for (int row = 0; row < 4; ++row) {
436 for (int col = 0; col < 4; ++col) {
437 a.setDouble(row, col, i);
438 b.setDouble(col, row, i++);
439 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000440 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000441
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000442 a.transpose();
443 REPORTER_ASSERT(reporter, nearly_equal(a, b));
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000444}
445
446static void test_get_set_double(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000447 SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000448 for (int row = 0; row < 4; ++row) {
449 for (int col = 0; col < 4; ++col) {
450 a.setDouble(row, col, 3.141592653589793);
451 REPORTER_ASSERT(reporter,
452 nearly_equal_double(3.141592653589793,
453 a.getDouble(row, col)));
454 a.setDouble(row, col, 0);
455 REPORTER_ASSERT(reporter,
456 nearly_equal_double(0, a.getDouble(row, col)));
457 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000458 }
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000459}
460
461static void test_set_row_col_major(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000462 SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
463 SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
464
reed@google.com7d683352012-12-03 21:19:52 +0000465 for (int row = 0; row < 4; ++row) {
466 for (int col = 0; col < 4; ++col) {
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000467 a.setDouble(row, col, row * 4 + col);
reed@google.com7d683352012-12-03 21:19:52 +0000468 }
469 }
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000470
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000471 double bufferd[16];
472 float bufferf[16];
473 a.asColMajord(bufferd);
474 b.setColMajord(bufferd);
475 REPORTER_ASSERT(reporter, nearly_equal(a, b));
476 b.setRowMajord(bufferd);
477 b.transpose();
478 REPORTER_ASSERT(reporter, nearly_equal(a, b));
479 a.asColMajorf(bufferf);
480 b.setColMajorf(bufferf);
481 REPORTER_ASSERT(reporter, nearly_equal(a, b));
482 b.setRowMajorf(bufferf);
483 b.transpose();
484 REPORTER_ASSERT(reporter, nearly_equal(a, b));
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000485}
486
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000487static void test_3x3_conversion(skiatest::Reporter* reporter) {
488 SkMScalar values4x4[16] = { 1, 2, 3, 4,
489 5, 6, 7, 8,
490 9, 10, 11, 12,
491 13, 14, 15, 16 };
492 SkScalar values3x3[9] = { 1, 2, 4,
493 5, 6, 8,
494 13, 14, 16 };
495 SkMScalar values4x4flattened[16] = { 1, 2, 0, 4,
496 5, 6, 0, 8,
497 0, 0, 1, 0,
498 13, 14, 0, 16 };
reed@google.com44699382013-10-31 17:28:30 +0000499 SkMatrix44 a44(SkMatrix44::kUninitialized_Constructor);
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000500 a44.setRowMajor(values4x4);
501
502 SkMatrix a33 = a44;
503 SkMatrix expected33;
504 for (int i = 0; i < 9; i++) expected33[i] = values3x3[i];
505 REPORTER_ASSERT(reporter, expected33 == a33);
506
507 SkMatrix44 a44flattened = a33;
reed@google.com44699382013-10-31 17:28:30 +0000508 SkMatrix44 expected44flattened(SkMatrix44::kUninitialized_Constructor);
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000509 expected44flattened.setRowMajor(values4x4flattened);
510 REPORTER_ASSERT(reporter, nearly_equal(a44flattened, expected44flattened));
511
512 // Test that a point with a Z value of 0 is transformed the same way.
513 SkScalar vec4[4] = { 2, 4, 0, 8 };
514 SkScalar vec3[3] = { 2, 4, 8 };
515
516 SkScalar vec4transformed[4];
517 SkScalar vec3transformed[3];
518 SkScalar vec4transformed2[4];
519 a44.mapScalars(vec4, vec4transformed);
520 a33.mapHomogeneousPoints(vec3transformed, vec3, 1);
521 a44flattened.mapScalars(vec4, vec4transformed2);
522 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[0], vec3transformed[0]));
523 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[1], vec3transformed[1]));
524 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[3], vec3transformed[2]));
525 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[0], vec4transformed2[0]));
526 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[1], vec4transformed2[1]));
527 REPORTER_ASSERT(reporter, !nearly_equal_scalar(vec4transformed[2], vec4transformed2[2]));
528 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[3], vec4transformed2[3]));
529}
530
caryclark@google.com42639cd2012-06-06 12:03:39 +0000531static void TestMatrix44(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000532 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
533 SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor);
534 SkMatrix44 iden1(SkMatrix44::kUninitialized_Constructor);
535 SkMatrix44 iden2(SkMatrix44::kUninitialized_Constructor);
536 SkMatrix44 rot(SkMatrix44::kUninitialized_Constructor);
reed@google.com125002a2011-06-09 19:13:41 +0000537
reed@google.com7d683352012-12-03 21:19:52 +0000538 mat.setTranslate(1, 1, 1);
reed@google.com125002a2011-06-09 19:13:41 +0000539 mat.invert(&inverse);
540 iden1.setConcat(mat, inverse);
541 REPORTER_ASSERT(reporter, is_identity(iden1));
542
reed@google.com7d683352012-12-03 21:19:52 +0000543 mat.setScale(2, 2, 2);
reed@google.com125002a2011-06-09 19:13:41 +0000544 mat.invert(&inverse);
545 iden1.setConcat(mat, inverse);
546 REPORTER_ASSERT(reporter, is_identity(iden1));
547
reed@google.com7d683352012-12-03 21:19:52 +0000548 mat.setScale(SK_MScalar1/2, SK_MScalar1/2, SK_MScalar1/2);
reed@google.com125002a2011-06-09 19:13:41 +0000549 mat.invert(&inverse);
550 iden1.setConcat(mat, inverse);
551 REPORTER_ASSERT(reporter, is_identity(iden1));
552
reed@google.com7d683352012-12-03 21:19:52 +0000553 mat.setScale(3, 3, 3);
554 rot.setRotateDegreesAbout(0, 0, -1, 90);
reed@google.com125002a2011-06-09 19:13:41 +0000555 mat.postConcat(rot);
556 REPORTER_ASSERT(reporter, mat.invert(NULL));
557 mat.invert(&inverse);
558 iden1.setConcat(mat, inverse);
559 REPORTER_ASSERT(reporter, is_identity(iden1));
560 iden2.setConcat(inverse, mat);
561 REPORTER_ASSERT(reporter, is_identity(iden2));
reed@google.comda9fac02011-06-13 14:46:52 +0000562
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000563 // test tiny-valued matrix inverse
564 mat.reset();
565 mat.setScale(1.0e-12, 1.0e-12, 1.0e-12);
566 rot.setRotateDegreesAbout(0, 0, -1, 90);
567 mat.postConcat(rot);
568 mat.postTranslate(1.0e-12, 1.0e-12, 1.0e-12);
569 REPORTER_ASSERT(reporter, mat.invert(NULL));
570 mat.invert(&inverse);
571 iden1.setConcat(mat, inverse);
572 REPORTER_ASSERT(reporter, is_identity(iden1));
skia.committer@gmail.comb74bdf02013-08-21 07:01:29 +0000573
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000574 // test mixed-valued matrix inverse
575 mat.reset();
jvanverth@google.com25f72ed2013-09-03 19:46:16 +0000576 mat.setScale(1.0e-10, 3.0, 1.0e+10);
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000577 rot.setRotateDegreesAbout(0, 0, -1, 90);
578 mat.postConcat(rot);
jvanverth@google.com25f72ed2013-09-03 19:46:16 +0000579 mat.postTranslate(1.0e+10, 3.0, 1.0e-10);
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000580 REPORTER_ASSERT(reporter, mat.invert(NULL));
581 mat.invert(&inverse);
582 iden1.setConcat(mat, inverse);
583 REPORTER_ASSERT(reporter, is_identity(iden1));
skia.committer@gmail.comb74bdf02013-08-21 07:01:29 +0000584
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000585 // test degenerate matrix
586 mat.reset();
587 mat.set3x3(1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0);
588 REPORTER_ASSERT(reporter, !mat.invert(NULL));
skia.committer@gmail.comb74bdf02013-08-21 07:01:29 +0000589
reed@google.comda9fac02011-06-13 14:46:52 +0000590 // test rol/col Major getters
591 {
592 mat.setTranslate(2, 3, 4);
593 float dataf[16];
594 double datad[16];
rmistry@google.comd6176b02012-08-23 18:14:13 +0000595
reed@google.comda9fac02011-06-13 14:46:52 +0000596 mat.asColMajorf(dataf);
597 assert16<float>(reporter, dataf,
598 1, 0, 0, 0,
599 0, 1, 0, 0,
600 0, 0, 1, 0,
601 2, 3, 4, 1);
602 mat.asColMajord(datad);
603 assert16<double>(reporter, datad, 1, 0, 0, 0,
604 0, 1, 0, 0,
605 0, 0, 1, 0,
606 2, 3, 4, 1);
607 mat.asRowMajorf(dataf);
608 assert16<float>(reporter, dataf, 1, 0, 0, 2,
609 0, 1, 0, 3,
610 0, 0, 1, 4,
611 0, 0, 0, 1);
612 mat.asRowMajord(datad);
613 assert16<double>(reporter, datad, 1, 0, 0, 2,
614 0, 1, 0, 3,
615 0, 0, 1, 4,
616 0, 0, 0, 1);
617 }
reed@google.com6f2b44d2011-06-24 18:13:39 +0000618
reed@google.com80b577e2012-11-09 21:25:06 +0000619 test_concat(reporter);
620
caryclark@google.com42639cd2012-06-06 12:03:39 +0000621 if (false) { // avoid bit rot, suppress warning (working on making this pass)
622 test_common_angles(reporter);
623 }
vollick@chromium.org3959a762012-11-13 15:08:22 +0000624
vollick@chromium.org57a54e32012-12-10 20:16:10 +0000625 test_constructor(reporter);
reed@google.com7d683352012-12-03 21:19:52 +0000626 test_gettype(reporter);
vollick@chromium.org3959a762012-11-13 15:08:22 +0000627 test_determinant(reporter);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000628 test_invert(reporter);
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000629 test_transpose(reporter);
630 test_get_set_double(reporter);
reed@google.com7d683352012-12-03 21:19:52 +0000631 test_set_row_col_major(reporter);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000632 test_translate(reporter);
633 test_scale(reporter);
634 test_map2(reporter);
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000635 test_3x3_conversion(reporter);
reed@google.com125002a2011-06-09 19:13:41 +0000636}
637
638#include "TestClassDef.h"
639DEFINE_TESTCLASS("Matrix44", Matrix44TestClass, TestMatrix44)