blob: ea6a56f436326ba1c802ee581d76106f8b6c6129 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
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.com6f2b44d2011-06-24 18:13:39 +000075static void test_common_angles(skiatest::Reporter* reporter) {
76 SkMatrix44 rot;
77 // Test precision of rotation in common cases
78 int common_angles[] = { 0, 90, -90, 180, -180, 270, -270, 360, -360 };
79 for (int i = 0; i < 9; ++i) {
robertphillips@google.com09042b82012-04-06 20:01:46 +000080 rot.setRotateDegreesAbout(0, 0, -1, SkIntToScalar(common_angles[i]));
reed@google.com6f2b44d2011-06-24 18:13:39 +000081
82 SkMatrix rot3x3 = rot;
83 REPORTER_ASSERT(reporter, rot3x3.rectStaysRect());
84 }
85}
86
reed@google.com80b577e2012-11-09 21:25:06 +000087static void test_concat(skiatest::Reporter* reporter) {
88 int i;
89 SkMatrix44 a, b, c, d;
90
91 a.setTranslate(10, 10, 10);
92 b.setScale(2, 2, 2);
93
94 SkScalar src[8] = {
95 0, 0, 0, 1,
96 1, 1, 1, 1
97 };
98 SkScalar dst[8];
99
100 c.setConcat(a, b);
101
102 d = a;
103 d.preConcat(b);
104 REPORTER_ASSERT(reporter, d == c);
skia.committer@gmail.com453995e2012-11-10 02:01:26 +0000105
reed@google.com1ea95be2012-11-09 21:39:48 +0000106 c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
reed@google.com80b577e2012-11-09 21:25:06 +0000107 for (i = 0; i < 3; ++i) {
108 REPORTER_ASSERT(reporter, 10 == dst[i]);
109 REPORTER_ASSERT(reporter, 12 == dst[i + 4]);
110 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +0000111
reed@google.com80b577e2012-11-09 21:25:06 +0000112 c.setConcat(b, a);
113
114 d = a;
115 d.postConcat(b);
116 REPORTER_ASSERT(reporter, d == c);
117
reed@google.com1ea95be2012-11-09 21:39:48 +0000118 c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
reed@google.com80b577e2012-11-09 21:25:06 +0000119 for (i = 0; i < 3; ++i) {
120 REPORTER_ASSERT(reporter, 20 == dst[i]);
121 REPORTER_ASSERT(reporter, 22 == dst[i + 4]);
122 }
123}
124
vollick@chromium.org3959a762012-11-13 15:08:22 +0000125static void test_determinant(skiatest::Reporter* reporter) {
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000126 SkMatrix44 a;
127 REPORTER_ASSERT(reporter, nearly_equal_double(1, a.determinant()));
128 a.set(1, 1, SkFloatToMScalar(2));
129 REPORTER_ASSERT(reporter, nearly_equal_double(2, a.determinant()));
130 SkMatrix44 b;
131 REPORTER_ASSERT(reporter, a.invert(&b));
132 REPORTER_ASSERT(reporter, nearly_equal_double(0.5, b.determinant()));
133 SkMatrix44 c = b = a;
134 c.set(0, 1, SkFloatToMScalar(4));
135 b.set(1, 0, SkFloatToMScalar(4));
136 REPORTER_ASSERT(reporter,
137 nearly_equal_double(a.determinant(),
138 b.determinant()));
139 SkMatrix44 d = a;
140 d.set(0, 0, SkFloatToMScalar(8));
141 REPORTER_ASSERT(reporter, nearly_equal_double(16, d.determinant()));
vollick@chromium.org3959a762012-11-13 15:08:22 +0000142
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000143 SkMatrix44 e = a;
144 e.postConcat(d);
145 REPORTER_ASSERT(reporter, nearly_equal_double(32, e.determinant()));
146 e.set(0, 0, SkFloatToMScalar(0));
147 REPORTER_ASSERT(reporter, nearly_equal_double(0, e.determinant()));
vollick@chromium.org3959a762012-11-13 15:08:22 +0000148}
149
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000150static void test_transpose(skiatest::Reporter* reporter) {
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000151 SkMatrix44 a;
152 SkMatrix44 b;
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000153
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000154 int i = 0;
155 for (int row = 0; row < 4; ++row) {
156 for (int col = 0; col < 4; ++col) {
157 a.setDouble(row, col, i);
158 b.setDouble(col, row, i++);
159 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000160 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000161
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000162 a.transpose();
163 REPORTER_ASSERT(reporter, nearly_equal(a, b));
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000164}
165
166static void test_get_set_double(skiatest::Reporter* reporter) {
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000167 SkMatrix44 a;
168 for (int row = 0; row < 4; ++row) {
169 for (int col = 0; col < 4; ++col) {
170 a.setDouble(row, col, 3.141592653589793);
171 REPORTER_ASSERT(reporter,
172 nearly_equal_double(3.141592653589793,
173 a.getDouble(row, col)));
174 a.setDouble(row, col, 0);
175 REPORTER_ASSERT(reporter,
176 nearly_equal_double(0, a.getDouble(row, col)));
177 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000178 }
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000179}
180
181static void test_set_row_col_major(skiatest::Reporter* reporter) {
182 SkMatrix44 a, b, c, d;
183 for (int row = 0; row < 4; ++row)
184 for (int col = 0; col < 4; ++col)
185 a.setDouble(row, col, row * 4 + col);
186 double bufferd[16];
187 float bufferf[16];
188 a.asColMajord(bufferd);
189 b.setColMajord(bufferd);
190 REPORTER_ASSERT(reporter, nearly_equal(a, b));
191 b.setRowMajord(bufferd);
192 b.transpose();
193 REPORTER_ASSERT(reporter, nearly_equal(a, b));
194 a.asColMajorf(bufferf);
195 b.setColMajorf(bufferf);
196 REPORTER_ASSERT(reporter, nearly_equal(a, b));
197 b.setRowMajorf(bufferf);
198 b.transpose();
199 REPORTER_ASSERT(reporter, nearly_equal(a, b));
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000200}
201
caryclark@google.com42639cd2012-06-06 12:03:39 +0000202static void TestMatrix44(skiatest::Reporter* reporter) {
reed@google.comda9fac02011-06-13 14:46:52 +0000203#ifdef SK_SCALAR_IS_FLOAT
reed@google.com125002a2011-06-09 19:13:41 +0000204 SkMatrix44 mat, inverse, iden1, iden2, rot;
205
206 mat.reset();
207 mat.setTranslate(SK_Scalar1, SK_Scalar1, SK_Scalar1);
208 mat.invert(&inverse);
209 iden1.setConcat(mat, inverse);
210 REPORTER_ASSERT(reporter, is_identity(iden1));
211
212 mat.setScale(SkIntToScalar(2), SkIntToScalar(2), SkIntToScalar(2));
213 mat.invert(&inverse);
214 iden1.setConcat(mat, inverse);
215 REPORTER_ASSERT(reporter, is_identity(iden1));
216
217 mat.setScale(SK_Scalar1/2, SK_Scalar1/2, SK_Scalar1/2);
218 mat.invert(&inverse);
219 iden1.setConcat(mat, inverse);
220 REPORTER_ASSERT(reporter, is_identity(iden1));
221
222 mat.setScale(SkIntToScalar(3), SkIntToScalar(5), SkIntToScalar(20));
223 rot.setRotateDegreesAbout(
224 SkIntToScalar(0),
225 SkIntToScalar(0),
226 SkIntToScalar(-1),
227 SkIntToScalar(90));
228 mat.postConcat(rot);
229 REPORTER_ASSERT(reporter, mat.invert(NULL));
230 mat.invert(&inverse);
231 iden1.setConcat(mat, inverse);
232 REPORTER_ASSERT(reporter, is_identity(iden1));
233 iden2.setConcat(inverse, mat);
234 REPORTER_ASSERT(reporter, is_identity(iden2));
reed@google.comda9fac02011-06-13 14:46:52 +0000235
236 // test rol/col Major getters
237 {
238 mat.setTranslate(2, 3, 4);
239 float dataf[16];
240 double datad[16];
rmistry@google.comd6176b02012-08-23 18:14:13 +0000241
reed@google.comda9fac02011-06-13 14:46:52 +0000242 mat.asColMajorf(dataf);
243 assert16<float>(reporter, dataf,
244 1, 0, 0, 0,
245 0, 1, 0, 0,
246 0, 0, 1, 0,
247 2, 3, 4, 1);
248 mat.asColMajord(datad);
249 assert16<double>(reporter, datad, 1, 0, 0, 0,
250 0, 1, 0, 0,
251 0, 0, 1, 0,
252 2, 3, 4, 1);
253 mat.asRowMajorf(dataf);
254 assert16<float>(reporter, dataf, 1, 0, 0, 2,
255 0, 1, 0, 3,
256 0, 0, 1, 4,
257 0, 0, 0, 1);
258 mat.asRowMajord(datad);
259 assert16<double>(reporter, datad, 1, 0, 0, 2,
260 0, 1, 0, 3,
261 0, 0, 1, 4,
262 0, 0, 0, 1);
263 }
reed@google.com6f2b44d2011-06-24 18:13:39 +0000264
reed@google.com80b577e2012-11-09 21:25:06 +0000265 test_concat(reporter);
266
caryclark@google.com42639cd2012-06-06 12:03:39 +0000267 if (false) { // avoid bit rot, suppress warning (working on making this pass)
268 test_common_angles(reporter);
269 }
vollick@chromium.org3959a762012-11-13 15:08:22 +0000270
271 test_determinant(reporter);
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000272 test_transpose(reporter);
273 test_get_set_double(reporter);
reed@google.comda9fac02011-06-13 14:46:52 +0000274#endif
reed@google.com125002a2011-06-09 19:13:41 +0000275}
276
277#include "TestClassDef.h"
278DEFINE_TESTCLASS("Matrix44", Matrix44TestClass, TestMatrix44)