#

API Docs for: 3.10.3
Show: Inherited Protected Private Deprecated

# 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} 3x3 matrix 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;