Source: core/math/Matrix.js

core/math/Matrix.js

  1. import Point from './Point';
  2. import { PI_2 } from '../const';
  3. /**
  4. * The PixiJS Matrix class as an object, which makes it a lot faster,
  5. * here is a representation of it :
  6. * | a | c | tx|
  7. * | b | d | ty|
  8. * | 0 | 0 | 1 |
  9. *
  10. * @class
  11. * @memberof PIXI
  12. */
  13. export default class Matrix
  14. {
  15. /**
  16. * @param {number} [a=1] - x scale
  17. * @param {number} [b=0] - x skew
  18. * @param {number} [c=0] - y skew
  19. * @param {number} [d=1] - y scale
  20. * @param {number} [tx=0] - x translation
  21. * @param {number} [ty=0] - y translation
  22. */
  23. constructor(a = 1, b = 0, c = 0, d = 1, tx = 0, ty = 0)
  24. {
  25. /**
  26. * @member {number}
  27. * @default 1
  28. */
  29. this.a = a;
  30. /**
  31. * @member {number}
  32. * @default 0
  33. */
  34. this.b = b;
  35. /**
  36. * @member {number}
  37. * @default 0
  38. */
  39. this.c = c;
  40. /**
  41. * @member {number}
  42. * @default 1
  43. */
  44. this.d = d;
  45. /**
  46. * @member {number}
  47. * @default 0
  48. */
  49. this.tx = tx;
  50. /**
  51. * @member {number}
  52. * @default 0
  53. */
  54. this.ty = ty;
  55. this.array = null;
  56. }
  57. /**
  58. * Creates a Matrix object based on the given array. The Element to Matrix mapping order is as follows:
  59. *
  60. * a = array[0]
  61. * b = array[1]
  62. * c = array[3]
  63. * d = array[4]
  64. * tx = array[2]
  65. * ty = array[5]
  66. *
  67. * @param {number[]} array - The array that the matrix will be populated from.
  68. */
  69. fromArray(array)
  70. {
  71. this.a = array[0];
  72. this.b = array[1];
  73. this.c = array[3];
  74. this.d = array[4];
  75. this.tx = array[2];
  76. this.ty = array[5];
  77. }
  78. /**
  79. * sets the matrix properties
  80. *
  81. * @param {number} a - Matrix component
  82. * @param {number} b - Matrix component
  83. * @param {number} c - Matrix component
  84. * @param {number} d - Matrix component
  85. * @param {number} tx - Matrix component
  86. * @param {number} ty - Matrix component
  87. *
  88. * @return {PIXI.Matrix} This matrix. Good for chaining method calls.
  89. */
  90. set(a, b, c, d, tx, ty)
  91. {
  92. this.a = a;
  93. this.b = b;
  94. this.c = c;
  95. this.d = d;
  96. this.tx = tx;
  97. this.ty = ty;
  98. return this;
  99. }
  100. /**
  101. * Creates an array from the current Matrix object.
  102. *
  103. * @param {boolean} transpose - Whether we need to transpose the matrix or not
  104. * @param {Float32Array} [out=new Float32Array(9)] - If provided the array will be assigned to out
  105. * @return {number[]} the newly created array which contains the matrix
  106. */
  107. toArray(transpose, out)
  108. {
  109. if (!this.array)
  110. {
  111. this.array = new Float32Array(9);
  112. }
  113. const array = out || this.array;
  114. if (transpose)
  115. {
  116. array[0] = this.a;
  117. array[1] = this.b;
  118. array[2] = 0;
  119. array[3] = this.c;
  120. array[4] = this.d;
  121. array[5] = 0;
  122. array[6] = this.tx;
  123. array[7] = this.ty;
  124. array[8] = 1;
  125. }
  126. else
  127. {
  128. array[0] = this.a;
  129. array[1] = this.c;
  130. array[2] = this.tx;
  131. array[3] = this.b;
  132. array[4] = this.d;
  133. array[5] = this.ty;
  134. array[6] = 0;
  135. array[7] = 0;
  136. array[8] = 1;
  137. }
  138. return array;
  139. }
  140. /**
  141. * Get a new position with the current transformation applied.
  142. * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering)
  143. *
  144. * @param {PIXI.Point} pos - The origin
  145. * @param {PIXI.Point} [newPos] - The point that the new position is assigned to (allowed to be same as input)
  146. * @return {PIXI.Point} The new point, transformed through this matrix
  147. */
  148. apply(pos, newPos)
  149. {
  150. newPos = newPos || new Point();
  151. const x = pos.x;
  152. const y = pos.y;
  153. newPos.x = (this.a * x) + (this.c * y) + this.tx;
  154. newPos.y = (this.b * x) + (this.d * y) + this.ty;
  155. return newPos;
  156. }
  157. /**
  158. * Get a new position with the inverse of the current transformation applied.
  159. * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input)
  160. *
  161. * @param {PIXI.Point} pos - The origin
  162. * @param {PIXI.Point} [newPos] - The point that the new position is assigned to (allowed to be same as input)
  163. * @return {PIXI.Point} The new point, inverse-transformed through this matrix
  164. */
  165. applyInverse(pos, newPos)
  166. {
  167. newPos = newPos || new Point();
  168. const id = 1 / ((this.a * this.d) + (this.c * -this.b));
  169. const x = pos.x;
  170. const y = pos.y;
  171. newPos.x = (this.d * id * x) + (-this.c * id * y) + (((this.ty * this.c) - (this.tx * this.d)) * id);
  172. newPos.y = (this.a * id * y) + (-this.b * id * x) + (((-this.ty * this.a) + (this.tx * this.b)) * id);
  173. return newPos;
  174. }
  175. /**
  176. * Translates the matrix on the x and y.
  177. *
  178. * @param {number} x How much to translate x by
  179. * @param {number} y How much to translate y by
  180. * @return {PIXI.Matrix} This matrix. Good for chaining method calls.
  181. */
  182. translate(x, y)
  183. {
  184. this.tx += x;
  185. this.ty += y;
  186. return this;
  187. }
  188. /**
  189. * Applies a scale transformation to the matrix.
  190. *
  191. * @param {number} x The amount to scale horizontally
  192. * @param {number} y The amount to scale vertically
  193. * @return {PIXI.Matrix} This matrix. Good for chaining method calls.
  194. */
  195. scale(x, y)
  196. {
  197. this.a *= x;
  198. this.d *= y;
  199. this.c *= x;
  200. this.b *= y;
  201. this.tx *= x;
  202. this.ty *= y;
  203. return this;
  204. }
  205. /**
  206. * Applies a rotation transformation to the matrix.
  207. *
  208. * @param {number} angle - The angle in radians.
  209. * @return {PIXI.Matrix} This matrix. Good for chaining method calls.
  210. */
  211. rotate(angle)
  212. {
  213. const cos = Math.cos(angle);
  214. const sin = Math.sin(angle);
  215. const a1 = this.a;
  216. const c1 = this.c;
  217. const tx1 = this.tx;
  218. this.a = (a1 * cos) - (this.b * sin);
  219. this.b = (a1 * sin) + (this.b * cos);
  220. this.c = (c1 * cos) - (this.d * sin);
  221. this.d = (c1 * sin) + (this.d * cos);
  222. this.tx = (tx1 * cos) - (this.ty * sin);
  223. this.ty = (tx1 * sin) + (this.ty * cos);
  224. return this;
  225. }
  226. /**
  227. * Appends the given Matrix to this Matrix.
  228. *
  229. * @param {PIXI.Matrix} matrix - The matrix to append.
  230. * @return {PIXI.Matrix} This matrix. Good for chaining method calls.
  231. */
  232. append(matrix)
  233. {
  234. const a1 = this.a;
  235. const b1 = this.b;
  236. const c1 = this.c;
  237. const d1 = this.d;
  238. this.a = (matrix.a * a1) + (matrix.b * c1);
  239. this.b = (matrix.a * b1) + (matrix.b * d1);
  240. this.c = (matrix.c * a1) + (matrix.d * c1);
  241. this.d = (matrix.c * b1) + (matrix.d * d1);
  242. this.tx = (matrix.tx * a1) + (matrix.ty * c1) + this.tx;
  243. this.ty = (matrix.tx * b1) + (matrix.ty * d1) + this.ty;
  244. return this;
  245. }
  246. /**
  247. * Sets the matrix based on all the available properties
  248. *
  249. * @param {number} x - Position on the x axis
  250. * @param {number} y - Position on the y axis
  251. * @param {number} pivotX - Pivot on the x axis
  252. * @param {number} pivotY - Pivot on the y axis
  253. * @param {number} scaleX - Scale on the x axis
  254. * @param {number} scaleY - Scale on the y axis
  255. * @param {number} rotation - Rotation in radians
  256. * @param {number} skewX - Skew on the x axis
  257. * @param {number} skewY - Skew on the y axis
  258. * @return {PIXI.Matrix} This matrix. Good for chaining method calls.
  259. */
  260. setTransform(x, y, pivotX, pivotY, scaleX, scaleY, rotation, skewX, skewY)
  261. {
  262. this.a = Math.cos(rotation + skewY) * scaleX;
  263. this.b = Math.sin(rotation + skewY) * scaleX;
  264. this.c = -Math.sin(rotation - skewX) * scaleY;
  265. this.d = Math.cos(rotation - skewX) * scaleY;
  266. this.tx = x - ((pivotX * this.a) + (pivotY * this.c));
  267. this.ty = y - ((pivotX * this.b) + (pivotY * this.d));
  268. return this;
  269. }
  270. /**
  271. * Prepends the given Matrix to this Matrix.
  272. *
  273. * @param {PIXI.Matrix} matrix - The matrix to prepend
  274. * @return {PIXI.Matrix} This matrix. Good for chaining method calls.
  275. */
  276. prepend(matrix)
  277. {
  278. const tx1 = this.tx;
  279. if (matrix.a !== 1 || matrix.b !== 0 || matrix.c !== 0 || matrix.d !== 1)
  280. {
  281. const a1 = this.a;
  282. const c1 = this.c;
  283. this.a = (a1 * matrix.a) + (this.b * matrix.c);
  284. this.b = (a1 * matrix.b) + (this.b * matrix.d);
  285. this.c = (c1 * matrix.a) + (this.d * matrix.c);
  286. this.d = (c1 * matrix.b) + (this.d * matrix.d);
  287. }
  288. this.tx = (tx1 * matrix.a) + (this.ty * matrix.c) + matrix.tx;
  289. this.ty = (tx1 * matrix.b) + (this.ty * matrix.d) + matrix.ty;
  290. return this;
  291. }
  292. /**
  293. * Decomposes the matrix (x, y, scaleX, scaleY, and rotation) and sets the properties on to a transform.
  294. *
  295. * @param {PIXI.Transform|PIXI.TransformStatic} transform - The transform to apply the properties to.
  296. * @return {PIXI.Transform|PIXI.TransformStatic} The transform with the newly applied properties
  297. */
  298. decompose(transform)
  299. {
  300. // sort out rotation / skew..
  301. const a = this.a;
  302. const b = this.b;
  303. const c = this.c;
  304. const d = this.d;
  305. const skewX = -Math.atan2(-c, d);
  306. const skewY = Math.atan2(b, a);
  307. const delta = Math.abs(skewX + skewY);
  308. if (delta < 0.00001 || Math.abs(PI_2 - delta) < 0.00001)
  309. {
  310. transform.rotation = skewY;
  311. transform.skew.x = transform.skew.y = 0;
  312. }
  313. else
  314. {
  315. transform.rotation = 0;
  316. transform.skew.x = skewX;
  317. transform.skew.y = skewY;
  318. }
  319. // next set scale
  320. transform.scale.x = Math.sqrt((a * a) + (b * b));
  321. transform.scale.y = Math.sqrt((c * c) + (d * d));
  322. // next set position
  323. transform.position.x = this.tx;
  324. transform.position.y = this.ty;
  325. return transform;
  326. }
  327. /**
  328. * Inverts this matrix
  329. *
  330. * @return {PIXI.Matrix} This matrix. Good for chaining method calls.
  331. */
  332. invert()
  333. {
  334. const a1 = this.a;
  335. const b1 = this.b;
  336. const c1 = this.c;
  337. const d1 = this.d;
  338. const tx1 = this.tx;
  339. const n = (a1 * d1) - (b1 * c1);
  340. this.a = d1 / n;
  341. this.b = -b1 / n;
  342. this.c = -c1 / n;
  343. this.d = a1 / n;
  344. this.tx = ((c1 * this.ty) - (d1 * tx1)) / n;
  345. this.ty = -((a1 * this.ty) - (b1 * tx1)) / n;
  346. return this;
  347. }
  348. /**
  349. * Resets this Matix to an identity (default) matrix.
  350. *
  351. * @return {PIXI.Matrix} This matrix. Good for chaining method calls.
  352. */
  353. identity()
  354. {
  355. this.a = 1;
  356. this.b = 0;
  357. this.c = 0;
  358. this.d = 1;
  359. this.tx = 0;
  360. this.ty = 0;
  361. return this;
  362. }
  363. /**
  364. * Creates a new Matrix object with the same values as this one.
  365. *
  366. * @return {PIXI.Matrix} A copy of this matrix. Good for chaining method calls.
  367. */
  368. clone()
  369. {
  370. const matrix = new Matrix();
  371. matrix.a = this.a;
  372. matrix.b = this.b;
  373. matrix.c = this.c;
  374. matrix.d = this.d;
  375. matrix.tx = this.tx;
  376. matrix.ty = this.ty;
  377. return matrix;
  378. }
  379. /**
  380. * Changes the values of the given matrix to be the same as the ones in this matrix
  381. *
  382. * @param {PIXI.Matrix} matrix - The matrix to copy from.
  383. * @return {PIXI.Matrix} The matrix given in parameter with its values updated.
  384. */
  385. copy(matrix)
  386. {
  387. matrix.a = this.a;
  388. matrix.b = this.b;
  389. matrix.c = this.c;
  390. matrix.d = this.d;
  391. matrix.tx = this.tx;
  392. matrix.ty = this.ty;
  393. return matrix;
  394. }
  395. /**
  396. * A default (identity) matrix
  397. *
  398. * @static
  399. * @const
  400. */
  401. static get IDENTITY()
  402. {
  403. return new Matrix();
  404. }
  405. /**
  406. * A temp matrix
  407. *
  408. * @static
  409. * @const
  410. */
  411. static get TEMP_MATRIX()
  412. {
  413. return new Matrix();
  414. }
  415. }