UNPKG

@zenghawtin/graph2d

Version:

Javascript library for 2d geometry

155 lines (144 loc) 4.76 kB
"use strict"; import Flatten from "../flatten"; import { Errors } from "../utils/errors"; /** * Class representing an affine transformation 3x3 matrix: * <pre> * [ a c tx * A = b d ty * 0 0 1 ] * </pre * @type {Matrix} */ export class Matrix { /** * Construct new instance of affine transformation matrix <br/> * If parameters omitted, construct identity matrix a = 1, d = 1 * @param {number} a - position(0,0) sx*cos(alpha) * @param {number} b - position (0,1) sx*sin(alpha) * @param {number} c - position (1,0) -sy*sin(alpha) * @param {number} d - position (1,1) sy*cos(alpha) * @param {number} tx - position (2,0) translation by x * @param {number} ty - position (2,1) translation by y */ constructor(a = 1, b = 0, c = 0, d = 1, tx = 0, ty = 0) { this.a = a; this.b = b; this.c = c; this.d = d; this.tx = tx; this.ty = ty; } /** * Return new cloned instance of matrix * @return {Matrix} **/ clone() { return new Matrix(this.a, this.b, this.c, this.d, this.tx, this.ty); } /** * Transform vector [x,y] using transformation matrix. <br/> * Vector [x,y] is an abstract array[2] of numbers and not a FlattenJS object <br/> * The result is also an abstract vector [x',y'] = A * [x,y]: * <code> * [x' [ ax + by + tx * y' = cx + dy + ty * 1] 1 ] * </code> * @param {number[]} vector - array[2] of numbers * @returns {number[]} transformation result - array[2] of numbers */ transform(vector) { return [ vector[0] * this.a + vector[1] * this.c + this.tx, vector[0] * this.b + vector[1] * this.d + this.ty, ]; } /** * Returns result of multiplication of this matrix by other matrix * @param {Matrix} other_matrix - matrix to multiply by * @returns {Matrix} */ multiply(other_matrix) { return new Matrix( this.a * other_matrix.a + this.c * other_matrix.b, this.b * other_matrix.a + this.d * other_matrix.b, this.a * other_matrix.c + this.c * other_matrix.d, this.b * other_matrix.c + this.d * other_matrix.d, this.a * other_matrix.tx + this.c * other_matrix.ty + this.tx, this.b * other_matrix.tx + this.d * other_matrix.ty + this.ty ); } /** * Return new matrix as a result of multiplication of the current matrix * by the matrix(1,0,0,1,tx,ty) * @param {Vector} vector - Translation by vector or * @param {number} tx - translation by x-axis * @param {number} ty - translation by y-axis * @returns {Matrix} */ translate(...args) { let tx, ty; if (args.length == 1 && !isNaN(args[0].x) && !isNaN(args[0].y)) { tx = args[0].x; ty = args[0].y; } else if ( args.length === 2 && typeof args[0] == "number" && typeof args[1] == "number" ) { tx = args[0]; ty = args[1]; } else { throw Errors.ILLEGAL_PARAMETERS; } return this.multiply(new Matrix(1, 0, 0, 1, tx, ty)); } /** * Return new matrix as a result of multiplication of the current matrix * by the matrix that defines rotation by given angle (in radians) around * center of rotation (centerX,centerY) in counterclockwise direction * @param {number} angle - angle in radians * @param {number} centerX - center of rotation * @param {number} centerY - center of rotation * @returns {Matrix} */ rotate(angle, centerX = 0.0, centerY = 0.0) { let cos = Math.cos(angle); let sin = Math.sin(angle); return this.translate(centerX, centerY) .multiply(new Matrix(cos, sin, -sin, cos, 0, 0)) .translate(-centerX, -centerY); } /** * Return new matrix as a result of multiplication of the current matrix * by the matrix (sx,0,0,sy,0,0) that defines scaling * @param {number} sx * @param {number} sy * @returns {Matrix} */ scale(sx, sy) { return this.multiply(new Matrix(sx, 0, 0, sy, 0, 0)); } /** * Returns true if two matrix are equal parameter by parameter * @param {Matrix} matrix - other matrix * @returns {boolean} true if equal, false otherwise */ equalTo(matrix) { if (!Flatten.Utils.EQ(this.tx, matrix.tx)) return false; if (!Flatten.Utils.EQ(this.ty, matrix.ty)) return false; if (!Flatten.Utils.EQ(this.a, matrix.a)) return false; if (!Flatten.Utils.EQ(this.b, matrix.b)) return false; if (!Flatten.Utils.EQ(this.c, matrix.c)) return false; if (!Flatten.Utils.EQ(this.d, matrix.d)) return false; return true; } } Flatten.Matrix = Matrix; /** * Function to create matrix equivalent to "new" constructor * @param args */ export const matrix = (...args) => new Flatten.Matrix(...args); Flatten.matrix = matrix;