Projective transformation matrix

From JSXGraph Wiki

The underlying JavaScript code

    var board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox: [-10, 10, 10, -10]});

    // Compute a projective transformation which maps the polygon p1 to the polygon p2.
    var p1 = board.create('polygon', [[-5,0], [0,0], [0,7], [-5,7]], {fillColor: 'yellow'});
    var p2 = board.create('polygon', [[2,-3], [7,-4], [5,3], [4,4]], {fillColor: 'yellow', visible: false});

    // Two global variables containing the transformation matrix (in vector and in matrix form)
    var x_global = [];
    var mat_global = [[0,0,0], [0,0,0], [0,0,0]];

    // This function computes the transformation matrix
    var updateTransformationMatrix = function() {
        var i, j, k, M = [];

        // Initialise a 13x13 matrix to zero.
        for (i = 0; i < 13; i++) {
            M.push([0,0,0,0,0, 0,0,0,0,0, 0,0,0]);
        }

        // 12 equations and 13 unknowns for the transformation matrix mat_global such that
        // mat_global * p1 - p2 * (i, j, k, l)^T = 0
        for (i = 0; i < 3; i++) {
            for (j = 0; j < 3; j++) {
                for (k = 0; k < 4; k++) {
                    M[i * 4 + k][i * 3 + j] = p1.vertices[k].coords.usrCoords[j];
                }
            }
        }
        for (i = 0; i < 3; i++) {
            for (k = 0; k < 4; k++) {
                M[i * 4 + k][9 + k] = -p2.vertices[k].coords.usrCoords[i];
            }
        }
        // Equation 13: set mat_global[0][0] = 1.
        // Remember that in JSXGraph the coordinates are ordered by (z, x, y)
        M[12][0] = 1;

        // RHS vector
        var b = [0,0,0,0,0, 0,0,0,0,0, 0,0,1];
        // Solve the system
        x_global = JXG.Math.Numerics.Gauss(M, b);

        // Convert the solution vector into matrix form
        for (i = 0; i < 3; i++) {
            for (j = 0; j < 3; j++) {
                mat_global[i][j] = x_global[i * 3 + j].toFixed(3);
            }
        }

        // Output of the transformation matrix
        var txt = '';
        for (i = 0; i < 3; i++) {
            txt += '<tr><td>' + mat_global[i].join('</td><td>') + '</td></tr>\n';
        }
        document.getElementById('jxg_output').innerHTML = txt;
    };

    updateTransformationMatrix();

    // Functions which return the coordinates of x_global
    var x_fcts = [];
    for (let i = 0; i < 9; i++) {
        x_fcts[i] = () => x_global[i];
    }

    var transform = board.create('transform', x_fcts, {type: 'generic'});
    var p3 = board.create('polygon', [p1, transform]);

    // Whenever a point of p1 is dragged, the transfomation matrix will be updated.
    for (let i = 0; i < 4; i++) {
        p1.vertices[i].on('drag', function() {
            updateTransformationMatrix();
        });
    }