1 /**
  2  * Hilo
  3  * Copyright 2015 alibaba.com
  4  * Licensed under the MIT License
  5  */
  6 
  7 /**
  8  * @class Matrix class is a transforming matrix, which declare how points in one coordinate maped to another coordinate.
  9  * @param {Number} a The value affects pixel positioning alongside the x axis when Scale or rotate images.
 10  * @param {Number} b The value affects pixel positioning alongside the y axis when rotate or skew images.
 11  * @param {Number} c The value affects pixel positioning alongside the x axis when rotate or skew images.
 12  * @param {Number} d The value affects pixel positioning alongside the y axis when Scale or rotate images.
 13  * @param {Number} tx The distance to move every point alongside the x axis.
 14  * @param {Number} ty The distance to move every point alongside the y axis.
 15  * @module hilo/geom/Matrix
 16  * @requires hilo/core/Class
 17  */
 18 var Matrix = Class.create(/** @lends Matrix.prototype */{
 19     constructor: function(a, b, c, d, tx, ty){
 20         this.a = a;
 21         this.b = b;
 22         this.c = c;
 23         this.d = d;
 24         this.tx = tx;
 25         this.ty = ty;
 26     },
 27 
 28     /**
 29      * set
 30      * @param {Number} a 
 31      * @param {Number} b 
 32      * @param {Number} c 
 33      * @param {Number} d 
 34      * @param {Number} tx
 35      * @param {Number} ty
 36      */
 37     set: function(a, b, c, d, tx, ty){
 38         this.a = a;
 39         this.b = b;
 40         this.c = c;
 41         this.d = d;
 42         this.tx = tx;
 43         this.ty = ty;
 44 	
 45 	return this;
 46     },
 47 
 48     /**
 49      * copy
 50      * @param  {Matrix} mat
 51      * @return {Matrix}  this
 52      */
 53     copy: function(mat){
 54         this.a = mat.a;
 55         this.b = mat.b;
 56         this.c = mat.c;
 57         this.d = mat.d;
 58         this.tx = mat.tx;
 59         this.ty = mat.ty;
 60 
 61         return this;
 62     },
 63 
 64     /**
 65      * clone
 66      * @return {Matrix}
 67      */
 68     clone: function(){
 69         return new Matrix().copy(this);
 70     },
 71 
 72     /**
 73      * Link a Matrix to current Matrix, in order to make geometry effects on these two composed more effective.
 74      * @param {Matrix} mtx Matrix that link to the source matrix.
 75      * @returns {Matrix} A Matrix Object.
 76      */
 77     concat: function(mtx){
 78         var args = arguments,
 79             a = this.a, b = this.b, c = this.c, d = this.d,
 80             tx = this.tx, ty = this.ty;
 81 
 82         var ma, mb, mc, md, mx, my;
 83         if(args.length >= 6){
 84             ma = args[0];
 85             mb = args[1];
 86             mc = args[2];
 87             md = args[3];
 88             mx = args[4];
 89             my = args[5];
 90         }
 91         else{
 92             ma = mtx.a;
 93             mb = mtx.b;
 94             mc = mtx.c;
 95             md = mtx.d;
 96             mx = mtx.tx;
 97             my = mtx.ty;
 98         }
 99 
100         this.a = a * ma + b * mc;
101         this.b = a * mb + b * md;
102         this.c = c * ma + d * mc;
103         this.d = c * mb + d * md;
104         this.tx = tx * ma + ty * mc + mx;
105         this.ty = tx * mb + ty * md + my;
106         return this;
107     },
108 
109     /**
110      * Rotate the Matrix Object.
111      * @param {Number} angle The angle to rotate.
112      * @returns {Matrix} A Matrix object.
113      */
114     rotate: function(angle){
115         var sin = Math.sin(angle), cos = Math.cos(angle),
116             a = this.a, b = this.b, c = this.c, d = this.d,
117             tx = this.tx, ty = this.ty;
118 
119         this.a = a * cos - b * sin;
120         this.b = a * sin + b * cos;
121         this.c = c * cos - d * sin;
122         this.d = c * sin + d * cos;
123         this.tx = tx * cos - ty * sin;
124         this.ty = tx * sin + ty * cos;
125         return this;
126     },
127 
128     /**
129      * Scale the Matrix.
130      * @param {Number} sx The value to multiply those object scale alongside the x axis.
131      * @param {Number} sy The value to multiply those object scale alongside the y axis.
132      * @returns {Matrix} A Matrix object.
133      */
134     scale: function(sx, sy){
135         this.a *= sx;
136         this.d *= sy;
137         this.c *= sx;
138         this.b *= sy;
139         this.tx *= sx;
140         this.ty *= sy;
141         return this;
142     },
143 
144     /**
145      * Translate the Matrix alongside x axis and y axis by dx and dy.
146      * @param {Number} dx Translate Matrix alongside the x axis to the right (measured in px).
147      * @param {Number} dy Translate Matrix alongside the y axis to the right (measured in px).
148      * @returns {Matrix} A Matrix object.
149      */
150     translate: function(dx, dy){
151         this.tx += dx;
152         this.ty += dy;
153         return this;
154     },
155 
156     /**
157      * Set each Matrix property a value to trigger null transform. The Matrix after applying identity matrix transformation will be exactly the same as original.
158      * @returns {Matrix} A Matrix object.
159      */
160     identity: function(){
161         this.a = this.d = 1;
162         this.b = this.c = this.tx = this.ty = 0;
163         return this;
164     },
165 
166     /**
167      * Apply an invert transformation of original Matrix. Using this invert transformation, you can reset a Matrix to a state before it had been apply some Matrix.
168      * @returns {Matrix} A Matrix object.
169      */
170     invert: function(){
171         var a = this.a;
172         var b = this.b;
173         var c = this.c;
174         var d = this.d;
175         var tx = this.tx;
176         var i = a * d - b * c;
177 
178         this.a = d / i;
179         this.b = -b / i;
180         this.c = -c / i;
181         this.d = a / i;
182         this.tx = (c * this.ty - d * tx) / i;
183         this.ty = -(a * this.ty - b * tx) / i;
184         return this;
185     },
186 
187     /**
188      * Return the result after apply a Matrix displaying transform on the point.
189      * @param {Object} point Point need to transform.
190      * @param {Boolean} round Whether ceil the coordinate values of the point.
191      * @param {Boolean} returnNew Whether return a new point.
192      * @returns {Object} 由应用矩阵转换所产生的点。
193      */
194     transformPoint: function(point, round, returnNew){
195         var x = point.x * this.a + point.y * this.c + this.tx,
196             y = point.x * this.b + point.y * this.d + this.ty;
197 
198         if(round){
199             x = x + 0.5 >> 0;
200             y = y + 0.5 >> 0;
201         }
202         if(returnNew) return {x:x, y:y};
203         point.x = x;
204         point.y = y;
205         return point;
206     }
207 
208 });
209