Matrix44Test.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936
  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. #include "include/core/SkMatrix44.h"
  8. #include "include/core/SkPoint3.h"
  9. #include "tests/Test.h"
  10. static bool nearly_equal_double(double a, double b) {
  11. const double tolerance = 1e-7;
  12. double diff = a - b;
  13. if (diff < 0)
  14. diff = -diff;
  15. return diff <= tolerance;
  16. }
  17. static bool nearly_equal_mscalar(SkMScalar a, SkMScalar b) {
  18. const SkMScalar tolerance = SK_MScalar1 / 200000;
  19. return SkTAbs<SkMScalar>(a - b) <= tolerance;
  20. }
  21. static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
  22. const SkScalar tolerance = SK_Scalar1 / 200000;
  23. return SkScalarAbs(a - b) <= tolerance;
  24. }
  25. template <typename T> void assert16(skiatest::Reporter* reporter, const T data[],
  26. T m0, T m1, T m2, T m3,
  27. T m4, T m5, T m6, T m7,
  28. T m8, T m9, T m10, T m11,
  29. T m12, T m13, T m14, T m15) {
  30. REPORTER_ASSERT(reporter, data[0] == m0);
  31. REPORTER_ASSERT(reporter, data[1] == m1);
  32. REPORTER_ASSERT(reporter, data[2] == m2);
  33. REPORTER_ASSERT(reporter, data[3] == m3);
  34. REPORTER_ASSERT(reporter, data[4] == m4);
  35. REPORTER_ASSERT(reporter, data[5] == m5);
  36. REPORTER_ASSERT(reporter, data[6] == m6);
  37. REPORTER_ASSERT(reporter, data[7] == m7);
  38. REPORTER_ASSERT(reporter, data[8] == m8);
  39. REPORTER_ASSERT(reporter, data[9] == m9);
  40. REPORTER_ASSERT(reporter, data[10] == m10);
  41. REPORTER_ASSERT(reporter, data[11] == m11);
  42. REPORTER_ASSERT(reporter, data[12] == m12);
  43. REPORTER_ASSERT(reporter, data[13] == m13);
  44. REPORTER_ASSERT(reporter, data[14] == m14);
  45. REPORTER_ASSERT(reporter, data[15] == m15);
  46. }
  47. static bool nearly_equal(const SkMatrix44& a, const SkMatrix44& b) {
  48. for (int i = 0; i < 4; ++i) {
  49. for (int j = 0; j < 4; ++j) {
  50. if (!nearly_equal_mscalar(a.get(i, j), b.get(i, j))) {
  51. SkDebugf("not equal %g %g\n", a.get(i, j), b.get(i, j));
  52. return false;
  53. }
  54. }
  55. }
  56. return true;
  57. }
  58. static bool is_identity(const SkMatrix44& m) {
  59. SkMatrix44 identity(SkMatrix44::kIdentity_Constructor);
  60. return nearly_equal(m, identity);
  61. }
  62. ///////////////////////////////////////////////////////////////////////////////
  63. static bool bits_isonly(int value, int mask) {
  64. return 0 == (value & ~mask);
  65. }
  66. static void test_constructor(skiatest::Reporter* reporter) {
  67. // Allocate a matrix on the heap
  68. SkMatrix44* placeholderMatrix = new SkMatrix44;
  69. std::unique_ptr<SkMatrix44> deleteMe(placeholderMatrix);
  70. for (int row = 0; row < 4; ++row) {
  71. for (int col = 0; col < 4; ++col) {
  72. placeholderMatrix->setDouble(row, col, row * col);
  73. }
  74. }
  75. // Use placement-new syntax to trigger the constructor on top of the heap
  76. // address we already initialized. This allows us to check that the
  77. // constructor did avoid initializing the matrix contents.
  78. SkMatrix44* testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kUninitialized_Constructor);
  79. REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
  80. REPORTER_ASSERT(reporter, !testMatrix->isIdentity());
  81. for (int row = 0; row < 4; ++row) {
  82. for (int col = 0; col < 4; ++col) {
  83. REPORTER_ASSERT(reporter, nearly_equal_double(row * col, testMatrix->getDouble(row, col)));
  84. }
  85. }
  86. // Verify that kIdentity_Constructor really does initialize to an identity matrix.
  87. testMatrix = 0;
  88. testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kIdentity_Constructor);
  89. REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
  90. REPORTER_ASSERT(reporter, testMatrix->isIdentity());
  91. REPORTER_ASSERT(reporter, *testMatrix == SkMatrix44::I());
  92. // Verify that that constructing from an SkMatrix initializes everything.
  93. SkMatrix44 scaleMatrix;
  94. scaleMatrix.setScale(3, 4, 5);
  95. REPORTER_ASSERT(reporter, scaleMatrix.isScale());
  96. testMatrix = new(&scaleMatrix) SkMatrix44(SkMatrix::I());
  97. REPORTER_ASSERT(reporter, testMatrix->isIdentity());
  98. REPORTER_ASSERT(reporter, *testMatrix == SkMatrix44::I());
  99. }
  100. static void test_translate(skiatest::Reporter* reporter) {
  101. SkMatrix44 mat;
  102. SkMatrix44 inverse;
  103. mat.setTranslate(0, 0, 0);
  104. REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
  105. mat.setTranslate(1, 2, 3);
  106. REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kTranslate_Mask));
  107. REPORTER_ASSERT(reporter, mat.invert(&inverse));
  108. REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kTranslate_Mask));
  109. SkMatrix44 a,b,c;
  110. a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
  111. b.setTranslate(10, 11, 12);
  112. c.setConcat(a, b);
  113. mat = a;
  114. mat.preTranslate(10, 11, 12);
  115. REPORTER_ASSERT(reporter, mat == c);
  116. c.setConcat(b, a);
  117. mat = a;
  118. mat.postTranslate(10, 11, 12);
  119. REPORTER_ASSERT(reporter, mat == c);
  120. }
  121. static void test_scale(skiatest::Reporter* reporter) {
  122. SkMatrix44 mat;
  123. SkMatrix44 inverse;
  124. mat.setScale(1, 1, 1);
  125. REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
  126. mat.setScale(1, 2, 3);
  127. REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kScale_Mask));
  128. REPORTER_ASSERT(reporter, mat.invert(&inverse));
  129. REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kScale_Mask));
  130. SkMatrix44 a,b,c;
  131. a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
  132. b.setScale(10, 11, 12);
  133. c.setConcat(a, b);
  134. mat = a;
  135. mat.preScale(10, 11, 12);
  136. REPORTER_ASSERT(reporter, mat == c);
  137. c.setConcat(b, a);
  138. mat = a;
  139. mat.postScale(10, 11, 12);
  140. REPORTER_ASSERT(reporter, mat == c);
  141. }
  142. static void make_i(SkMatrix44* mat) { mat->setIdentity(); }
  143. static void make_t(SkMatrix44* mat) { mat->setTranslate(1, 2, 3); }
  144. static void make_s(SkMatrix44* mat) { mat->setScale(1, 2, 3); }
  145. static void make_st(SkMatrix44* mat) {
  146. mat->setScale(1, 2, 3);
  147. mat->postTranslate(1, 2, 3);
  148. }
  149. static void make_a(SkMatrix44* mat) {
  150. mat->setRotateDegreesAbout(1, 2, 3, 45);
  151. }
  152. static void make_p(SkMatrix44* mat) {
  153. SkMScalar data[] = {
  154. 1, 2, 3, 4, 5, 6, 7, 8,
  155. 1, 2, 3, 4, 5, 6, 7, 8,
  156. };
  157. mat->setRowMajor(data);
  158. }
  159. typedef void (*Make44Proc)(SkMatrix44*);
  160. static const Make44Proc gMakeProcs[] = {
  161. make_i, make_t, make_s, make_st, make_a, make_p
  162. };
  163. static void test_map2(skiatest::Reporter* reporter, const SkMatrix44& mat) {
  164. SkMScalar src2[] = { 1, 2 };
  165. SkMScalar src4[] = { src2[0], src2[1], 0, 1 };
  166. SkMScalar dstA[4], dstB[4];
  167. for (int i = 0; i < 4; ++i) {
  168. dstA[i] = SkDoubleToMScalar(123456789);
  169. dstB[i] = SkDoubleToMScalar(987654321);
  170. }
  171. mat.map2(src2, 1, dstA);
  172. mat.mapMScalars(src4, dstB);
  173. for (int i = 0; i < 4; ++i) {
  174. REPORTER_ASSERT(reporter, dstA[i] == dstB[i]);
  175. }
  176. }
  177. static void test_map2(skiatest::Reporter* reporter) {
  178. SkMatrix44 mat;
  179. for (size_t i = 0; i < SK_ARRAY_COUNT(gMakeProcs); ++i) {
  180. gMakeProcs[i](&mat);
  181. test_map2(reporter, mat);
  182. }
  183. }
  184. static void test_gettype(skiatest::Reporter* reporter) {
  185. SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor);
  186. REPORTER_ASSERT(reporter, matrix.isIdentity());
  187. REPORTER_ASSERT(reporter, SkMatrix44::kIdentity_Mask == matrix.getType());
  188. int expectedMask;
  189. matrix.set(1, 1, 0);
  190. expectedMask = SkMatrix44::kScale_Mask;
  191. REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
  192. matrix.set(0, 3, 1); // translate-x
  193. expectedMask |= SkMatrix44::kTranslate_Mask;
  194. REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
  195. matrix.set(2, 0, 1);
  196. expectedMask |= SkMatrix44::kAffine_Mask;
  197. REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
  198. matrix.set(3, 2, 1);
  199. REPORTER_ASSERT(reporter, matrix.getType() & SkMatrix44::kPerspective_Mask);
  200. // ensure that negative zero is treated as zero
  201. SkMScalar dx = 0;
  202. SkMScalar dy = 0;
  203. SkMScalar dz = 0;
  204. matrix.setTranslate(-dx, -dy, -dz);
  205. REPORTER_ASSERT(reporter, matrix.isIdentity());
  206. matrix.preTranslate(-dx, -dy, -dz);
  207. REPORTER_ASSERT(reporter, matrix.isIdentity());
  208. matrix.postTranslate(-dx, -dy, -dz);
  209. REPORTER_ASSERT(reporter, matrix.isIdentity());
  210. }
  211. static void test_common_angles(skiatest::Reporter* reporter) {
  212. SkMatrix44 rot;
  213. // Test precision of rotation in common cases
  214. int common_angles[] = { 0, 90, -90, 180, -180, 270, -270, 360, -360 };
  215. for (int i = 0; i < 9; ++i) {
  216. rot.setRotateDegreesAbout(0, 0, -1, SkIntToScalar(common_angles[i]));
  217. SkMatrix rot3x3 = rot;
  218. REPORTER_ASSERT(reporter, rot3x3.rectStaysRect());
  219. }
  220. }
  221. static void test_concat(skiatest::Reporter* reporter) {
  222. int i;
  223. SkMatrix44 a,b,c,d;
  224. a.setTranslate(10, 10, 10);
  225. b.setScale(2, 2, 2);
  226. SkScalar src[8] = {
  227. 0, 0, 0, 1,
  228. 1, 1, 1, 1
  229. };
  230. SkScalar dst[8];
  231. c.setConcat(a, b);
  232. d = a;
  233. d.preConcat(b);
  234. REPORTER_ASSERT(reporter, d == c);
  235. c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
  236. for (i = 0; i < 3; ++i) {
  237. REPORTER_ASSERT(reporter, 10 == dst[i]);
  238. REPORTER_ASSERT(reporter, 12 == dst[i + 4]);
  239. }
  240. c.setConcat(b, a);
  241. d = a;
  242. d.postConcat(b);
  243. REPORTER_ASSERT(reporter, d == c);
  244. c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
  245. for (i = 0; i < 3; ++i) {
  246. REPORTER_ASSERT(reporter, 20 == dst[i]);
  247. REPORTER_ASSERT(reporter, 22 == dst[i + 4]);
  248. }
  249. }
  250. static void test_determinant(skiatest::Reporter* reporter) {
  251. SkMatrix44 a(SkMatrix44::kIdentity_Constructor);
  252. REPORTER_ASSERT(reporter, nearly_equal_double(1, a.determinant()));
  253. a.set(1, 1, 2);
  254. REPORTER_ASSERT(reporter, nearly_equal_double(2, a.determinant()));
  255. SkMatrix44 b;
  256. REPORTER_ASSERT(reporter, a.invert(&b));
  257. REPORTER_ASSERT(reporter, nearly_equal_double(0.5, b.determinant()));
  258. SkMatrix44 c = b = a;
  259. c.set(0, 1, 4);
  260. b.set(1, 0, 4);
  261. REPORTER_ASSERT(reporter,
  262. nearly_equal_double(a.determinant(),
  263. b.determinant()));
  264. SkMatrix44 d = a;
  265. d.set(0, 0, 8);
  266. REPORTER_ASSERT(reporter, nearly_equal_double(16, d.determinant()));
  267. SkMatrix44 e = a;
  268. e.postConcat(d);
  269. REPORTER_ASSERT(reporter, nearly_equal_double(32, e.determinant()));
  270. e.set(0, 0, 0);
  271. REPORTER_ASSERT(reporter, nearly_equal_double(0, e.determinant()));
  272. }
  273. static void test_invert(skiatest::Reporter* reporter) {
  274. SkMatrix44 inverse;
  275. double inverseData[16];
  276. SkMatrix44 identity(SkMatrix44::kIdentity_Constructor);
  277. identity.invert(&inverse);
  278. inverse.asRowMajord(inverseData);
  279. assert16<double>(reporter, inverseData,
  280. 1, 0, 0, 0,
  281. 0, 1, 0, 0,
  282. 0, 0, 1, 0,
  283. 0, 0, 0, 1);
  284. SkMatrix44 translation;
  285. translation.setTranslate(2, 3, 4);
  286. translation.invert(&inverse);
  287. inverse.asRowMajord(inverseData);
  288. assert16<double>(reporter, inverseData,
  289. 1, 0, 0, -2,
  290. 0, 1, 0, -3,
  291. 0, 0, 1, -4,
  292. 0, 0, 0, 1);
  293. SkMatrix44 scale;
  294. scale.setScale(2, 4, 8);
  295. scale.invert(&inverse);
  296. inverse.asRowMajord(inverseData);
  297. assert16<double>(reporter, inverseData,
  298. 0.5, 0, 0, 0,
  299. 0, 0.25, 0, 0,
  300. 0, 0, 0.125, 0,
  301. 0, 0, 0, 1);
  302. SkMatrix44 scaleTranslation;
  303. scaleTranslation.setScale(32, 128, 1024);
  304. scaleTranslation.preTranslate(2, 3, 4);
  305. scaleTranslation.invert(&inverse);
  306. inverse.asRowMajord(inverseData);
  307. assert16<double>(reporter, inverseData,
  308. 0.03125, 0, 0, -2,
  309. 0, 0.0078125, 0, -3,
  310. 0, 0, 0.0009765625, -4,
  311. 0, 0, 0, 1);
  312. SkMatrix44 rotation;
  313. rotation.setRotateDegreesAbout(0, 0, 1, 90);
  314. rotation.invert(&inverse);
  315. SkMatrix44 expected;
  316. double expectedInverseRotation[16] =
  317. {0, 1, 0, 0,
  318. -1, 0, 0, 0,
  319. 0, 0, 1, 0,
  320. 0, 0, 0, 1};
  321. expected.setRowMajord(expectedInverseRotation);
  322. REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
  323. SkMatrix44 affine;
  324. affine.setRotateDegreesAbout(0, 0, 1, 90);
  325. affine.preScale(10, 20, 100);
  326. affine.preTranslate(2, 3, 4);
  327. affine.invert(&inverse);
  328. double expectedInverseAffine[16] =
  329. {0, 0.1, 0, -2,
  330. -0.05, 0, 0, -3,
  331. 0, 0, 0.01, -4,
  332. 0, 0, 0, 1};
  333. expected.setRowMajord(expectedInverseAffine);
  334. REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
  335. SkMatrix44 perspective(SkMatrix44::kIdentity_Constructor);
  336. perspective.setDouble(3, 2, 1.0);
  337. perspective.invert(&inverse);
  338. double expectedInversePerspective[16] =
  339. {1, 0, 0, 0,
  340. 0, 1, 0, 0,
  341. 0, 0, 1, 0,
  342. 0, 0, -1, 1};
  343. expected.setRowMajord(expectedInversePerspective);
  344. REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
  345. SkMatrix44 affineAndPerspective(SkMatrix44::kIdentity_Constructor);
  346. affineAndPerspective.setDouble(3, 2, 1.0);
  347. affineAndPerspective.preScale(10, 20, 100);
  348. affineAndPerspective.preTranslate(2, 3, 4);
  349. affineAndPerspective.invert(&inverse);
  350. double expectedInverseAffineAndPerspective[16] =
  351. {0.1, 0, 2, -2,
  352. 0, 0.05, 3, -3,
  353. 0, 0, 4.01, -4,
  354. 0, 0, -1, 1};
  355. expected.setRowMajord(expectedInverseAffineAndPerspective);
  356. REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
  357. SkMatrix44 tinyScale(SkMatrix44::kIdentity_Constructor);
  358. tinyScale.setDouble(0, 0, 1e-39);
  359. REPORTER_ASSERT(reporter, tinyScale.getType() == SkMatrix44::kScale_Mask);
  360. REPORTER_ASSERT(reporter, !tinyScale.invert(nullptr));
  361. REPORTER_ASSERT(reporter, !tinyScale.invert(&inverse));
  362. SkMatrix44 tinyScaleTranslate(SkMatrix44::kIdentity_Constructor);
  363. tinyScaleTranslate.setDouble(0, 0, 1e-38);
  364. REPORTER_ASSERT(reporter, tinyScaleTranslate.invert(nullptr));
  365. tinyScaleTranslate.setDouble(0, 3, 10);
  366. REPORTER_ASSERT(
  367. reporter, tinyScaleTranslate.getType() ==
  368. (SkMatrix44::kScale_Mask | SkMatrix44::kTranslate_Mask));
  369. REPORTER_ASSERT(reporter, !tinyScaleTranslate.invert(nullptr));
  370. REPORTER_ASSERT(reporter, !tinyScaleTranslate.invert(&inverse));
  371. SkMatrix44 tinyScalePerspective(SkMatrix44::kIdentity_Constructor);
  372. tinyScalePerspective.setDouble(0, 0, 1e-39);
  373. tinyScalePerspective.setDouble(3, 2, -1);
  374. REPORTER_ASSERT(reporter, (tinyScalePerspective.getType() &
  375. SkMatrix44::kPerspective_Mask) ==
  376. SkMatrix44::kPerspective_Mask);
  377. REPORTER_ASSERT(reporter, !tinyScalePerspective.invert(nullptr));
  378. REPORTER_ASSERT(reporter, !tinyScalePerspective.invert(&inverse));
  379. }
  380. static void test_transpose(skiatest::Reporter* reporter) {
  381. SkMatrix44 a,b;
  382. int i = 0;
  383. for (int row = 0; row < 4; ++row) {
  384. for (int col = 0; col < 4; ++col) {
  385. a.setDouble(row, col, i);
  386. b.setDouble(col, row, i++);
  387. }
  388. }
  389. a.transpose();
  390. REPORTER_ASSERT(reporter, nearly_equal(a, b));
  391. }
  392. static void test_get_set_double(skiatest::Reporter* reporter) {
  393. SkMatrix44 a;
  394. for (int row = 0; row < 4; ++row) {
  395. for (int col = 0; col < 4; ++col) {
  396. a.setDouble(row, col, 3.141592653589793);
  397. REPORTER_ASSERT(reporter,
  398. nearly_equal_double(3.141592653589793,
  399. a.getDouble(row, col)));
  400. a.setDouble(row, col, 0);
  401. REPORTER_ASSERT(reporter,
  402. nearly_equal_double(0, a.getDouble(row, col)));
  403. }
  404. }
  405. }
  406. static void test_set_3x3(skiatest::Reporter* r) {
  407. static float vals[9] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, };
  408. SkMatrix44 mat;
  409. mat.set3x3RowMajorf(vals);
  410. REPORTER_ASSERT(r, 1.0f == mat.getFloat(0, 0));
  411. REPORTER_ASSERT(r, 2.0f == mat.getFloat(0, 1));
  412. REPORTER_ASSERT(r, 3.0f == mat.getFloat(0, 2));
  413. REPORTER_ASSERT(r, 4.0f == mat.getFloat(1, 0));
  414. REPORTER_ASSERT(r, 5.0f == mat.getFloat(1, 1));
  415. REPORTER_ASSERT(r, 6.0f == mat.getFloat(1, 2));
  416. REPORTER_ASSERT(r, 7.0f == mat.getFloat(2, 0));
  417. REPORTER_ASSERT(r, 8.0f == mat.getFloat(2, 1));
  418. REPORTER_ASSERT(r, 9.0f == mat.getFloat(2, 2));
  419. }
  420. static void test_set_row_col_major(skiatest::Reporter* reporter) {
  421. SkMatrix44 a,b;
  422. for (int row = 0; row < 4; ++row) {
  423. for (int col = 0; col < 4; ++col) {
  424. a.setDouble(row, col, row * 4 + col);
  425. }
  426. }
  427. double bufferd[16];
  428. float bufferf[16];
  429. a.asColMajord(bufferd);
  430. b.setColMajord(bufferd);
  431. REPORTER_ASSERT(reporter, nearly_equal(a, b));
  432. b.setRowMajord(bufferd);
  433. b.transpose();
  434. REPORTER_ASSERT(reporter, nearly_equal(a, b));
  435. a.asColMajorf(bufferf);
  436. b.setColMajorf(bufferf);
  437. REPORTER_ASSERT(reporter, nearly_equal(a, b));
  438. b.setRowMajorf(bufferf);
  439. b.transpose();
  440. REPORTER_ASSERT(reporter, nearly_equal(a, b));
  441. }
  442. static void test_3x3_conversion(skiatest::Reporter* reporter) {
  443. SkMScalar values4x4[16] = { 1, 2, 3, 4,
  444. 5, 6, 7, 8,
  445. 9, 10, 11, 12,
  446. 13, 14, 15, 16 };
  447. SkScalar values3x3[9] = { 1, 2, 4,
  448. 5, 6, 8,
  449. 13, 14, 16 };
  450. SkMScalar values4x4flattened[16] = { 1, 2, 0, 4,
  451. 5, 6, 0, 8,
  452. 0, 0, 1, 0,
  453. 13, 14, 0, 16 };
  454. SkMatrix44 a44;
  455. a44.setRowMajor(values4x4);
  456. SkMatrix a33 = a44;
  457. SkMatrix expected33;
  458. for (int i = 0; i < 9; i++) expected33[i] = values3x3[i];
  459. REPORTER_ASSERT(reporter, expected33 == a33);
  460. SkMatrix44 a44flattened = a33;
  461. SkMatrix44 expected44flattened;
  462. expected44flattened.setRowMajor(values4x4flattened);
  463. REPORTER_ASSERT(reporter, nearly_equal(a44flattened, expected44flattened));
  464. // Test that a point with a Z value of 0 is transformed the same way.
  465. SkScalar vec4[4] = { 2, 4, 0, 8 };
  466. SkPoint3 vec3 = { 2, 4, 8 };
  467. SkScalar vec4transformed[4];
  468. SkPoint3 vec3transformed;
  469. SkScalar vec4transformed2[4];
  470. a44.mapScalars(vec4, vec4transformed);
  471. a33.mapHomogeneousPoints(&vec3transformed, &vec3, 1);
  472. a44flattened.mapScalars(vec4, vec4transformed2);
  473. REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[0], vec3transformed.fX));
  474. REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[1], vec3transformed.fY));
  475. REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[3], vec3transformed.fZ));
  476. REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[0], vec4transformed2[0]));
  477. REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[1], vec4transformed2[1]));
  478. REPORTER_ASSERT(reporter, !nearly_equal_scalar(vec4transformed[2], vec4transformed2[2]));
  479. REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[3], vec4transformed2[3]));
  480. }
  481. static void test_has_perspective(skiatest::Reporter* reporter) {
  482. SkMatrix44 transform(SkMatrix44::kIdentity_Constructor);
  483. transform.setDouble(3, 2, -0.1);
  484. REPORTER_ASSERT(reporter, transform.hasPerspective());
  485. transform.reset();
  486. REPORTER_ASSERT(reporter, !transform.hasPerspective());
  487. transform.setDouble(3, 0, -1.0);
  488. REPORTER_ASSERT(reporter, transform.hasPerspective());
  489. transform.reset();
  490. transform.setDouble(3, 1, -1.0);
  491. REPORTER_ASSERT(reporter, transform.hasPerspective());
  492. transform.reset();
  493. transform.setDouble(3, 2, -0.3);
  494. REPORTER_ASSERT(reporter, transform.hasPerspective());
  495. transform.reset();
  496. transform.setDouble(3, 3, 0.5);
  497. REPORTER_ASSERT(reporter, transform.hasPerspective());
  498. transform.reset();
  499. transform.setDouble(3, 3, 0.0);
  500. REPORTER_ASSERT(reporter, transform.hasPerspective());
  501. }
  502. static bool is_rectilinear (SkVector4& p1, SkVector4& p2, SkVector4& p3, SkVector4& p4) {
  503. return (SkScalarNearlyEqual(p1.fData[0], p2.fData[0]) &&
  504. SkScalarNearlyEqual(p2.fData[1], p3.fData[1]) &&
  505. SkScalarNearlyEqual(p3.fData[0], p4.fData[0]) &&
  506. SkScalarNearlyEqual(p4.fData[1], p1.fData[1])) ||
  507. (SkScalarNearlyEqual(p1.fData[1], p2.fData[1]) &&
  508. SkScalarNearlyEqual(p2.fData[0], p3.fData[0]) &&
  509. SkScalarNearlyEqual(p3.fData[1], p4.fData[1]) &&
  510. SkScalarNearlyEqual(p4.fData[0], p1.fData[0]));
  511. }
  512. static SkVector4 mul_with_persp_divide(const SkMatrix44& transform, const SkVector4& target) {
  513. SkVector4 result = transform * target;
  514. if (result.fData[3] != 0.0f && result.fData[3] != SK_Scalar1) {
  515. float wInverse = SK_Scalar1 / result.fData[3];
  516. result.set(result.fData[0] * wInverse,
  517. result.fData[1] * wInverse,
  518. result.fData[2] * wInverse,
  519. SK_Scalar1);
  520. }
  521. return result;
  522. }
  523. static bool empirically_preserves_2d_axis_alignment(skiatest::Reporter* reporter,
  524. const SkMatrix44& transform) {
  525. SkVector4 p1(5.0f, 5.0f, 0.0f);
  526. SkVector4 p2(10.0f, 5.0f, 0.0f);
  527. SkVector4 p3(10.0f, 20.0f, 0.0f);
  528. SkVector4 p4(5.0f, 20.0f, 0.0f);
  529. REPORTER_ASSERT(reporter, is_rectilinear(p1, p2, p3, p4));
  530. p1 = mul_with_persp_divide(transform, p1);
  531. p2 = mul_with_persp_divide(transform, p2);
  532. p3 = mul_with_persp_divide(transform, p3);
  533. p4 = mul_with_persp_divide(transform, p4);
  534. return is_rectilinear(p1, p2, p3, p4);
  535. }
  536. static void test(bool expected, skiatest::Reporter* reporter, const SkMatrix44& transform) {
  537. if (expected) {
  538. REPORTER_ASSERT(reporter, empirically_preserves_2d_axis_alignment(reporter, transform));
  539. REPORTER_ASSERT(reporter, transform.preserves2dAxisAlignment());
  540. } else {
  541. REPORTER_ASSERT(reporter, !empirically_preserves_2d_axis_alignment(reporter, transform));
  542. REPORTER_ASSERT(reporter, !transform.preserves2dAxisAlignment());
  543. }
  544. }
  545. static void test_preserves_2d_axis_alignment(skiatest::Reporter* reporter) {
  546. SkMatrix44 transform;
  547. SkMatrix44 transform2;
  548. static const struct TestCase {
  549. SkMScalar a; // row 1, column 1
  550. SkMScalar b; // row 1, column 2
  551. SkMScalar c; // row 2, column 1
  552. SkMScalar d; // row 2, column 2
  553. bool expected;
  554. } test_cases[] = {
  555. { 3.f, 0.f,
  556. 0.f, 4.f, true }, // basic case
  557. { 0.f, 4.f,
  558. 3.f, 0.f, true }, // rotate by 90
  559. { 0.f, 0.f,
  560. 0.f, 4.f, true }, // degenerate x
  561. { 3.f, 0.f,
  562. 0.f, 0.f, true }, // degenerate y
  563. { 0.f, 0.f,
  564. 3.f, 0.f, true }, // degenerate x + rotate by 90
  565. { 0.f, 4.f,
  566. 0.f, 0.f, true }, // degenerate y + rotate by 90
  567. { 3.f, 4.f,
  568. 0.f, 0.f, false },
  569. { 0.f, 0.f,
  570. 3.f, 4.f, false },
  571. { 0.f, 3.f,
  572. 0.f, 4.f, false },
  573. { 3.f, 0.f,
  574. 4.f, 0.f, false },
  575. { 3.f, 4.f,
  576. 5.f, 0.f, false },
  577. { 3.f, 4.f,
  578. 0.f, 5.f, false },
  579. { 3.f, 0.f,
  580. 4.f, 5.f, false },
  581. { 0.f, 3.f,
  582. 4.f, 5.f, false },
  583. { 2.f, 3.f,
  584. 4.f, 5.f, false },
  585. };
  586. for (size_t i = 0; i < sizeof(test_cases)/sizeof(TestCase); ++i) {
  587. const TestCase& value = test_cases[i];
  588. transform.setIdentity();
  589. transform.set(0, 0, value.a);
  590. transform.set(0, 1, value.b);
  591. transform.set(1, 0, value.c);
  592. transform.set(1, 1, value.d);
  593. test(value.expected, reporter, transform);
  594. }
  595. // Try the same test cases again, but this time make sure that other matrix
  596. // elements (except perspective) have entries, to test that they are ignored.
  597. for (size_t i = 0; i < sizeof(test_cases)/sizeof(TestCase); ++i) {
  598. const TestCase& value = test_cases[i];
  599. transform.setIdentity();
  600. transform.set(0, 0, value.a);
  601. transform.set(0, 1, value.b);
  602. transform.set(1, 0, value.c);
  603. transform.set(1, 1, value.d);
  604. transform.set(0, 2, 1.f);
  605. transform.set(0, 3, 2.f);
  606. transform.set(1, 2, 3.f);
  607. transform.set(1, 3, 4.f);
  608. transform.set(2, 0, 5.f);
  609. transform.set(2, 1, 6.f);
  610. transform.set(2, 2, 7.f);
  611. transform.set(2, 3, 8.f);
  612. test(value.expected, reporter, transform);
  613. }
  614. // Try the same test cases again, but this time add perspective which is
  615. // always assumed to not-preserve axis alignment.
  616. for (size_t i = 0; i < sizeof(test_cases)/sizeof(TestCase); ++i) {
  617. const TestCase& value = test_cases[i];
  618. transform.setIdentity();
  619. transform.set(0, 0, value.a);
  620. transform.set(0, 1, value.b);
  621. transform.set(1, 0, value.c);
  622. transform.set(1, 1, value.d);
  623. transform.set(0, 2, 1.f);
  624. transform.set(0, 3, 2.f);
  625. transform.set(1, 2, 3.f);
  626. transform.set(1, 3, 4.f);
  627. transform.set(2, 0, 5.f);
  628. transform.set(2, 1, 6.f);
  629. transform.set(2, 2, 7.f);
  630. transform.set(2, 3, 8.f);
  631. transform.set(3, 0, 9.f);
  632. transform.set(3, 1, 10.f);
  633. transform.set(3, 2, 11.f);
  634. transform.set(3, 3, 12.f);
  635. test(false, reporter, transform);
  636. }
  637. // Try a few more practical situations to check precision
  638. // Reuse TestCase (a, b, c, d) as (x, y, z, degrees) axis to rotate about.
  639. TestCase rotation_tests[] = {
  640. { 0.0, 0.0, 1.0, 90.0, true },
  641. { 0.0, 0.0, 1.0, 180.0, true },
  642. { 0.0, 0.0, 1.0, 270.0, true },
  643. { 0.0, 1.0, 0.0, 90.0, true },
  644. { 1.0, 0.0, 0.0, 90.0, true },
  645. { 0.0, 0.0, 1.0, 45.0, false },
  646. // In 3d these next two are non-preserving, but we're testing in 2d after
  647. // orthographic projection, where they are.
  648. { 0.0, 1.0, 0.0, 45.0, true },
  649. { 1.0, 0.0, 0.0, 45.0, true },
  650. };
  651. for (size_t i = 0; i < sizeof(rotation_tests)/sizeof(TestCase); ++i) {
  652. const TestCase& value = rotation_tests[i];
  653. transform.setRotateDegreesAbout(value.a, value.b, value.c, value.d);
  654. test(value.expected, reporter, transform);
  655. }
  656. static const struct DoubleRotationCase {
  657. SkMScalar x1;
  658. SkMScalar y1;
  659. SkMScalar z1;
  660. SkMScalar degrees1;
  661. SkMScalar x2;
  662. SkMScalar y2;
  663. SkMScalar z2;
  664. SkMScalar degrees2;
  665. bool expected;
  666. } double_rotation_tests[] = {
  667. { 0.0, 0.0, 1.0, 90.0, 0.0, 1.0, 0.0, 90.0, true },
  668. { 0.0, 0.0, 1.0, 90.0, 1.0, 0.0, 0.0, 90.0, true },
  669. { 0.0, 1.0, 0.0, 90.0, 0.0, 0.0, 1.0, 90.0, true },
  670. };
  671. for (size_t i = 0; i < sizeof(double_rotation_tests)/sizeof(DoubleRotationCase); ++i) {
  672. const DoubleRotationCase& value = double_rotation_tests[i];
  673. transform.setRotateDegreesAbout(value.x1, value.y1, value.z1, value.degrees1);
  674. transform2.setRotateDegreesAbout(value.x2, value.y2, value.z2, value.degrees2);
  675. transform.postConcat(transform2);
  676. test(value.expected, reporter, transform);
  677. }
  678. // Perspective cases.
  679. transform.setIdentity();
  680. transform.setDouble(3, 2, -0.1); // Perspective depth 10
  681. transform2.setRotateDegreesAbout(0.0, 1.0, 0.0, 45.0);
  682. transform.preConcat(transform2);
  683. test(false, reporter, transform);
  684. transform.setIdentity();
  685. transform.setDouble(3, 2, -0.1); // Perspective depth 10
  686. transform2.setRotateDegreesAbout(0.0, 0.0, 1.0, 90.0);
  687. transform.preConcat(transform2);
  688. test(true, reporter, transform);
  689. }
  690. // just want to exercise the various converters for MScalar
  691. static void test_toint(skiatest::Reporter* reporter) {
  692. SkMatrix44 mat;
  693. mat.setScale(3, 3, 3);
  694. SkMScalar sum = SkMScalarFloor(mat.get(0, 0)) +
  695. SkMScalarRound(mat.get(1, 0)) +
  696. SkMScalarCeil(mat.get(2, 0));
  697. int isum = SkMScalarFloorToInt(mat.get(0, 1)) +
  698. SkMScalarRoundToInt(mat.get(1, 2)) +
  699. SkMScalarCeilToInt(mat.get(2, 3));
  700. REPORTER_ASSERT(reporter, sum >= 0);
  701. REPORTER_ASSERT(reporter, isum >= 0);
  702. REPORTER_ASSERT(reporter, static_cast<SkMScalar>(isum) == SkIntToMScalar(isum));
  703. }
  704. DEF_TEST(Matrix44, reporter) {
  705. SkMatrix44 mat;
  706. SkMatrix44 inverse;
  707. SkMatrix44 iden1;
  708. SkMatrix44 iden2;
  709. SkMatrix44 rot;
  710. mat.setTranslate(1, 1, 1);
  711. mat.invert(&inverse);
  712. iden1.setConcat(mat, inverse);
  713. REPORTER_ASSERT(reporter, is_identity(iden1));
  714. mat.setScale(2, 2, 2);
  715. mat.invert(&inverse);
  716. iden1.setConcat(mat, inverse);
  717. REPORTER_ASSERT(reporter, is_identity(iden1));
  718. mat.setScale(SK_MScalar1/2, SK_MScalar1/2, SK_MScalar1/2);
  719. mat.invert(&inverse);
  720. iden1.setConcat(mat, inverse);
  721. REPORTER_ASSERT(reporter, is_identity(iden1));
  722. mat.setScale(3, 3, 3);
  723. rot.setRotateDegreesAbout(0, 0, -1, 90);
  724. mat.postConcat(rot);
  725. REPORTER_ASSERT(reporter, mat.invert(nullptr));
  726. mat.invert(&inverse);
  727. iden1.setConcat(mat, inverse);
  728. REPORTER_ASSERT(reporter, is_identity(iden1));
  729. iden2.setConcat(inverse, mat);
  730. REPORTER_ASSERT(reporter, is_identity(iden2));
  731. // test tiny-valued matrix inverse
  732. mat.reset();
  733. auto v = SkDoubleToMScalar(1.0e-12);
  734. mat.setScale(v,v,v);
  735. rot.setRotateDegreesAbout(0, 0, -1, 90);
  736. mat.postConcat(rot);
  737. mat.postTranslate(v,v,v);
  738. REPORTER_ASSERT(reporter, mat.invert(nullptr));
  739. mat.invert(&inverse);
  740. iden1.setConcat(mat, inverse);
  741. REPORTER_ASSERT(reporter, is_identity(iden1));
  742. // test mixed-valued matrix inverse
  743. mat.reset();
  744. mat.setScale(SkDoubleToMScalar(1.0e-2),
  745. SkDoubleToMScalar(3.0),
  746. SkDoubleToMScalar(1.0e+2));
  747. rot.setRotateDegreesAbout(0, 0, -1, 90);
  748. mat.postConcat(rot);
  749. mat.postTranslate(SkDoubleToMScalar(1.0e+2),
  750. SkDoubleToMScalar(3.0),
  751. SkDoubleToMScalar(1.0e-2));
  752. REPORTER_ASSERT(reporter, mat.invert(nullptr));
  753. mat.invert(&inverse);
  754. iden1.setConcat(mat, inverse);
  755. REPORTER_ASSERT(reporter, is_identity(iden1));
  756. // test degenerate matrix
  757. mat.reset();
  758. mat.set3x3(1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0);
  759. REPORTER_ASSERT(reporter, !mat.invert(nullptr));
  760. // test rol/col Major getters
  761. {
  762. mat.setTranslate(2, 3, 4);
  763. float dataf[16];
  764. double datad[16];
  765. mat.asColMajorf(dataf);
  766. assert16<float>(reporter, dataf,
  767. 1, 0, 0, 0,
  768. 0, 1, 0, 0,
  769. 0, 0, 1, 0,
  770. 2, 3, 4, 1);
  771. mat.asColMajord(datad);
  772. assert16<double>(reporter, datad, 1, 0, 0, 0,
  773. 0, 1, 0, 0,
  774. 0, 0, 1, 0,
  775. 2, 3, 4, 1);
  776. mat.asRowMajorf(dataf);
  777. assert16<float>(reporter, dataf, 1, 0, 0, 2,
  778. 0, 1, 0, 3,
  779. 0, 0, 1, 4,
  780. 0, 0, 0, 1);
  781. mat.asRowMajord(datad);
  782. assert16<double>(reporter, datad, 1, 0, 0, 2,
  783. 0, 1, 0, 3,
  784. 0, 0, 1, 4,
  785. 0, 0, 0, 1);
  786. }
  787. test_concat(reporter);
  788. if (false) { // avoid bit rot, suppress warning (working on making this pass)
  789. test_common_angles(reporter);
  790. }
  791. test_constructor(reporter);
  792. test_gettype(reporter);
  793. test_determinant(reporter);
  794. test_invert(reporter);
  795. test_transpose(reporter);
  796. test_get_set_double(reporter);
  797. test_set_row_col_major(reporter);
  798. test_set_3x3(reporter);
  799. test_translate(reporter);
  800. test_scale(reporter);
  801. test_map2(reporter);
  802. test_3x3_conversion(reporter);
  803. test_has_perspective(reporter);
  804. test_preserves_2d_axis_alignment(reporter);
  805. test_toint(reporter);
  806. }