export class Mat { /** * Represents a matrix! * * @param {number[][]} entries The entries of the matrix, as an array of arrays * in row major order */ constructor(entries) { this.rows = entries.length; this.cols = entries[0].length; this.entries = entries } /** * Constructs a 4x4 identity matrix */ static identity() { return new Mat([ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1], ]); } /** * Constructs a matrix which produces a transation by the vector v. * @param {number[]} v the vector to translate by (vec3) */ static translation(v) { return new Mat([ [1, 0, 0, v[0]], [0, 1, 0, v[1]], [0, 0, 1, v[2]], [0, 0, 0, 1], ]); } /** * Constructs a matrix representing right-handed rotation about an axis by a given angle. For more * details, see: * https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Quaternion-derived_rotation_matrix * * @param {number} theta the angle to rotate by * @param {number[]} v a vector that defines the axis of rotation (vec3) */ static rotation(theta, v) { try { const vp = Vec.scale(Vec.normalize(v), Math.sin(theta/2)); var u = [Math.cos(theta/2), vp[0], vp[1], vp[2]]; } catch (error) { return this.identity(); } return new Mat([ [1 - 2*(u[2]*u[2] + u[3]*u[3]), 2*(u[1]*u[2] - u[3]*u[0]), 2*(u[1]*u[3] + u[2]*u[0]), 0], [2*(u[1]*u[2] + u[3]*u[0]), 1 - 2*(u[1]*u[1] + u[3]*u[3]), 2*(u[2]*u[3] - u[1]*u[0]), 0], [2*(u[1]*u[3] - u[2]*u[0]), 2*(u[2]*u[3] + u[1]*u[0]), 1 - 2*(u[1]*u[1] + u[2]*u[2]), 0], [0, 0, 0, 1], ]) } /** * Constructs a 3d rotation matrix which rotates from the old axis to the new axis. * * @param {number[]} oldAxis The orientation of an axis after the rotation * @param {number[]} newAxis The orientation of an axis after the rotation */ static rotateTo(oldAxis, newAxis) { let crs = Vec.cross(oldAxis, newAxis); const lengthSinAngle = Vec.norm(crs); const angle = Math.atan2(lengthSinAngle, Vec.dot(oldAxis, newAxis)); // If the axes are anti/parallel, the rotation axis is a zero vector! if(lengthSinAngle === 0) { crs = [0, 1, 0]; // Any nonzero axis will do! } return this.rotation(angle, crs); } static scale(xScale, yScale, zScale) { return new Mat([ [xScale, 0, 0, 0], [0, yScale, 0, 0], [0, 0, zScale, 0], [0, 0, 0, 1], ]); } /** * Construct and return a new matrix given by self + B * @param {*} B the matrix to add */ add(B) { let C = new Array(this.rows); for(let i=0; i