SOURCE CODE: Uize.Math.Matrix2D (view docs)

/*______________
|       ______  |   U I Z E    J A V A S C R I P T    F R A M E W O R K
|     /      /  |   ---------------------------------------------------
|    /    O /   |    MODULE : Uize.Math.Matrix2D Object
|   /    / /    |
|  /    / /  /| |    ONLINE : http://uize.com
| /____/ /__/_| | COPYRIGHT : (c)1997-2016 UIZE
|          /___ |   LICENSE : Available under MIT License or GNU General Public License
|_______________|             http://uize.com/license.html
*/

/* Module Meta Data
  type: Object
  importance: 2
  codeCompleteness: 75
  docCompleteness: 100
*/

/*?
  Introduction
    The =Uize.Math.Matrix2D= module provides support for building and applying 2-D affine transformations in a 2-dimensional plane.

    *DEVELOPERS:* `Petar Ivanov` & `Ben Ilegbodu`, original code contributed by `Zazzle Inc.`

    Not a Uize Subclass
      First off, it's worth emphasizing that the =Uize.Math.Matrix2D= object is not a =Uize.Class= subclass, but a very lightweight object.

      As such, the =Uize.Math.Matrix2D= object does not support events, does not provide state properties, does not inherit subclassing facilities from the =Uize.Class= base class, etc. This object is deliberately designed to be very lightweight and to have a really tiny footprint - in the spirit of JavaScript's native objects, such as =String=, =Number=, =Date=, and the like.
*/

Uize.module ({
  name:'Uize.Math.Matrix2D',
  builder:function () {
    'use strict';

    var
      _Uize = Uize
    ;

    /*** Constructor ***/
      var
        _object = _Uize.noNew (
          function (_coefficients) {
            var m = this;

            m._setCoefficients(
              _Uize.isArray(_coefficients)
                ? _coefficients
                : (arguments.length == 6
                  ? arguments
                  : [1.0, 0.0, 0.0, 1.0, 0.0, 0.0] // identity matrix
                )
            );
            /*?
              Constructor
                Creates an instance of the =Uize.Math.Matrix2D= object from the specified coefficients.

                SYNTAX
                .....................................
                var matrixOBJ = Uize.Math.Matrix2D(xxFLOAT, yxFLOAT, xyFLOAT, yyFLOT, xFLOAT, yFLOAT);
                .....................................

                EXAMPLE
                ..................................................................
                var matrix = Uize.Math.Matrix2D (2.0, 3.0, 4.0, 5.0, 6.0, 7.0);
                ..................................................................

                This will resultant in a matrix that looks like...

                ..................................................................
                :| 2.0 | 3.0 | 6.0 |
                :| 4.0 | 5.0 | 7.0 |
                ..................................................................

                VARIATION 1
                .....................................
                var matrixOBJ = Uize.Math.Matrix2D(coefficientsARRAY);
                .....................................

                In this variation, the coefficients, instead of being passed as individual parameters, are passed as a 6-element array.

                EXAMPLE
                ..................................................................
                var matrix = Uize.Math.Matrix2D ([2.0, 3.0, 4.0, 5.0, 6.0, 7.0]);
                ..................................................................

                This will resultant in a matrix that looks like...

                ..................................................................
                :| 2.0 | 3.0 | 6.0 |
                :| 4.0 | 5.0 | 7.0 |
                ..................................................................

                VARIATION 2
                .....................................
                var matrixOBJ = Uize.Math.Matrix2D();
                .....................................

                When no parameters are passed to the =Uize.Math.Matrix2D= `constructor`, the matrix is initialized as the identity matrix.

                EXAMPLE
                ..................................................................
                var identityMatrix = Uize.Math.Matrix2D ();
                ..................................................................

                This will resultant in a matrix that looks like...

                EXAMPLE
                ..................................................................
                :| 1 | 0 | 0 |
                :| 0 | 1 | 0 |
                ..................................................................
            */
          }
        ),
        _objectPrototype = _object.prototype
      ;


    /*** Private Instance Methods ***/
      _objectPrototype._setCoefficients = function (_coefficients) {
        var m = this;

        m._XX = +_coefficients[0];
        m._YX = +_coefficients[1];
        m._XY = +_coefficients[2];
        m._YY = +_coefficients[3];
        m._X =  +_coefficients[4];
        m._Y =  +_coefficients[5];
      };


    /*** Public Instance Methods ***/
      _objectPrototype.clone = function () {
        return _object(this.values());
        /*?
          Instance Methods
            clone
              Makes a copy of the 2-D matrix, returning a reference to the cloned =Uize.Math.Matrix2D= object.

              SYNTAX
              .....................................................
              var newMatrixOBJ = matrix.clone();
              .....................................................

              NOTES
              - Returns a reference to the cloned =Uize.Math.Matrix2D= object
        */
      };

      _objectPrototype.multiply = function (_other) {
        var m = this;

        m._setCoefficients([
          _other._XX * m._XX + _other._YX * m._XY,
          _other._XX * m._YX + _other._YX * m._YY,
          _other._XY * m._XX + _other._YY * m._XY,
          _other._XY * m._YX + _other._YY * m._YY,
          _other._XX * m._X + _other._YX * m._Y + _other._X,
          _other._XY * m._X + _other._YY * m._Y + _other._Y
        ]);

        return m;
        /*?
          Instance Methods
            multiply
              Multiplies this matrix by the specified =otherMatrixOBJ= transformation, by appending the specified =otherMatrixOBJ=.

              SYNTAX
              .....................................................
              var matrixOBJ = matrix.multiply(otherMatrixOBJ);
              .....................................................

              EXAMPLE
              .....................................................
              var matrix = Uize.Math.Matrix2D(1,0,0,1,20,30);
              matrix.multiply(Uize.Math.Matrix2D(2,0,0,2,8,9));
              .....................................................

              The matrix created in the previous example would be...

              .....................................................
              :| 2.0 | 0.0 | 48.0 |
              :| 0.0 | 2.0 | 69.0 |
              .....................................................

              NOTES
              - The other transformation is added after the orignal one (i.e. appended).
              - Returns a reference to the same =Uize.Math.Matrix2D= object
        */
      };

      _objectPrototype.rotate = function (_angle) {
        var
          _cos = Math.cos(_angle),
          _sin = Math.sin(_angle)
        ;

        return this.multiply(_object(_cos, -_sin, _sin, _cos, 0, 0));
        /*?
          Instance Methods
            rotate
              Appends to this matrix a clockwise rotation, around the origin and by the specified =angleFLOAT=.

              SYNTAX
              .....................................................
              var matrixOBJ = matrix.rotate(angleFLOAT);
              .....................................................

              EXAMPLE
              .....................................................
              var matrix = Uize.Math.Matrix2D();
              matrix.rotate(Math.PI / 4);
              .....................................................

              The matrix created in the previous example would be...

              .....................................................
              :| 0.7071 | -0.7071 | 0.0 |
              :| 0.7071 |  0.7071 | 0.0 |
              .....................................................

              NOTES
              - The rotation is added after the original transformation (i.e. appended).
              - =angleFLOAT= is in radians
              - Positive rotation is a rotation from positive X-axis towards positive Y-axis
              - Returns a reference to the same =Uize.Math.Matrix2D= object

        */
      };


      _objectPrototype.scale = function (_xScale, _yScale) {
        return this.multiply(_object(_xScale, 0, 0, _yScale, 0, 0));
        /*?
          Instance Methods
            scale
              Applies the scale vector (specified by =xScaleFLOAT= and =yScaleFLOAT=) to this matrix by appending the scale vector.

              SYNTAX
              .....................................................
              var matrixOBJ = matrix.scale(xScaleFLOAT, yScaleFLOAT);
              .....................................................

              EXAMPLE
              .....................................................
              var matrix = Uize.Math.Matrix2D(1,2,3,4,20,30);
              matrix.scale(10, 100);
              .....................................................

              The matrix created in the previous example would be...

              .....................................................
              :|  10 |   20 |  200 |
              :| 300 |  400 | 3000 |
              .....................................................

              NOTES
              - The scaling transformation is added after the original one (i.e. appended).
              - Returns a reference to the same =Uize.Math.Matrix2D= object
        */
      };

      _objectPrototype.toString = function () {
        return this.values() + '';
        /*?
          Instance Methods
            toString
              Serializes the 2-D matrix to a string.

              SYNTAX
              .....................................................
              var matrixString = matrix.toString();
              .....................................................
        */
      };

      _objectPrototype.translate = function (_x, _y) {
        var m = this;

        m._X += _x;
        m._Y += _y;

        return m;
        /*?
          Instance Methods
            translate
              Applies the translation vector (specified by xOffsetFLOAT and yOffsetFLOAT) to this matrix by appending the translation vector.

              SYNTAX
              .....................................................
              var matrixOBJ = matrix.translate(xOffsetFLOAT, yOffsetFLOAT);
              .....................................................

              EXAMPLE
              .....................................................
              var matrix = Uize.Math.Matrix2D(1,0,0,1,20,30);
              matrix.translate(8, 9);
              .....................................................

              The matrix created in the previous example would be...

              .....................................................
              :| 1 | 0 | 28 |
              :| 0 | 1 | 39 |
              .....................................................

              NOTES
              - The translation is added after the original transformation (i.e appended).
              - Returns a reference to the same =Uize.Math.Matrix2D= object
        */
      };

      _objectPrototype.values = function () {
        var m = this;
        return [m._XX, m._YX, m._XY, m._YY, m._X, m._Y];
        /*?
          Instance Methods
            values
              Gets a 6-element array of values that represent the matrix coefficients of this matrix.

              SYNTAX
              .....................................................
              var coefficiensARRAY = matrix.values();
              .....................................................

              EXAMPLE
              .....................................................
              var matrix = Uize.Math.Matrix2D();
              matrix.rotate(Math.PI / 2);
              matrix.translate(20,30);
              var matrixArray = matrix.values();
              .....................................................

              The array returned in the previous example would be =[0,-1,1,0,20,30]=.

              NOTES
              - Returns an new array containing the matrix coefficients
              - The translation coefficients are at the end of the array
        */
      };

      _objectPrototype.xForm = function (_param1, _param2) {
        var
          m = this,

          // assume two parameters
          _x = +_param1,
          _y = +_param2
        ;

        if (_Uize.isPlainObject(_param1)) { // passed a vector object
          _x = +_param1.x;
          _y = +_param1.y;
        }

        return {
          x:m._XX * _x + m._YX * _y + m._X,
          y:m._XY * _x + m._YY * _y + m._Y
        };
        /*?
          Instance Methods
            xForm
              Applies this matrix to the 2-D vector (specified by =xFLOAT= and =yFLOAT=).

              SYNTAX
              .....................................................
              var vectorOBJ = matrix.xForm(xFLOAT, yFLOAT);
              .....................................................

              EXAMPLE
              .....................................................
              var matrix = Uize.Math.Matrix2D();
              matrix.rotate(Math.PI / 2);
              var vector = matrix.xForm(1,0);
              .....................................................

              The vector returned in the previous example would be ={x:0, y:1}=.

              VARIATION
              .....................................................
              var vectorOBJ = matrix.xForm(vectorOBJ);
              .....................................................

              In this variation, the 2-D vector is specified a simple object, =vectorOBJ=, with 2 properties =x= and =y=.

              EXAMPLE
              .....................................................
              var matrix = Uize.Math.Matrix2D();
              matrix.rotate(Math.PI / 2);
              var vector = matrix.xForm({x:1, y:0});
              .....................................................

              The vector returned in the previous example would be ={x:0, y:1}=.

              NOTES
              - Returns a vector object with =x= and =y= properties
        */
      };

    return _object;
  }
});