Files
dss/static/js/libs/matrix.js
2013-06-22 17:06:56 +01:00

410 lines
11 KiB
JavaScript
Executable File

/**
* http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Matrix.html
*
* A great resource: http://www.senocular.com/flash/tutorials/transformmatrix/
*
* (a:Number = 1, b:Number = 0, c:Number = 0, d:Number = 1, tx:Number = 0, ty:Number = 0)
*
* @param int a
* @param int b
* @param int c
* @param int d
* @param int tx
* @param int ty
*/
Matrix = function(a, b, c, d, tx, ty){
/**
* @var int a The value that affects the positioning of pixels along the x
* axis when scaling or rotating an image.
*/
this.a = a || 1;
/**
* @var int b The value that affects the positioning of pixels
* along the y axis when rotating or skewing an image.
*/
this.b = b || 0;
/**
* @var int c The value that affects the positioning of pixels
* along the x axis when rotating or skewing an image.
*/
this.c = c || 0;
/**
* @var int d The value that affects the positioning of
* pixels along the x axis when scaling or rotating an image.
*/
this.d = d || 1;
/**
* @var int tx The distance by which to translate each point
* long the x axis.
*/
this.tx = tx || 0;
/**
* @var int ty The distance by which to translate each point
* along the y axis.
*/
this.ty = ty || 0;
};
/**
* @return {Matrix} A clone of this Matrix.
*/
Matrix.prototype.clone = function(){
return new Matrix(this.a, this.b, this.c, this.d, this.tx, this.ty);
};
/**
* Concatenates a matrix with the current matrix, effectively combining the
* geometric effects of the two.
*
* http://en.wikipedia.org/wiki/Matrix_multiplication
*
* @link {http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Matrix.html#concat()}
*
* @param {Matrix} m The matrix to contat with this matrix.
*
* @return void
*/
Matrix.prototype.concat = function(m) {
var r = new Matrix();
// 1,1
// (a,c,tx) * (a,b,0)
r.a = (this.a * m.a) + (this.c * m.b);
// 1,2
// (a,c,tx) * (c,d,0)
r.c = (this.a * m.c) + (this.c * m.d);
// 1,3
// (a,c,tx) * (tx,ty,1)
r.tx = (this.a * m.tx) + (this.c * m.ty) + this.tx;
// 2,1
// (b,d,ty) * (a,b,0)
r.b = (this.b * m.a) + (this.d * m.b);
// 2,2
//(b,d,ty) * (c,d,0)
r.d = (this.b * m.c) + (this.d * m.d);
// 2,3
// (b,d,ty) * (tx,ty,1);
r.ty = (this.b * m.tx) + (this.d * m.ty) + this.ty;
this.a = r.a;
this.b = r.b;
this.c = r.c;
this.d = r.d;
this.tx = r.tx;
this.ty = r.ty;
return this;
};
/**
* Includes parameters for scaling, rotation, and translation.
* createBox(scaleX:Number, scaleY:Number, rotation:Number = 0, tx:Number = 0,
* ty:Number = 0):void
*
* @param float scaleX
* @param float scaleY
* @param float rotation
* @param float tx
* @param float ty
*
* @return void
*/
Matrix.prototype.createBox = function(scaleX, scaleY, rotation, tx, ty){
this.identity();
this.rotate(rotation);
this.scale(scaleX, scaleY);
this.translate(tx, ty);
};
/**
* Creates the specific style of matrix expected by the beginGradientFill() and
* lineGradientStyle() methods of the Graphics class.
* createGradientBox(width:Number, height:Number, rotation:Number = 0, tx:Number =
* 0, ty:Number = 0):void
*
* @link {http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Matrix.html#createGradientBox()}
*
* @param float width
* @param float height
* @param float rotation
* @param float tx
* @param float ty
*
* @return void
*/
Matrix.prototype.createGradientBox = function(width, height,
rotation, tx, ty){
// does the graphics class have to be finished first? thinking yes.
};
/**
* Given a point in the pretransform coordinate space, returns the coordinates
* of that point after the transformation occurs.
* deltaTransformPoint(point:Point):Point
*
* @link {http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Matrix.html#deltaTransformPoint()}
*
* @param {Point} point
*
* @return {Point}
*/
Matrix.prototype.deltaTransformPoint = function(point){
var point = {
x : ( (this.a * point.x) +
(this.c * point.y) ),
y : ( (this.b * point.x) +
(this.d * point.y) )
};
return new Point(point.x, point.y);
};
/**
* Sets each matrix property to a value that causes a null transformation.
* identity():void
*
* @link {http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Matrix.html#identity()}
*
* @return void
*/
Matrix.prototype.identity = function(){
// 1 0 0
// 0 1 0
// 0 0 1
this.a = 1;
this.b = 0;
this.c = 0;
this.d = 1;
this.tx = 0;
this.ty = 0;
};
/**
* Performs the opposite transformation of the original matrix. invert():void
*
* Math below taken straight from Wikipedia:
* http://en.wikipedia.org/wiki/Matrix_inversion#Methods_of_matrix_inversion
*
* @link {http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Matrix.html#invert()}
*
* @return void
*/
Matrix.prototype.invert = 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
);
// AA-1 = A-1A = I
// Flash Matrix -> Wikipedia Matrix -> Inverted Matrix
// a c tx -> a b c -> A D G
// b d ty -> d e f -> B E H
// 0 0 1 -> g h k -> C F K
// Notice we do not need F or K
// C is necessary to test for invertability
var A = (this.d * 1) - (this.ty * 0),
B = (this.ty * 0) - (1 * this.b),
C = (this.b * 0) - (this.d_ * 0),
D = (this.tx * 0) - (this.c * 1),
E = (this.a * 1) - (this.tx * 0),
G = (this.c * this.ty) - (this.tx * this.d),
H = (this.tx * this.b) - (this.a * this.ty);
// Z = a(ek − fh) + b(fg − kd) + c(dh − eg)
// Test to see if this Matrix is invertable
if(((this.a * A) + (this.c * B) + (this.tx * C)) <= 0) { // not invertable
return null;
}
return new Matrix(A, B, D, E, G, H);
};
/**
* Applies a rotation transformation to the Matrix object.
* rotate(angle:Number):void
*
* http://en.wikipedia.org/wiki/Rotation_matrix
*
* @link {http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Matrix.html#rotate()}
*
* @return void
*
*/
Matrix.prototype.rotate = function(r){
var m = new Matrix(Math.cos(r), Math.sin(r), -Math.sin(r), Math.cos(r), 0, 0);
this.concat(m);
};
Matrix.prototype.getRotation = function(degrees) {
var scale = Math.sqrt(this.a*this.a + this.b*this.b);
// arc sin, convert from radians to degrees, round
// DO NOT USE: see update below
var sin = this.b/scale;
var radians = Math.asin(sin);
if(degrees) {
return Math.round(radians * (180/Math.PI));
}
return radians;
};
Matrix.prototype.degToRad = function(deg) {
return deg * (Math.PI / 180);
};
Matrix.prototype.radToDeg = function(rad) {
return rad * (180/Math.PI);
};
/**
* Applies a scaling transformation to the matrix. scale(sx:Number,
* sy:Number):void
*
* @link http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Matrix.html#scale()}
*
* @param float sx
* @param float sy
*
* @return void
*
*/
Matrix.prototype.scale = function(sx, sy){
var m = new Matrix(sx, 0, 0, sy, 0, 0);
this.concat(m);
};
/**
* Returns a text value listing the properties of the Matrix object.
* toString():String
*
* @link {http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Matrix.html#toString()}
*
* @return string
*
* TODO: need to test this override...see if it works.
*/
Matrix.prototype.toString = function(){
return this.a + ' ' + this.c + ' ' + this.tx + '\n' +
this.b + ' ' + this.d + ' ' + this.ty;
};
/**
* Returns the result of applying the geometric transformation represented by
* the Matrix object to the specified point. transformPoint(point:Point):Point
*
* Converts a local point to a world (matrix) point.
*
* @link {http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Matrix.html#transformPoint()}
*
* @param {Point} point
*
* @return {Point}
*
*/
Matrix.prototype.transformPoint = function(point){
// WARNING: DOUBLE CHECK MATH!! been awhile since knocking these out
// in my linear algebra class
var point = {
x : ( (this.a * point.x) +
(this.c * point.y) +
(this.tx) ),
y : ( (this.b * point.x) +
(this.d * point.y) +
(this.ty) )
};
return new Point(point.x, point.y);
};
/**
* Translates the matrix along the x and y axes, as specified by the dx and dy
* parameters. translate(dx:Number, dy:Number):void
*
* @link {http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Matrix.html#translate()}
*
* @param float dx
* @param float dy
*
* @return void
*
*/
Matrix.prototype.translate = function(dx, dy){
this.tx += dx;
this.ty += dy;
};
Matrix.prototype.toMatrixString = function () {
return 'matrix(' + this.a.toFixed(20) + ', ' +
this.b.toFixed(20) + ', ' +
this.c.toFixed(20) + ', ' +
this.d.toFixed(20) + ', ' +
this.tx.toFixed(20) + ', ' +
this.ty.toFixed(20) + ')';
};
Matrix.initWithElem = function ($elem) {
var tr = $elem.css('-webkit-transform');
var m = new Matrix();
try {
var v = tr.split('(')[1].split(')')[0].split(',');
m = new Matrix(Number(v[0]),
Number(v[1]),
Number(v[2]),
Number(v[3]),
Number(v[4]),
Number(v[5]));
} catch (e) {}
return m;
};