import { ItemTransformProps } from "../data/props/ItemTransformProps";
import "./PointType";
/**
* @typedef {Float32Array} Matrix3
*/
/**
* Matrix calculation utilities
* @typedef {Object} Matrix3Utilities
* @property {function():Matrix3} identity Create irentity matrix
* @property {function(Matrix3, Object)} projection Update projection matrix
* @property {function(ItemTransformProps, Matrix3)} transformLocal Calculate local transformation
* @property {function(Matrix3, ItemTransformProps, Matrix3)} transform Calculate global transformation
* @property {function(Matrix3, Matrix3)} inverse Create inverse matrix
* @property {function(matrix, Point):boolean} isPointInMatrix Returns true if the point in the matrix
* @property {function(Matrix3, array, Object)} calcCorners Calculate cornrers
*/
export const Matrix3Utilities = {
/**
* Create irentity matrix
* @returns {Matrix3}
*/
identity: () => new Float32Array([1, 0, 0, 1, 0, 0]),
/**
* Update projection matrix
* @param {Matrix3} destinationMatrix
* @param {Object} resolution
* @param {number} resolution.width
* @param {number} resolution.height
*/
projection: (destinationMatrix, resolution) => {
destinationMatrix[0] = 2 / resolution.width;
destinationMatrix[1] = destinationMatrix[2] = 0;
destinationMatrix[3] = -2 / resolution.height;
destinationMatrix[4] = -1;
destinationMatrix[5] = 1;
},
/**
* Calculate local transformation
* @param {Matrix3} destinationMatrix
* @param {ItemTransformProps} itemTransform
*/
transformLocal: (destinationMatrix, itemTransform) => {
const anchorX = itemTransform.anchorX,
anchorY = itemTransform.anchorY,
scaledWidth = itemTransform.scaledWidth,
scaledHeight = itemTransform.scaledHeight;
destinationMatrix[0] = itemTransform.cosRotationA * scaledWidth;
destinationMatrix[1] = itemTransform.sinRotationA * scaledWidth;
destinationMatrix[2] = -itemTransform.sinRotationB * scaledHeight;
destinationMatrix[3] = itemTransform.cosRotationB * scaledHeight;
destinationMatrix[4] =
itemTransform.x -
anchorX * destinationMatrix[0] -
anchorY * destinationMatrix[2];
destinationMatrix[5] =
itemTransform.y -
anchorX * destinationMatrix[1] -
anchorY * destinationMatrix[3];
},
/**
* Calculate global transformation
* @param {Matrix3} destinationMatrix
* @param {Matrix3} matrix
* @param {ItemTransformProps} itemTransform
*/
transform: (destinationMatrix, matrix, itemTransform) => {
const x = itemTransform.x,
y = itemTransform.y,
anchorX = itemTransform.anchorX,
anchorY = itemTransform.anchorY,
sinRotationA = itemTransform.sinRotationA,
sinRotationB = itemTransform.sinRotationB,
cosRotationA = itemTransform.cosRotationA,
cosRotationB = itemTransform.cosRotationB,
scaledWidth = itemTransform.scaledWidth,
scaledHeight = itemTransform.scaledHeight;
destinationMatrix[0] =
(cosRotationA * matrix[0] + sinRotationA * matrix[2]) * scaledWidth;
destinationMatrix[1] =
(cosRotationA * matrix[1] + sinRotationA * matrix[3]) * scaledWidth;
destinationMatrix[2] =
(cosRotationB * matrix[2] - sinRotationB * matrix[0]) * scaledHeight;
destinationMatrix[3] =
(cosRotationB * matrix[3] - sinRotationB * matrix[1]) * scaledHeight;
destinationMatrix[4] =
-anchorX * destinationMatrix[0] -
anchorY * destinationMatrix[2] +
x * matrix[0] +
y * matrix[2] +
matrix[4];
destinationMatrix[5] =
-anchorX * destinationMatrix[1] -
anchorY * destinationMatrix[3] +
x * matrix[1] +
y * matrix[3] +
matrix[5];
},
/**
* Create inverse matrix
* @param {Matrix3} destinationMatrix
* @param {Matrix3} matrix
*/
inverse: (destinationMatrix, matrix) => {
const det = 1 / (matrix[0] * matrix[3] - matrix[2] * matrix[1]);
destinationMatrix[0] = det * matrix[3];
destinationMatrix[1] = -det * matrix[1];
destinationMatrix[2] = -det * matrix[2];
destinationMatrix[3] = det * matrix[0];
destinationMatrix[4] =
det * (matrix[2] * matrix[5] - matrix[3] * matrix[4]);
destinationMatrix[5] =
-det * (matrix[0] * matrix[5] - matrix[1] * matrix[4]);
},
/**
* Returns true if the point in the matrix
* @param {Matrix3} matrix
* @param {Point} point
* @returns {boolean}
*/
isPointInMatrix: (matrix, point) => {
const x = point.x * matrix[0] + point.y * matrix[2] + matrix[4],
y = point.x * matrix[1] + point.y * matrix[3] + matrix[5];
return x >= 0 && x <= 1 && y >= 0 && y <= 1;
},
/**
* Calculate cornrers
* @param {Array<Point>} corners
* @param {Matrix3} matrix
* @param {Object} resolution
* @param {number} resolution.widthHalf
* @param {number} resolution.heightHalf
*/
calcCorners: (corners, matrix, resolution) => {
const widthHalf = resolution.widthHalf,
heightHalf = resolution.heightHalf;
corners[0].x = widthHalf + matrix[4] * widthHalf;
corners[0].y = resolution.height - (heightHalf + matrix[5] * heightHalf);
corners[1].x = corners[0].x + (matrix[0] + matrix[2]) * widthHalf;
corners[1].y = corners[0].y - (matrix[1] + matrix[3]) * heightHalf;
corners[2].x = corners[0].x + (matrix[0] + widthHalf * matrix[2]);
corners[2].y = corners[0].y - (matrix[1] + heightHalf * matrix[3]);
corners[3].x = corners[0].x + (widthHalf * matrix[0] + matrix[2]);
corners[3].y = corners[0].y - (heightHalf * matrix[1] + matrix[3]);
},
};