Source: papier-matrix-utils.js

/*
	This file is a part of "Papier" a paper-crafting tool
	
Copyright (C) 2018  Saint Pierre Thomas ( s1pierro@protonmail.fr )

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
function  distance (c1, c2)
{
	var d = Math.sqrt( (c2[0]-c1[0])*(c2[0]-c1[0])+
							 (c2[1]-c1[1])*(c2[1]-c1[1])+
							 (c2[2]-c1[2])*(c2[2]-c1[2]) );
	return d;
}
/** @constructor */
function Vector(a, b, c) {
    this.o = a;
    this.s = b;
    this.n = c
}
/**
	set the vector from two vertice wher a will be the origin
	@param {object} a - the first vertice to use to compute the vector object ( will be origin )
	@param {object} b - the seecond vertice to use to compute the vector object

*/
Vector.prototype.setFromVertices = function (a, b)
{
	if (a[0] == b[0] && a[1] == b[1] && a[2] == b[2])
	{
		this.o = [0.0, 0.0, 0.0];
		this.s = [0.0, 0.0, 0.0];
		this.n = 0.0;
	}
	var c = Math.sqrt((b[0] - a[0]) * (b[0] - a[0]) + (b[1] - a[1]) * (b[1] - a[1]) + (b[2] - a[2]) * (b[2] - a[2]));
	this.o = a;
	this.s = [(b[0] - a[0]) / c, (b[1] - a[1]) / c, (b[2] - a[2]) / c];
	this.n = c;
}
function vectfromvertices(a, b) {
	if (a[0] == b[0] && a[1] == b[1] && a[2] == b[2])
		return new Vector([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], 0.0);
    var c = Math.sqrt((b[0] - a[0]) * (b[0] - a[0]) + (b[1] - a[1]) * (b[1] - a[1]) + (b[2] - a[2]) * (b[2] - a[2]));
    return new Vector(a, [(b[0] - a[0]) / c, (b[1] - a[1]) / c, (b[2] - a[2]) / c], c)
}
window.vectfromvertices = vectfromvertices;
function magnitudevertex(a) {
    return Math.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2])
}
window.magnitudevertex = magnitudevertex;

function normalisevertex(a) {
    var b = [0, 0, 0],
        c = magnitudevertex(a);
    b[0] = a[0] / c;
    b[1] = a[1] / c;
    b[2] = a[2] / c;
    return b
}
window.normalisevertex = normalisevertex;

function vectorproduct(a, b) {
    return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]]
}
window.vectorproduct = vectorproduct;

function scalarproduct(a, b) {
    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
}
window.scalarproduct = scalarproduct;

function multiplymatrix(a, b) {
    var c = [];
    c.length = 16;
    var d, e, f;
    for (e = 0; 4 > e; e++)
        for (d = 0; 4 > d; d++)
            for (f = c[d + 4 * e] = 0; 4 > f; f++) c[d + 4 * e] += a[f + 4 * e] * b[d + 4 * f];
    return c
}
window.multiplymatrix = multiplymatrix;

function applypersp(a) {
    v1[0] = viewangle / a[2] * a[0];
    v1[1] = viewangle / a[2] * a[1];
    v1[2] = a[2];
    return v1
}
window.applypersp = applypersp;

function applymat(a, b) {

     var c = [];
    c.lenth = 3;
   c[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3];
    c[1] = a[4] * b[0] + a[5] * b[1] + a[6] * b[2] + a[7];
    c[2] = a[8] * b[0] + a[9] * b[1] + a[10] * b[2] + a[11];
    return c
}
window.applymat = applymat;

function applymatNpersp(a, b) {
    var c = [];
    c.lenth = 3;
    c[2] = a[8] * b[0] + a[9] * b[1] + a[10] * b[2] + a[11];
    c[0] = viewangle / c[2] * (a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3]);
    c[1] = viewangle / c[2] * (a[4] * b[0] + a[5] * b[1] + a[6] * b[2] + a[7]);
    return c
}
window.applymatNpersp = applymatNpersp;

function applymatNscale(a, b) {
     var c = [];
    c.lenth = 3;
   c[0] = (a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3])*scaleconst;
    c[1] = (a[4] * b[0] + a[5] * b[1] + a[6] * b[2] + a[7])*scaleconst;
    c[2] = (a[8] * b[0] + a[9] * b[1] + a[10] * b[2] + a[11])*scaleconst;
    return c
}
window.applymatNscale = applymatNscale;

function genimat() {
    var a = [];
    a.length = 16;
    var b, c;
    for (b = 0; 4 > b; b++)
        for (c = 0; 4 > c; c++) a[b + 4 * c] = b == c ? 1 : 0;
    return a
}
window.genimat = genimat;

function gentmat(a, b, c) {
    var d = genimat();
    d[3] = a;
    d[7] = b;
    d[11] = c;
    return d
}
window.gentmat = gentmat;
function gentmatfromvector(vect) {

	var a = vect.s[0]*vect.n;
	var b = vect.s[1]*vect.n;
	var c = vect.s[2]*vect.n;

	var d = genimat();

	d[3] = a;
	d[7] = b;
	d[11] = c;
	return d;
}
window.gentmatfromvector = gentmatfromvector;

function genscalemat(scale) {

	var d = genimat();

	d[0] = scale;
	d[5] = scale;
	d[10] = scale;
	d[15] = scale;

	return d;
}
window.genscalemat = genscalemat;

function genrmat(a, b, c) {
    a *= Math.PI / 180;
    var d = Math.PI / 180 * b,
        e = Math.PI / 180 * c;
    c = genimat();
    b = Math.cos(a);
    a = Math.sin(a);
    var f = Math.cos(d);
    d = Math.sin(d);
    var g = Math.cos(e);
    e = Math.sin(e);
    var h = b * d,
        k = a * d;
    c[0] = f * g;
    c[1] = -f * e;
    c[2] = -d;
    c[4] = -k * g + b * e;
    c[5] = k * e + b * g;
    c[6] = -a * f;
    c[8] = h * g + a * e;
    c[9] = -h * e + a * g;
    c[10] = b * f;
    c[3] = c[7] = c[11] = c[12] = c[13] = c[14] = 0;
    c[15] = 1;
    return c
}
window.genrmat = genrmat;
function axe_ang_to_mat ( axe, ang )
{
	var matrix = genimat();
	var rcos = Math.cos( ang );
	var rsin = Math.sin( ang );
	matrix[0] =           rcos + axe[0]*axe[0]*(1-rcos);
	matrix[4] =  axe[2] * rsin + axe[1]*axe[0]*(1-rcos);
	matrix[8] = -axe[1] * rsin + axe[2]*axe[0]*(1-rcos);
	matrix[1] = -axe[2] * rsin + axe[0]*axe[1]*(1-rcos);
	matrix[5] =           rcos + axe[1]*axe[1]*(1-rcos);
	matrix[9] =  axe[0] * rsin + axe[2]*axe[1]*(1-rcos);
	matrix[2] =  axe[1] * rsin + axe[0]*axe[2]*(1-rcos);
	matrix[6] = -axe[0] * rsin + axe[1]*axe[2]*(1-rcos);
	matrix[10] =          rcos + axe[2]*axe[2]*(1-rcos);
	matrix[3] =  matrix[7] = matrix[11] = matrix[12] = matrix[13] = matrix[14] = 0;
	matrix[15] =  1;
	return matrix;
}
window.axe_ang_to_mat = axe_ang_to_mat;
function geninterpmat (vs, ve)
{	
	l(' ## interpolation', 'lg');
	var scal, ang;
	var frmat = genimat ();
	var m = new THREE.Matrix4();
	
	// matrice de translation :
	//var translatevector = vectfromvertices( ve.o, vs.o );
	
	var a = ve.o[0] - vs.o[0];
	var b = ve.o[1] - vs.o[1];
	var c = ve.o[2] - vs.o[2];
	var ftmat = gentmat(a, b, c);

	
	// verrification du cas d'alignement des vecteurs :
	var aligntestvector = vectfromvertices( vs.s, ve.s );
	

	if ( aligntestvector.n == 0 )
	{
		// les vecteurs sont de meme sens, une matrice d'identté suffit
		// pour la rotation
		frmat = genimat ();
	}
	else if ( aligntestvector.n == 2 )
	{
		fl('OPPOSED TARGET');
	//TODO /!\ IMPORTANT
	// Les vecteur sont de sens opposés, un vecteur aligné a leurs plan normal
	// doit etre defini pour effectuer une rotation de 180°
	}
	else
	{
	
		var a = vs.s;
		var b = ve.s;
		
		var vp = vectorproduct ( a, b);	
		vp = normalisevertex (vp);
		var sp = scalarproduct ( a, b );
		// FREAK solution
		if ( sp > 1.0 && sp < 1.000001) sp = 1.0;
		if ( sp < -1.0 && sp > -1.000001) sp = 1.0;
		
      var ang = Math.acos (sp);
      
		frmat = axe_ang_to_mat (vp , ang );
	}
	var mat = gentmat( -vs.o[0], -vs.o[1], -vs.o[2]);
	var mat3 = gentmat( ve.o[0], ve.o[1], ve.o[2]);
	var mat2 = multiplymatrix (frmat, mat);

	var finalmat = multiplymatrix (mat3, mat2);

	return finalmat;

}
window.geninterpmat = geninterpmat;