gcanvas
Version:
A Canvas API implementation that generates Gcode
270 lines (249 loc) • 7.64 kB
JavaScript
module.exports = Matrix;
var Point = require('./point');
/**
* <pre>
* _ _
* | a c tx |
* | b d ty |
* |_0 0 1 _|
* </pre>
* Creates a matrix for 2d affine transformations.
*
* concat, inverse, rotate, scale and translate return new matrices with the
* transformations applied. The matrix is not modified in place.
*
* Returns the identity matrix when called with no arguments.
* @name Matrix
* @param {Number} [a]
* @param {Number} [b]
* @param {Number} [c]
* @param {Number} [d]
* @param {Number} [tx]
* @param {Number} [ty]
* @constructor
*/
function Matrix(a, b, c, d, tx, ty) {
this.a = a !== undefined ? a : 1;
this.b = b || 0;
this.c = c || 0;
this.d = d !== undefined ? d : 1;
this.tx = tx || 0;
this.ty = ty || 0;
}
Matrix.prototype = {
clone: function() {
return new Matrix(
this.a,
this.b,
this.c,
this.d,
this.tx,
this.ty
);
},
/**
* Returns the result of this matrix multiplied by another matrix
* combining the geometric effects of the two. In mathematical terms,
* concatenating two matrixes is the same as combining them using matrix multiplication.
* If this matrix is A and the matrix passed in is B, the resulting matrix is A x B
* http://mathworld.wolfram.com/MatrixMultiplication.html
* @name concat
* @methodOf Matrix#
*
* @param {Matrix} matrix The matrix to multiply this matrix by.
* @returns The result of the matrix multiplication, a new matrix.
* @type Matrix
*/
concat: function(matrix) {
return new Matrix(
this.a * matrix.a + this.c * matrix.b,
this.b * matrix.a + this.d * matrix.b,
this.a * matrix.c + this.c * matrix.d,
this.b * matrix.c + this.d * matrix.d,
this.a * matrix.tx + this.c * matrix.ty + this.tx,
this.b * matrix.tx + this.d * matrix.ty + this.ty
);
},
/**
* Given a point in the pretransform coordinate space, returns the coordinates of
* that point after the transformation occurs. Unlike the standard transformation
* applied using the transformnew Point() method, the deltaTransformnew Point() method's
* transformation does not consider the translation parameters tx and ty.
* @name deltaTransformPoint
* @methodOf Matrix#
* @see #transformPoint
*
* @return A new point transformed by this matrix ignoring tx and ty.
* @type Point
*/
deltaTransformPoint: function(point) {
return new Point(
this.a * point.x + this.c * point.y,
this.b * point.x + this.d * point.y
);
},
/**
* Returns the inverse of the matrix.
* http://mathworld.wolfram.com/MatrixInverse.html
* @name inverse
* @methodOf Matrix#
*
* @returns A new matrix that is the inverse of this matrix.
* @type Matrix
*/
inverse: function() {
var determinant = this.a * this.d - this.b * this.c;
return new Matrix(
this.d / determinant,
-this.b / determinant,
-this.c / determinant,
this.a / determinant,
(this.c * this.ty - this.d * this.tx) / determinant,
(this.b * this.tx - this.a * this.ty) / determinant
);
},
/**
* Returns a new matrix that corresponds this matrix multiplied by a
* a rotation matrix.
* @name rotate
* @methodOf Matrix#
* @see Matrix.rotation
*
* @param {Number} theta Amount to rotate in radians.
* @param {Point} [aboutPoint] The point about which this rotation occurs. Defaults to (0,0).
* @returns A new matrix, rotated by the specified amount.
* @type Matrix
*/
rotate: function(theta, aboutPoint) {
return this.concat(Matrix.rotation(theta, aboutPoint));
},
/**
* Returns a new matrix that corresponds this matrix multiplied by a
* a scaling matrix.
* @name scale
* @methodOf Matrix#
* @see Matrix.scale
*
* @param {Number} sx
* @param {Number} [sy]
* @param {Point} [aboutPoint] The point that remains fixed during the scaling
* @type Matrix
*/
scale: function(sx, sy, aboutPoint) {
return this.concat(Matrix.scale(sx, sy, aboutPoint));
},
/**
* Returns the result of applying the geometric transformation represented by the
* Matrix object to the specified point.
* @name transformPoint
* @methodOf Matrix#
* @see #deltaTransformPoint
*
* @returns A new point with the transformation applied.
* @type Point
*/
transformPoint: function(point) {
return new Point(
this.a * point.x + this.c * point.y + this.tx,
this.b * point.x + this.d * point.y + this.ty
);
},
/**
* Translates the matrix along the x and y axes, as specified by the tx and ty parameters.
* @name translate
* @methodOf Matrix#
* @see Matrix.translation
*
* @param {Number} tx The translation along the x axis.
* @param {Number} ty The translation along the y axis.
* @returns A new matrix with the translation applied.
* @type Matrix
*/
translate: function(tx, ty) {
return this.concat(Matrix.translation(tx, ty));
}
};
/**
* Creates a matrix transformation that corresponds to the given rotation,
* around (0,0) or the specified point.
* @see Matrix#rotate
*
* @param {Number} theta Rotation in radians.
* @param {Point} [aboutPoint] The point about which this rotation occurs. Defaults to (0,0).
* @returns
* @type Matrix
*/
Matrix.rotation = function(theta, aboutPoint) {
var rotationMatrix = new Matrix(
Math.cos(theta),
Math.sin(theta),
-Math.sin(theta),
Math.cos(theta)
);
if(aboutPoint) {
rotationMatrix =
Matrix.translation(aboutPoint.x, aboutPoint.y).concat(
rotationMatrix
).concat(
Matrix.translation(-aboutPoint.x, -aboutPoint.y)
);
}
return rotationMatrix;
};
/**
* Returns a matrix that corresponds to scaling by factors of sx, sy along
* the x and y axis respectively.
* If only one parameter is given the matrix is scaled uniformly along both axis.
* If the optional aboutPoint parameter is given the scaling takes place
* about the given point.
* @see Matrix#scale
*
* @param {Number} sx The amount to scale by along the x axis or uniformly if no sy is given.
* @param {Number} [sy] The amount to scale by along the y axis.
* @param {Point} [aboutPoint] The point about which the scaling occurs. Defaults to (0,0).
* @returns A matrix transformation representing scaling by sx and sy.
* @type Matrix
*/
Matrix.scale = function(sx, sy, aboutPoint) {
sy = sy || sx;
var scaleMatrix = new Matrix(sx, 0, 0, sy);
if(aboutPoint) {
scaleMatrix =
Matrix.translation(aboutPoint.x, aboutPoint.y).concat(
scaleMatrix
).concat(
Matrix.translation(-aboutPoint.x, -aboutPoint.y)
);
}
return scaleMatrix;
};
/**
* Returns a matrix that corresponds to a translation of tx, ty.
* @see Matrix#translate
*
* @param {Number} tx The amount to translate in the x direction.
* @param {Number} ty The amount to translate in the y direction.
* @return A matrix transformation representing a translation by tx and ty.
* @type Matrix
*/
Matrix.translation = function(tx, ty) {
return new Matrix(1, 0, 0, 1, tx, ty);
};
/**
* A constant representing the identity matrix.
* @name IDENTITY
* @fieldOf Matrix
*/
Matrix.IDENTITY = new Matrix();
/**
* A constant representing the horizontal flip transformation matrix.
* @name HORIZONTAL_FLIP
* @fieldOf Matrix
*/
Matrix.HORIZONTAL_FLIP = new Matrix(-1, 0, 0, 1);
/**
* A constant representing the vertical flip transformation matrix.
* @name VERTICAL_FLIP
* @fieldOf Matrix
*/
Matrix.VERTICAL_FLIP = new Matrix(1, 0, 0, -1);