UNPKG

transformation-matrix

Version:

2d transformation matrix functions written in ES6 syntax. Tree shaking ready!

67 lines (61 loc) 2.25 kB
import { scale } from './scale' import { compose } from './transform' /** * Decompose a matrix into translation, scaling and rotation components, optionally * take horizontal and vertical flip in to consideration. * Note this function decomposes a matrix in rotation -> scaling -> translation order. I.e. for * certain translation T {tx, ty}, rotation R and scaling S { sx, sy }, it's only true for: * decomposeTSR(compose(T, S, R)) === { translate: T, rotation: R, scale: S } * composing in a different order may yield a different decomposition result. * @param matrix {Matrix} Affine Matrix * @param flipX {boolean} Whether the matrix contains vertical flip, i.e. mirrors on x-axis * @param flipY {boolean} Whether the matrix contains horizontal flip, i.e. mirrors on y-axis * @returns {Transform} A transform object consisted by its translation, scaling * and rotation components. */ export function decomposeTSR (matrix, flipX = false, flipY = false) { // Remove flip from the matrix first - flip could be incorrectly interpreted as // rotations (e.g. flipX + flipY = rotate by 180 degrees). // Note flipX is a vertical flip, and flipY is a horizontal flip. if (flipX) { if (flipY) { matrix = compose(matrix, scale(-1, -1)) } else { matrix = compose(matrix, scale(1, -1)) } } else if (flipY) { matrix = compose(matrix, scale(-1, 1)) } const a = matrix.a; const b = matrix.b const c = matrix.c; const d = matrix.d let scaleX, scaleY, rotation if (a !== 0 || c !== 0) { const hypotAc = Math.hypot(a, c) scaleX = hypotAc scaleY = (a * d - b * c) / hypotAc const acos = Math.acos(a / hypotAc) rotation = c > 0 ? -acos : acos } else if (b !== 0 || d !== 0) { const hypotBd = Math.hypot(b, d) scaleX = (a * d - b * c) / hypotBd scaleY = hypotBd const acos = Math.acos(b / hypotBd) rotation = Math.PI / 2 + (d > 0 ? -acos : acos) } else { scaleX = 0 scaleY = 0 rotation = 0 } // put the flip factors back if (flipY) { scaleX = -scaleX } if (flipX) { scaleY = -scaleY } return { translate: { tx: matrix.e, ty: matrix.f }, scale: { sx: scaleX, sy: scaleY }, rotation: { angle: rotation } } }