transformation-matrix
Version:
2d transformation matrix functions written in ES6 syntax. Tree shaking ready!
78 lines (76 loc) • 2.51 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.decomposeTSR = decomposeTSR;
var _scale = require("./scale");
var _transform = require("./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.
*/
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 = (0, _transform.compose)(matrix, (0, _scale.scale)(-1, -1));
} else {
matrix = (0, _transform.compose)(matrix, (0, _scale.scale)(1, -1));
}
} else if (flipY) {
matrix = (0, _transform.compose)(matrix, (0, _scale.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
}
};
}
;