Version 3.18.1
Show:

File: matrix/js/MatrixUtil.js

            /**
             * Matrix utilities.
             *
             * @class MatrixUtil
             * @module matrix
             **/
            
            var MatrixUtil = {
                    /**
                     * Used as value for the _rounding method.
                     *
                     * @property _rounder
                     * @private
                     */
                    _rounder: 100000,
            
                    /**
                     * Rounds values
                     *
                     * @method _round
                     * @private
                     */
                    _round: function(val) {
                        val = Math.round(val * MatrixUtil._rounder) / MatrixUtil._rounder;
                        return val;
                    },
                    /**
                     * Converts a radian value to a degree.
                     *
                     * @method rad2deg
                     * @param {Number} rad Radian value to be converted.
                     * @return Number
                     */
                    rad2deg: function(rad) {
                        var deg = rad * (180 / Math.PI);
                        return deg;
                    },
            
                    /**
                     * Converts a degree value to a radian.
                     *
                     * @method deg2rad
                     * @param {Number} deg Degree value to be converted to radian.
                     * @return Number
                     */
                    deg2rad: function(deg) {
                        var rad = deg * (Math.PI / 180);
                        return rad;
                    },
            
                    /**
                     * Converts an angle to a radian
                     *
                     * @method angle2rad
                     * @param {Objecxt} val Value to be converted to radian.
                     * @return Number
                     */
                    angle2rad: function(val) {
                        if (typeof val === 'string' && val.indexOf('rad') > -1) {
                            val = parseFloat(val);
                        } else { // default to deg
                            val = MatrixUtil.deg2rad(parseFloat(val));
                        }
            
                        return val;
                    },
            
                    /**
                     * Converts a transform object to an array of column vectors.
                     *
                     * /                                             \
                     * | matrix[0][0]   matrix[1][0]    matrix[2][0] |
                     * | matrix[0][1]   matrix[1][1]    matrix[2][1] |
                     * | matrix[0][2]   matrix[1][2]    matrix[2][2] |
                     * \                                             /
                     *
                     * @method getnxn
                     * @return Array
                     */
                    convertTransformToArray: function(matrix)
                    {
                        var matrixArray = [
                                [matrix.a, matrix.c, matrix.dx],
                                [matrix.b, matrix.d, matrix.dy],
                                [0, 0, 1]
                            ];
                        return matrixArray;
                    },
            
                    /**
                     * Returns the determinant of a given matrix.
                     *
                     * /                                             \
                     * | matrix[0][0]   matrix[1][0]    matrix[2][0] |
                     * | matrix[0][1]   matrix[1][1]    matrix[2][1] |
                     * | matrix[0][2]   matrix[1][2]    matrix[2][2] |
                     * | matrix[0][3]   matrix[1][3]    matrix[2][3] |
                     * \                                             /
                     *
                     * @method getDeterminant
                     * @param {Array} matrix An nxn matrix represented an array of vector (column) arrays. Each vector array has index for each row.
                     * @return Number
                     */
                    getDeterminant: function(matrix)
                    {
                        var determinant = 0,
                            len = matrix.length,
                            i = 0,
                            multiplier;
            
                        if(len == 2)
                        {
                            return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
                        }
                        for(; i < len; ++i)
                        {
                            multiplier = matrix[i][0];
                            if(i % 2 === 0 || i === 0)
                            {
                                determinant += multiplier * MatrixUtil.getDeterminant(MatrixUtil.getMinors(matrix, i, 0));
                            }
                            else
                            {
                                determinant -= multiplier * MatrixUtil.getDeterminant(MatrixUtil.getMinors(matrix, i, 0));
                            }
                        }
                        return determinant;
                    },
            
                    /**
                     * Returns the inverse of a matrix
                     *
                     * @method inverse
                     * @param Array matrix An array representing an nxn matrix
                     * @return Array
                     *
                     * /                                             \
                     * | matrix[0][0]   matrix[1][0]    matrix[2][0] |
                     * | matrix[0][1]   matrix[1][1]    matrix[2][1] |
                     * | matrix[0][2]   matrix[1][2]    matrix[2][2] |
                     * | matrix[0][3]   matrix[1][3]    matrix[2][3] |
                     * \                                             /
                     */
                    inverse: function(matrix)
                    {
                        var determinant = 0,
                            len = matrix.length,
                            i = 0,
                            j,
                            inverse,
                            adjunct = [],
                            //vector representing 2x2 matrix
                            minor = [];
                        if(len === 2)
                        {
                            determinant = matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
                            inverse = [
                                [matrix[1][1] * determinant, -matrix[1][0] * determinant],
                                [-matrix[0][1] * determinant, matrix[0][0] * determinant]
                            ];
                        }
                        else
                        {
                            determinant = MatrixUtil.getDeterminant(matrix);
                            for(; i < len; ++i)
                            {
                                adjunct[i] = [];
                                for(j = 0; j < len; ++j)
                                {
                                    minor = MatrixUtil.getMinors(matrix, j, i);
                                    adjunct[i][j] = MatrixUtil.getDeterminant(minor);
                                    if((i + j) % 2 !== 0 && (i + j) !== 0)
                                    {
                                        adjunct[i][j] *= -1;
                                    }
                                }
                            }
                            inverse = MatrixUtil.scalarMultiply(adjunct, 1/determinant);
                        }
                        return inverse;
                    },
            
                    /**
                     * Multiplies a matrix by a numeric value.
                     *
                     * @method scalarMultiply
                     * @param {Array} matrix The matrix to be altered.
                     * @param {Number} multiplier The number to multiply against the matrix.
                     * @return Array
                     */
                    scalarMultiply: function(matrix, multiplier)
                    {
                        var i = 0,
                            j,
                            len = matrix.length;
                        for(; i < len; ++i)
                        {
                            for(j = 0; j < len; ++j)
                            {
                                matrix[i][j] = MatrixUtil._round(matrix[i][j] * multiplier);
                            }
                        }
                        return matrix;
                    },
            
                    /**
                     * Returns the transpose for an nxn matrix.
                     *
                     * @method transpose
                     * @param matrix An nxn matrix represented by an array of vector arrays.
                     * @return Array
                     */
                    transpose: function(matrix)
                    {
                        var len = matrix.length,
                            i = 0,
                            j = 0,
                            transpose = [];
                        for(; i < len; ++i)
                        {
                            transpose[i] = [];
                            for(j = 0; j < len; ++j)
                            {
                                transpose[i].push(matrix[j][i]);
                            }
                        }
                        return transpose;
                    },
            
                    /**
                     * Returns a matrix of minors based on a matrix, column index and row index.
                     *
                     * @method getMinors
                     * @param {Array} matrix The matrix from which to extract the matrix of minors.
                     * @param {Number} columnIndex A zero-based index representing the specified column to exclude.
                     * @param {Number} rowIndex A zero-based index represeenting the specified row to exclude.
                     * @return Array
                     */
                    getMinors: function(matrix, columnIndex, rowIndex)
                    {
                        var minors = [],
                            len = matrix.length,
                            i = 0,
                            j,
                            column;
                        for(; i < len; ++i)
                        {
                            if(i !== columnIndex)
                            {
                                column = [];
                                for(j = 0; j < len; ++j)
                                {
                                    if(j !== rowIndex)
                                    {
                                        column.push(matrix[i][j]);
                                    }
                                }
                                minors.push(column);
                            }
                        }
                        return minors;
                    },
            
                    /**
                     * Returns the sign of value
                     *
                     * @method sign
                     * @param {Number} val value to be interpreted
                     * @return Number
                     */
                    sign: function(val)
                    {
                        return val === 0 ? 1 : val/Math.abs(val);
                    },
            
                    /**
                     * Multiplies a vector and a matrix
                     *
                     * @method vectorMatrixProduct
                     * @param {Array} vector Array representing a column vector
                     * @param {Array} matrix Array representing an nxn matrix
                     * @return Array
                     */
                    vectorMatrixProduct: function(vector, matrix)
                    {
                        var i,
                            j,
                            len = vector.length,
                            product = [],
                            rowProduct;
                        for(i = 0; i < len; ++i)
                        {
                            rowProduct = 0;
                            for(j = 0; j < len; ++j)
                            {
                                rowProduct += vector[i] * matrix[i][j];
                            }
                            product[i] = rowProduct;
                        }
                        return product;
                    },
            
                    /**
                     * Breaks up a 2d transform matrix into a series of transform operations.
                     *
                     * @method decompose
                     * @param {Array} matrix A 3x3 multidimensional array
                     * @return Array
                     */
                    decompose: function(matrix)
                    {
                        var a = parseFloat(matrix[0][0]),
                            b = parseFloat(matrix[1][0]),
                            c = parseFloat(matrix[0][1]),
                            d = parseFloat(matrix[1][1]),
                            dx = parseFloat(matrix[0][2]),
                            dy = parseFloat(matrix[1][2]),
                            rotate,
                            sx,
                            sy,
                            shear;
                        if((a * d - b * c) === 0)
                        {
                            return false;
                        }
                        //get length of vector(ab)
                        sx = MatrixUtil._round(Math.sqrt(a * a + b * b));
                        //normalize components of vector(ab)
                        a /= sx;
                        b /= sx;
                        shear = MatrixUtil._round(a * c + b * d);
                        c -= a * shear;
                        d -= b * shear;
                        //get length of vector(cd)
                        sy = MatrixUtil._round(Math.sqrt(c * c + d * d));
                        //normalize components of vector(cd)
                        c /= sy;
                        d /= sy;
                        shear /=sy;
                        shear = MatrixUtil._round(MatrixUtil.rad2deg(Math.atan(shear)));
                        rotate = MatrixUtil._round(MatrixUtil.rad2deg(Math.atan2(matrix[1][0], matrix[0][0])));
            
                        return [
                            ["translate", dx, dy],
                            ["rotate", rotate],
                            ["skewX", shear],
                            ["scale", sx, sy]
                        ];
                    },
            
                    /**
                     * Parses a transform string and returns an array of transform arrays.
                     *
                     * @method getTransformArray
                     * @param {String} val A transform string
                     * @return Array
                     */
                    getTransformArray: function(transform) {
                        var re = /\s*([a-z]*)\(([\w,\.,\-,\s]*)\)/gi,
                            transforms = [],
                            args,
                            m,
                            decomp,
                            methods = MatrixUtil.transformMethods;
            
                        while ((m = re.exec(transform))) {
                            if (methods.hasOwnProperty(m[1]))
                            {
                                args = m[2].split(',');
                                args.unshift(m[1]);
                                transforms.push(args);
                            }
                            else if(m[1] == "matrix")
                            {
                                args = m[2].split(',');
                                decomp = MatrixUtil.decompose([
                                    [args[0], args[2], args[4]],
                                    [args[1], args[3], args[5]],
                                    [0, 0, 1]
                                ]);
                                transforms.push(decomp[0]);
                                transforms.push(decomp[1]);
                                transforms.push(decomp[2]);
                                transforms.push(decomp[3]);
                            }
                        }
                        return transforms;
                    },
            
                    /**
                     * Returns an array of transform arrays representing transform functions and arguments.
                     *
                     * @method getTransformFunctionArray
                     * @return Array
                     */
                    getTransformFunctionArray: function(transform) {
                        var list;
                        switch(transform)
                        {
                            case "skew" :
                                list = [transform, 0, 0];
                            break;
                            case "scale" :
                                list = [transform, 1, 1];
                            break;
                            case "scaleX" :
                                list = [transform, 1];
                            break;
                            case "scaleY" :
                                list = [transform, 1];
                            break;
                            case "translate" :
                                list = [transform, 0, 0];
                            break;
                            default :
                                list = [transform, 0];
                            break;
                        }
                        return list;
                    },
            
                    /**
                     * Compares to arrays or transform functions to ensure both contain the same functions in the same
                     * order.
                     *
                     * @method compareTransformSequence
                     * @param {Array} list1 Array to compare
                     * @param {Array} list2 Array to compare
                     * @return Boolean
                     */
                    compareTransformSequence: function(list1, list2)
                    {
                        var i = 0,
                            len = list1.length,
                            len2 = list2.length,
                            isEqual = len === len2;
                        if(isEqual)
                        {
                            for(; i < len; ++i)
                            {
                                if(list1[i][0] != list2[i][0])
                                {
                                    isEqual = false;
                                    break;
                                }
                            }
                        }
                        return isEqual;
                    },
            
                    /**
                     * Mapping of possible transform method names.
                     *
                     * @property transformMethods
                     * @type Object
                     */
                    transformMethods: {
                        rotate: "rotate",
                        skew: "skew",
                        skewX: "skewX",
                        skewY: "skewY",
                        translate: "translate",
                        translateX: "translateX",
                        translateY: "tranlsateY",
                        scale: "scale",
                        scaleX: "scaleX",
                        scaleY: "scaleY"
                    }
            
            };
            
            Y.MatrixUtil = MatrixUtil;