source: Dev/trunk/src/client/dojox/gfx/matrix.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 17.5 KB
Line 
1define(["./_base","dojo/_base/lang"],
2  function(g, lang){
3        var m = g.matrix = {};
4
5        // candidates for dojox.math:
6        var _degToRadCache = {};
7        m._degToRad = function(degree){
8                return _degToRadCache[degree] || (_degToRadCache[degree] = (Math.PI * degree / 180));
9        };
10        m._radToDeg = function(radian){ return radian / Math.PI * 180; };
11
12        m.Matrix2D = function(arg){
13                // summary:
14                //              a 2D matrix object
15                // description:
16                //              Normalizes a 2D matrix-like object. If arrays is passed,
17                //              all objects of the array are normalized and multiplied sequentially.
18                // arg: Object
19                //              a 2D matrix-like object, a number, or an array of such objects
20                if(arg){
21                        if(typeof arg == "number"){
22                                this.xx = this.yy = arg;
23                        }else if(arg instanceof Array){
24                                if(arg.length > 0){
25                                        var matrix = m.normalize(arg[0]);
26                                        // combine matrices
27                                        for(var i = 1; i < arg.length; ++i){
28                                                var l = matrix, r = m.normalize(arg[i]);
29                                                matrix = new m.Matrix2D();
30                                                matrix.xx = l.xx * r.xx + l.xy * r.yx;
31                                                matrix.xy = l.xx * r.xy + l.xy * r.yy;
32                                                matrix.yx = l.yx * r.xx + l.yy * r.yx;
33                                                matrix.yy = l.yx * r.xy + l.yy * r.yy;
34                                                matrix.dx = l.xx * r.dx + l.xy * r.dy + l.dx;
35                                                matrix.dy = l.yx * r.dx + l.yy * r.dy + l.dy;
36                                        }
37                                        lang.mixin(this, matrix);
38                                }
39                        }else{
40                                lang.mixin(this, arg);
41                        }
42                }
43        };
44
45        // the default (identity) matrix, which is used to fill in missing values
46        lang.extend(m.Matrix2D, {xx: 1, xy: 0, yx: 0, yy: 1, dx: 0, dy: 0});
47
48        lang.mixin(m, {
49                // summary:
50                //              class constants, and methods of dojox/gfx/matrix
51
52                // matrix constants
53
54                // identity: dojox/gfx/matrix.Matrix2D
55                //              an identity matrix constant: identity * (x, y) == (x, y)
56                identity: new m.Matrix2D(),
57
58                // flipX: dojox/gfx/matrix.Matrix2D
59                //              a matrix, which reflects points at x = 0 line: flipX * (x, y) == (-x, y)
60                flipX:    new m.Matrix2D({xx: -1}),
61
62                // flipY: dojox/gfx/matrix.Matrix2D
63                //              a matrix, which reflects points at y = 0 line: flipY * (x, y) == (x, -y)
64                flipY:    new m.Matrix2D({yy: -1}),
65
66                // flipXY: dojox/gfx/matrix.Matrix2D
67                //              a matrix, which reflects points at the origin of coordinates: flipXY * (x, y) == (-x, -y)
68                flipXY:   new m.Matrix2D({xx: -1, yy: -1}),
69
70                // matrix creators
71
72                translate: function(a, b){
73                        // summary:
74                        //              forms a translation matrix
75                        // description:
76                        //              The resulting matrix is used to translate (move) points by specified offsets.
77                        // a: Number|dojox/gfx.Point
78                        //              an x coordinate value, or a point-like object, which specifies offsets for both dimensions
79                        // b: Number?
80                        //              a y coordinate value
81                        // returns: dojox/gfx/matrix.Matrix2D
82                        if(arguments.length > 1){
83                                return new m.Matrix2D({dx: a, dy: b}); // dojox/gfx/matrix.Matrix2D
84                        }
85                        // branch
86                        return new m.Matrix2D({dx: a.x, dy: a.y}); // dojox/gfx/matrix.Matrix2D
87                },
88                scale: function(a, b){
89                        // summary:
90                        //              forms a scaling matrix
91                        // description:
92                        //              The resulting matrix is used to scale (magnify) points by specified offsets.
93                        // a: Number|dojox/gfx.Point
94                        //              a scaling factor used for the x coordinate, or
95                        //              a uniform scaling factor used for the both coordinates, or
96                        //              a point-like object, which specifies scale factors for both dimensions
97                        // b: Number?
98                        //              a scaling factor used for the y coordinate
99                        // returns: dojox/gfx/matrix.Matrix2D
100                        if(arguments.length > 1){
101                                return new m.Matrix2D({xx: a, yy: b}); // dojox/gfx/matrix.Matrix2D
102                        }
103                        if(typeof a == "number"){
104                                return new m.Matrix2D({xx: a, yy: a}); // dojox/gfx/matrix.Matrix2D
105                        }
106                        return new m.Matrix2D({xx: a.x, yy: a.y}); // dojox/gfx/matrix.Matrix2D
107                },
108                rotate: function(angle){
109                        // summary:
110                        //              forms a rotating matrix
111                        // description:
112                        //              The resulting matrix is used to rotate points
113                        //              around the origin of coordinates (0, 0) by specified angle.
114                        // angle: Number
115                        //              an angle of rotation in radians (>0 for CW)
116                        // returns: dojox/gfx/matrix.Matrix2D
117                        var c = Math.cos(angle);
118                        var s = Math.sin(angle);
119                        return new m.Matrix2D({xx: c, xy: -s, yx: s, yy: c}); // dojox/gfx/matrix.Matrix2D
120                },
121                rotateg: function(degree){
122                        // summary:
123                        //              forms a rotating matrix
124                        // description:
125                        //              The resulting matrix is used to rotate points
126                        //              around the origin of coordinates (0, 0) by specified degree.
127                        //              See dojox/gfx/matrix.rotate() for comparison.
128                        // degree: Number
129                        //              an angle of rotation in degrees (>0 for CW)
130                        // returns: dojox/gfx/matrix.Matrix2D
131                        return m.rotate(m._degToRad(degree)); // dojox/gfx/matrix.Matrix2D
132                },
133                skewX: function(angle) {
134                        // summary:
135                        //              forms an x skewing matrix
136                        // description:
137                        //              The resulting matrix is used to skew points in the x dimension
138                        //              around the origin of coordinates (0, 0) by specified angle.
139                        // angle: Number
140                        //              a skewing angle in radians
141                        // returns: dojox/gfx/matrix.Matrix2D
142                        return new m.Matrix2D({xy: Math.tan(angle)}); // dojox/gfx/matrix.Matrix2D
143                },
144                skewXg: function(degree){
145                        // summary:
146                        //              forms an x skewing matrix
147                        // description:
148                        //              The resulting matrix is used to skew points in the x dimension
149                        //              around the origin of coordinates (0, 0) by specified degree.
150                        //              See dojox/gfx/matrix.skewX() for comparison.
151                        // degree: Number
152                        //              a skewing angle in degrees
153                        // returns: dojox/gfx/matrix.Matrix2D
154                        return m.skewX(m._degToRad(degree)); // dojox/gfx/matrix.Matrix2D
155                },
156                skewY: function(angle){
157                        // summary:
158                        //              forms a y skewing matrix
159                        // description:
160                        //              The resulting matrix is used to skew points in the y dimension
161                        //              around the origin of coordinates (0, 0) by specified angle.
162                        // angle: Number
163                        //              a skewing angle in radians
164                        // returns: dojox/gfx/matrix.Matrix2D
165                        return new m.Matrix2D({yx: Math.tan(angle)}); // dojox/gfx/matrix.Matrix2D
166                },
167                skewYg: function(degree){
168                        // summary:
169                        //              forms a y skewing matrix
170                        // description:
171                        //              The resulting matrix is used to skew points in the y dimension
172                        //              around the origin of coordinates (0, 0) by specified degree.
173                        //              See dojox/gfx/matrix.skewY() for comparison.
174                        // degree: Number
175                        //              a skewing angle in degrees
176                        // returns: dojox/gfx/matrix.Matrix2D
177                        return m.skewY(m._degToRad(degree)); // dojox/gfx/matrix.Matrix2D
178                },
179                reflect: function(a, b){
180                        // summary:
181                        //              forms a reflection matrix
182                        // description:
183                        //              The resulting matrix is used to reflect points around a vector,
184                        //              which goes through the origin.
185                        // a: dojox/gfx.Point|Number
186                        //              a point-like object, which specifies a vector of reflection, or an X value
187                        // b: Number?
188                        //              a Y value
189                        // returns: dojox/gfx/matrix.Matrix2D
190                        if(arguments.length == 1){
191                                b = a.y;
192                                a = a.x;
193                        }
194                        // make a unit vector
195                        var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = 2 * a * b / n2;
196                        return new m.Matrix2D({xx: 2 * a2 / n2 - 1, xy: xy, yx: xy, yy: 2 * b2 / n2 - 1}); // dojox/gfx/matrix.Matrix2D
197                },
198                project: function(a, b){
199                        // summary:
200                        //              forms an orthogonal projection matrix
201                        // description:
202                        //              The resulting matrix is used to project points orthogonally on a vector,
203                        //              which goes through the origin.
204                        // a: dojox/gfx.Point|Number
205                        //              a point-like object, which specifies a vector of projection, or
206                        //              an x coordinate value
207                        // b: Number?
208                        //              a y coordinate value
209                        // returns: dojox/gfx/matrix.Matrix2D
210                        if(arguments.length == 1){
211                                b = a.y;
212                                a = a.x;
213                        }
214                        // make a unit vector
215                        var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = a * b / n2;
216                        return new m.Matrix2D({xx: a2 / n2, xy: xy, yx: xy, yy: b2 / n2}); // dojox/gfx/matrix.Matrix2D
217                },
218
219                // ensure matrix 2D conformance
220                normalize: function(matrix){
221                        // summary:
222                        //              converts an object to a matrix, if necessary
223                        // description:
224                        //              Converts any 2D matrix-like object or an array of
225                        //              such objects to a valid dojox/gfx/matrix.Matrix2D object.
226                        // matrix: Object
227                        //              an object, which is converted to a matrix, if necessary
228                        // returns: dojox/gfx/matrix.Matrix2D
229                        return (matrix instanceof m.Matrix2D) ? matrix : new m.Matrix2D(matrix); // dojox/gfx/matrix.Matrix2D
230                },
231
232                // common operations
233
234                isIdentity: function(matrix){
235                        // summary:
236                        //              returns whether the specified matrix is the identity.
237                        // matrix: dojox/gfx/matrix.Matrix2D
238                        //              a 2D matrix object to be tested
239                        // returns: Boolean
240                        return matrix.xx == 1 && matrix.xy == 0 && matrix.yx == 0 && matrix.yy == 1 && matrix.dx == 0 && matrix.dy == 0; // Boolean
241                },
242                clone: function(matrix){
243                        // summary:
244                        //              creates a copy of a 2D matrix
245                        // matrix: dojox/gfx/matrix.Matrix2D
246                        //              a 2D matrix-like object to be cloned
247                        // returns: dojox/gfx/matrix.Matrix2D
248                        var obj = new m.Matrix2D();
249                        for(var i in matrix){
250                                if(typeof(matrix[i]) == "number" && typeof(obj[i]) == "number" && obj[i] != matrix[i]) obj[i] = matrix[i];
251                        }
252                        return obj; // dojox/gfx/matrix.Matrix2D
253                },
254                invert: function(matrix){
255                        // summary:
256                        //              inverts a 2D matrix
257                        // matrix: dojox/gfx/matrix.Matrix2D
258                        //              a 2D matrix-like object to be inverted
259                        // returns: dojox/gfx/matrix.Matrix2D
260                        var M = m.normalize(matrix),
261                                D = M.xx * M.yy - M.xy * M.yx;
262                                M = new m.Matrix2D({
263                                        xx: M.yy/D, xy: -M.xy/D,
264                                        yx: -M.yx/D, yy: M.xx/D,
265                                        dx: (M.xy * M.dy - M.yy * M.dx) / D,
266                                        dy: (M.yx * M.dx - M.xx * M.dy) / D
267                                });
268                        return M; // dojox/gfx/matrix.Matrix2D
269                },
270                _multiplyPoint: function(matrix, x, y){
271                        // summary:
272                        //              applies a matrix to a point
273                        // matrix: dojox/gfx/matrix.Matrix2D
274                        //              a 2D matrix object to be applied
275                        // x: Number
276                        //              an x coordinate of a point
277                        // y: Number
278                        //              a y coordinate of a point
279                        // returns: dojox/gfx.Point
280                        return {x: matrix.xx * x + matrix.xy * y + matrix.dx, y: matrix.yx * x + matrix.yy * y + matrix.dy}; // dojox/gfx.Point
281                },
282                multiplyPoint: function(matrix, /* Number||Point */ a, /* Number? */ b){
283                        // summary:
284                        //              applies a matrix to a point
285                        // matrix: dojox/gfx/matrix.Matrix2D
286                        //              a 2D matrix object to be applied
287                        // a: Number|dojox/gfx.Point
288                        //              an x coordinate of a point, or a point
289                        // b: Number?
290                        //              a y coordinate of a point
291                        // returns: dojox/gfx.Point
292                        var M = m.normalize(matrix);
293                        if(typeof a == "number" && typeof b == "number"){
294                                return m._multiplyPoint(M, a, b); // dojox/gfx.Point
295                        }
296                        return m._multiplyPoint(M, a.x, a.y); // dojox/gfx.Point
297                },
298                multiplyRectangle: function(matrix, /*Rectangle*/ rect){
299                        // summary:
300                        //              Applies a matrix to a rectangle.
301                        // description:
302                        //              The method applies the transformation on all corners of the
303                        //              rectangle and returns the smallest rectangle enclosing the 4 transformed
304                        //              points.
305                        // matrix: dojox/gfx/matrix.Matrix2D
306                        //              a 2D matrix object to be applied.
307                        // rect: Rectangle
308                        //              the rectangle to transform.
309                        // returns: dojox/gfx.Rectangle
310                        var M = m.normalize(matrix);
311                        rect = rect || {x:0, y:0, width:0, height:0};
312                        if(m.isIdentity(M))
313                                return {x: rect.x, y: rect.y, width: rect.width, height: rect.height}; // dojo/gfx.Rectangle
314                        var p0 = m.multiplyPoint(M, rect.x, rect.y),
315                                p1 = m.multiplyPoint(M, rect.x, rect.y + rect.height),
316                                p2 = m.multiplyPoint(M, rect.x + rect.width, rect.y),
317                                p3 = m.multiplyPoint(M, rect.x + rect.width, rect.y + rect.height),
318                                minx = Math.min(p0.x, p1.x, p2.x, p3.x),
319                                miny = Math.min(p0.y, p1.y, p2.y, p3.y),
320                                maxx = Math.max(p0.x, p1.x, p2.x, p3.x),
321                                maxy = Math.max(p0.y, p1.y, p2.y, p3.y);
322                        return{ // dojo/gfx.Rectangle
323                                x: minx,
324                                y: miny,
325                                width: maxx - minx,
326                                height: maxy - miny
327                        };
328                },
329                multiply: function(matrix){
330                        // summary:
331                        //              combines matrices by multiplying them sequentially in the given order
332                        // matrix: dojox/gfx/matrix.Matrix2D
333                        //              a 2D matrix-like object,
334                        //              all subsequent arguments are matrix-like objects too
335                        var M = m.normalize(matrix);
336                        // combine matrices
337                        for(var i = 1; i < arguments.length; ++i){
338                                var l = M, r = m.normalize(arguments[i]);
339                                M = new m.Matrix2D();
340                                M.xx = l.xx * r.xx + l.xy * r.yx;
341                                M.xy = l.xx * r.xy + l.xy * r.yy;
342                                M.yx = l.yx * r.xx + l.yy * r.yx;
343                                M.yy = l.yx * r.xy + l.yy * r.yy;
344                                M.dx = l.xx * r.dx + l.xy * r.dy + l.dx;
345                                M.dy = l.yx * r.dx + l.yy * r.dy + l.dy;
346                        }
347                        return M; // dojox/gfx/matrix.Matrix2D
348                },
349
350                // high level operations
351
352                _sandwich: function(matrix, x, y){
353                        // summary:
354                        //              applies a matrix at a central point
355                        // matrix: dojox/gfx/matrix.Matrix2D
356                        //              a 2D matrix-like object, which is applied at a central point
357                        // x: Number
358                        //              an x component of the central point
359                        // y: Number
360                        //              a y component of the central point
361                        return m.multiply(m.translate(x, y), matrix, m.translate(-x, -y)); // dojox/gfx/matrix.Matrix2D
362                },
363                scaleAt: function(a, b, c, d){
364                        // summary:
365                        //              scales a picture using a specified point as a center of scaling
366                        // description:
367                        //              Compare with dojox/gfx/matrix.scale().
368                        // a: Number
369                        //              a scaling factor used for the x coordinate, or a uniform scaling factor used for both coordinates
370                        // b: Number?
371                        //              a scaling factor used for the y coordinate
372                        // c: Number|Point
373                        //              an x component of a central point, or a central point
374                        // d: Number
375                        //              a y component of a central point
376                        // returns: dojox/gfx/matrix.Matrix2D
377                        switch(arguments.length){
378                                case 4:
379                                        // a and b are scale factor components, c and d are components of a point
380                                        return m._sandwich(m.scale(a, b), c, d); // dojox/gfx/matrix.Matrix2D
381                                case 3:
382                                        if(typeof c == "number"){
383                                                return m._sandwich(m.scale(a), b, c); // dojox/gfx/matrix.Matrix2D
384                                        }
385                                        return m._sandwich(m.scale(a, b), c.x, c.y); // dojox/gfx/matrix.Matrix2D
386                        }
387                        return m._sandwich(m.scale(a), b.x, b.y); // dojox/gfx/matrix.Matrix2D
388                },
389                rotateAt: function(angle, a, b){
390                        // summary:
391                        //              rotates a picture using a specified point as a center of rotation
392                        // description:
393                        //              Compare with dojox/gfx/matrix.rotate().
394                        // angle: Number
395                        //              an angle of rotation in radians (>0 for CW)
396                        // a: Number|dojox/gfx.Point
397                        //              an x component of a central point, or a central point
398                        // b: Number?
399                        //              a y component of a central point
400                        // returns: dojox/gfx/matrix.Matrix2D
401                        if(arguments.length > 2){
402                                return m._sandwich(m.rotate(angle), a, b); // dojox/gfx/matrix.Matrix2D
403                        }
404                        return m._sandwich(m.rotate(angle), a.x, a.y); // dojox/gfx/matrix.Matrix2D
405                },
406                rotategAt: function(degree, a, b){
407                        // summary:
408                        //              rotates a picture using a specified point as a center of rotation
409                        // description:
410                        //              Compare with dojox/gfx/matrix.rotateg().
411                        // degree: Number
412                        //              an angle of rotation in degrees (>0 for CW)
413                        // a: Number|dojox/gfx.Point
414                        //              an x component of a central point, or a central point
415                        // b: Number?
416                        //              a y component of a central point
417                        // returns: dojox/gfx/matrix.Matrix2D
418                        if(arguments.length > 2){
419                                return m._sandwich(m.rotateg(degree), a, b); // dojox/gfx/matrix.Matrix2D
420                        }
421                        return m._sandwich(m.rotateg(degree), a.x, a.y); // dojox/gfx/matrix.Matrix2D
422                },
423                skewXAt: function(angle, a, b){
424                        // summary:
425                        //              skews a picture along the x axis using a specified point as a center of skewing
426                        // description:
427                        //              Compare with dojox/gfx/matrix.skewX().
428                        // angle: Number
429                        //              a skewing angle in radians
430                        // a: Number|dojox/gfx.Point
431                        //              an x component of a central point, or a central point
432                        // b: Number?
433                        //              a y component of a central point
434                        // returns: dojox/gfx/matrix.Matrix2D
435                        if(arguments.length > 2){
436                                return m._sandwich(m.skewX(angle), a, b); // dojox/gfx/matrix.Matrix2D
437                        }
438                        return m._sandwich(m.skewX(angle), a.x, a.y); // dojox/gfx/matrix.Matrix2D
439                },
440                skewXgAt: function(degree, a, b){
441                        // summary:
442                        //              skews a picture along the x axis using a specified point as a center of skewing
443                        // description:
444                        //              Compare with dojox/gfx/matrix.skewXg().
445                        // degree: Number
446                        //              a skewing angle in degrees
447                        // a: Number|dojox/gfx.Point
448                        //              an x component of a central point, or a central point
449                        // b: Number?
450                        //              a y component of a central point
451                        // returns: dojox/gfx/matrix.Matrix2D
452                        if(arguments.length > 2){
453                                return m._sandwich(m.skewXg(degree), a, b); // dojox/gfx/matrix.Matrix2D
454                        }
455                        return m._sandwich(m.skewXg(degree), a.x, a.y); // dojox/gfx/matrix.Matrix2D
456                },
457                skewYAt: function(angle, a, b){
458                        // summary:
459                        //              skews a picture along the y axis using a specified point as a center of skewing
460                        // description:
461                        //              Compare with dojox/gfx/matrix.skewY().
462                        // angle: Number
463                        //              a skewing angle in radians
464                        // a: Number|dojox/gfx.Point
465                        //              an x component of a central point, or a central point
466                        // b: Number?
467                        //              a y component of a central point
468                        // returns: dojox/gfx/matrix.Matrix2D
469                        if(arguments.length > 2){
470                                return m._sandwich(m.skewY(angle), a, b); // dojox/gfx/matrix.Matrix2D
471                        }
472                        return m._sandwich(m.skewY(angle), a.x, a.y); // dojox/gfx/matrix.Matrix2D
473                },
474                skewYgAt: function(/* Number */ degree, /* Number||Point */ a, /* Number? */ b){
475                        // summary:
476                        //              skews a picture along the y axis using a specified point as a center of skewing
477                        // description:
478                        //              Compare with dojox/gfx/matrix.skewYg().
479                        // degree: Number
480                        //              a skewing angle in degrees
481                        // a: Number|dojox/gfx.Point
482                        //              an x component of a central point, or a central point
483                        // b: Number?
484                        //              a y component of a central point
485                        // returns: dojox/gfx/matrix.Matrix2D
486                        if(arguments.length > 2){
487                                return m._sandwich(m.skewYg(degree), a, b); // dojox/gfx/matrix.Matrix2D
488                        }
489                        return m._sandwich(m.skewYg(degree), a.x, a.y); // dojox/gfx/matrix.Matrix2D
490                }
491
492                //TODO: rect-to-rect mapping, scale-to-fit (isotropic and anisotropic versions)
493
494        });
495        // propagate Matrix2D up
496        g.Matrix2D = m.Matrix2D;
497
498        return m;
499});
500
501
Note: See TracBrowser for help on using the repository browser.