/**
* Math functions, used within BIMSURFER, but also available for you to use in your application code.
* @module BIMSURFER
* @submodule math
* @class math
* @static
*/
(function () {
"use strict";
/*
* Optimizations made based on glMatrix by Brandon Jones
*/
/*
* Copyright (c) 2010 Brandon Jones
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
BIMSURFER.math = {
/**
* Returns a new UUID.
* @method createUUID
* @static
* @return string The new UUID
*/
createUUID: function () {
// http://www.broofa.com/Tools/Math.uuid.htm
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
var uuid = new Array(36);
var rnd = 0, r;
return function () {
for (var i = 0; i < 36; i++) {
if (i === 8 || i === 13 || i === 18 || i === 23) {
uuid[ i ] = '-';
} else if (i === 14) {
uuid[ i ] = '4';
} else {
if (rnd <= 0x02) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0;
r = rnd & 0xf;
rnd = rnd >> 4;
uuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ];
}
}
return uuid.join('');
};
}(),
vec2: function () {
return new Float64Array(2);
},
vec3: function () {
return new Float64Array(3);
},
vec4: function () {
return new Float64Array(4);
},
/**
*
*/
mat3: function () {
return new Float64Array(9);
},
/**
*
*/
mat4: function () {
return new Float64Array(16);
},
/**
* Floating-point modulus
* @param a
* @param b
* @returns {*}
*/
fmod: function (a, b) {
if (a < b) {
console.error("BIMSURFER.math.fmod : Attempting to find modulus within negative range - would be infinite loop - ignoring");
return a;
}
while (b <= a) {
a -= b;
}
return a;
},
/**
* Negates a four-element vector.
* @method negateVec4
* @param {Array(Number)} v Vector to negate
* @param {Array(Number)} [dest] Destination vector
* @return {Array(Number)} dest if specified, v otherwise
*/
negateVec4: function (v, dest) {
if (!dest) {
dest = v;
}
dest[0] = -v[0];
dest[1] = -v[1];
dest[2] = -v[2];
dest[3] = -v[3];
return dest;
},
/**
* Adds one four-element vector to another.
* @method addVec4
* @param {Array(Number)} u First vector
* @param {Array(Number)} v Second vector
* @param {Array(Number)} [dest] Destination vector
* @return {Array(Number)} dest if specified, u otherwise
*/
addVec4: function (u, v, dest) {
if (!dest) {
dest = u;
}
dest[0] = u[0] + v[0];
dest[1] = u[1] + v[1];
dest[2] = u[2] + v[2];
dest[3] = u[3] + v[3];
return dest;
},
/**
* Adds a scalar value to each element of a four-element vector.
* @method addVec4Scalar
* @param {Array(Number)} v The vector
* @param {Number} s The scalar
* @param {Array(Number)} [dest] Destination vector
* @return {Array(Number)} dest if specified, v otherwise
*/
addVec4Scalar: function (v, s, dest) {
if (!dest) {
dest = v;
}
dest[0] = v[0] + s;
dest[1] = v[1] + s;
dest[2] = v[2] + s;
dest[3] = v[3] + s;
return dest;
},
/**
* Adds one three-element vector to another.
* @method addVec3
* @param {Array(Number)} u First vector
* @param {Array(Number)} v Second vector
* @param {Array(Number)} [dest] Destination vector
* @return {Array(Number)} dest if specified, u otherwise
*/
addVec3: function (u, v, dest) {
if (!dest) {
dest = u;
}
dest[0] = u[0] + v[0];
dest[1] = u[1] + v[1];
dest[2] = u[2] + v[2];
return dest;
},
/**
* Adds a scalar value to each element of a three-element vector.
* @method addVec4Scalar
* @param {Array(Number)} v The vector
* @param {Number} s The scalar
* @param {Array(Number)} [dest] Destination vector
* @return {Array(Number)} dest if specified, v otherwise
*/
addVec3Scalar: function (v, s, dest) {
if (!dest) {
dest = v;
}
dest[0] = v[0] + s;
dest[1] = v[1] + s;
dest[2] = v[2] + s;
return dest;
},
/**
* Subtracts one four-element vector from another.
* @method subVec4
* @param {Array(Number)} u First vector
* @param {Array(Number)} v Vector to subtract
* @param {Array(Number)} [dest] Destination vector
* @return {Array(Number)} dest if specified, u otherwise
*/
subVec4: function (u, v, dest) {
if (!dest) {
dest = u;
}
dest[0] = u[0] - v[0];
dest[1] = u[1] - v[1];
dest[2] = u[2] - v[2];
dest[3] = u[3] - v[3];
return dest;
},
/**
* Subtracts one three-element vector from another.
* @method subVec3
* @param {Array(Number)} u First vector
* @param {Array(Number)} v Vector to subtract
* @param {Array(Number)} [dest] Destination vector
* @return {Array(Number)} dest if specified, u otherwise
*/
subVec3: function (u, v, dest) {
if (!dest) {
dest = u;
}
dest[0] = u[0] - v[0];
dest[1] = u[1] - v[1];
dest[2] = u[2] - v[2];
return dest;
},
/**
* Subtracts one two-element vector from another.
* @method subVec2
* @param {Array(Number)} u First vector
* @param {Array(Number)} v Vector to subtract
* @param {Array(Number)} [dest] Destination vector
* @return {Array(Number)} dest if specified, u otherwise
*/
subVec2: function (u, v, dest) {
if (!dest) {
dest = u;
}
dest[0] = u[0] - v[0];
dest[1] = u[1] - v[1];
return dest;
},
/**
* Subtracts a scalar value from each element of a four-element vector.
* @method subVec4Scalar
* @param {Array(Number)} v The vector
* @param {Number} s The scalar
* @param {Array(Number)} [dest] Destination vector
* @return {Array(Number)} dest if specified, v otherwise
*/
subVec4Scalar: function (v, s, dest) {
if (!dest) {
dest = v;
}
dest[0] = v[0] - s;
dest[1] = v[1] - s;
dest[2] = v[2] - s;
dest[3] = v[3] - s;
return dest;
},
/**
* Sets each element of a 4-element vector to a scalar value minus the value of that element.
* @method subScalarVec4
* @param {Array(Number)} v The vector
* @param {Number} s The scalar
* @param {Array(Number)} [dest] Destination vector
* @return {Array(Number)} dest if specified, v otherwise
*/
subScalarVec4: function (v, s, dest) {
if (!dest) {
dest = v;
}
dest[0] = s - v[0];
dest[1] = s - v[1];
dest[2] = s - v[2];
dest[3] = s - v[3];
return dest;
},
/**
* Multiplies one three-element vector by another.
* @method mulVec3
* @param {Array(Number)} u First vector
* @param {Array(Number)} v Second vector
* @param {Array(Number)} [dest] Destination vector
* @return {Array(Number)} dest if specified, u otherwise
*/
mulVec4: function (u, v, dest) {
if (!dest) {
dest = u;
}
dest[0] = u[0] * v[0];
dest[1] = u[1] * v[1];
dest[2] = u[2] * v[2];
dest[3] = u[3] * v[3];
return dest;
},
/**
* Multiplies each element of a four-element vector by a scalar.
* @method mulVec34calar
* @param {Array(Number)} v The vector
* @param {Number} s The scalar
* @param {Array(Number)} [dest] Destination vector
* @return {Array(Number)} dest if specified, v otherwise
*/
mulVec4Scalar: function (v, s, dest) {
if (!dest) {
dest = v;
}
dest[0] = v[0] * s;
dest[1] = v[1] * s;
dest[2] = v[2] * s;
dest[3] = v[3] * s;
return dest;
},
/**
* Multiplies each element of a three-element vector by a scalar.
* @method mulVec3Scalar
* @param {Array(Number)} v The vector
* @param {Number} s The scalar
* @param {Array(Number)} [dest] Destination vector
* @return {Array(Number)} dest if specified, v otherwise
*/
mulVec3Scalar: function (v, s, dest) {
if (!dest) {
dest = v;
}
dest[0] = v[0] * s;
dest[1] = v[1] * s;
dest[2] = v[2] * s;
return dest;
},
/**
* Multiplies each element of a two-element vector by a scalar.
* @method mulVec2Scalar
* @param {Array(Number)} v The vector
* @param {Number} s The scalar
* @param {Array(Number)} [dest] Destination vector
* @return {Array(Number)} dest if specified, v otherwise
*/
mulVec2Scalar: function (v, s, dest) {
if (!dest) {
dest = v;
}
dest[0] = v[0] * s;
dest[1] = v[1] * s;
return dest;
},
/**
* Divides one three-element vector by another.
* @method divVec3
* @static
* @param {Array(Number)} u First vector
* @param {Array(Number)} v Second vector
* @param {Array(Number)} [dest] Destination vector
* @return {Array(Number)} dest if specified, u otherwise
*/
divVec3: function (u, v, dest) {
if (!dest) {
dest = u;
}
dest[0] = u[0] / v[0];
dest[1] = u[1] / v[1];
dest[2] = u[2] / v[2];
return dest;
},
/**
* Divides one four-element vector by another.
* @method divVec4
* @static
* @param {Array(Number)} u First vector
* @param {Array(Number)} v Second vector
* @param {Array(Number)} [dest] Destination vector
* @return {Array(Number)} dest if specified, u otherwise
*/
divVec4: function (u, v, dest) {
if (!dest) {
dest = u;
}
dest[0] = u[0] / v[0];
dest[1] = u[1] / v[1];
dest[2] = u[2] / v[2];
dest[3] = u[3] / v[3];
return dest;
},
/**
* @param v vec3
* @param s scalar
* @param dest vec3 - optional destination
* @return [] dest if specified, v otherwise
*
*/
divScalarVec3: function (s, v, dest) {
if (!dest) {
dest = v;
}
dest[0] = s / v[0];
dest[1] = s / v[1];
dest[2] = s / v[2];
return dest;
},
/**
* @param v vec3
* @param s scalar
* @param dest vec3 - optional destination
* @return [] dest if specified, v otherwise
*
*/
divVec3Scalar: function (v, s, dest) {
if (!dest) {
dest = v;
}
dest[0] = v[0] / s;
dest[1] = v[1] / s;
dest[2] = v[2] / s;
return dest;
},
/**
* @param v vec4
* @param s scalar
* @param dest vec4 - optional destination
* @return [] dest if specified, v otherwise
*
*/
divVec4Scalar: function (v, s, dest) {
if (!dest) {
dest = v;
}
dest[0] = v[0] / s;
dest[1] = v[1] / s;
dest[2] = v[2] / s;
dest[3] = v[3] / s;
return dest;
},
/**
* @param s scalar
* @param v vec4
* @param dest vec4 - optional destination
* @return [] dest if specified, v otherwise
*/
divScalarVec4: function (s, v, dest) {
if (!dest) {
dest = v;
}
dest[0] = s / v[0];
dest[1] = s / v[1];
dest[2] = s / v[2];
dest[3] = s / v[3];
return dest;
},
dotVec4: function (u, v) {
return (u[0] * v[0] + u[1] * v[1] + u[2] * v[2] + u[3] * v[3]);
},
cross3Vec4: function (u, v) {
var u0 = u[0], u1 = u[1], u2 = u[2];
var v0 = v[0], v1 = v[1], v2 = v[2];
return [
u1 * v2 - u2 * v1,
u2 * v0 - u0 * v2,
u0 * v1 - u1 * v0,
0.0];
},
/**
* @param u vec3
* @param v vec3
* @param dest vec3 - optional destination
* @return [] dest if specified, u otherwise
*
*/
cross3Vec3: function (u, v, dest) {
if (!dest) {
dest = u;
}
var x = u[0], y = u[1], z = u[2];
var x2 = v[0], y2 = v[1], z2 = v[2];
dest[0] = y * z2 - z * y2;
dest[1] = z * x2 - x * z2;
dest[2] = x * y2 - y * x2;
return dest;
},
/** */
sqLenVec4: function (v) {
return BIMSURFER.math.dotVec4(v, v);
},
/** */
lenVec4: function (v) {
return Math.sqrt(BIMSURFER.math.sqLenVec4(v));
},
/** */
dotVec3: function (u, v) {
return (u[0] * v[0] + u[1] * v[1] + u[2] * v[2]);
},
/** */
dotVec2: function (u, v) {
return (u[0] * v[0] + u[1] * v[1]);
},
/** */
sqLenVec3: function (v) {
return BIMSURFER.math.dotVec3(v, v);
},
/** */
sqLenVec2: function (v) {
return BIMSURFER.math.dotVec2(v, v);
},
/** */
lenVec3: function (v) {
return Math.sqrt(BIMSURFER.math.sqLenVec3(v));
},
/** */
lenVec2: function (v) {
return Math.sqrt(BIMSURFER.math.sqLenVec2(v));
},
/**
* @param v vec3
* @param dest vec3 - optional destination
* @return [] dest if specified, v otherwise
*
*/
rcpVec3: function (v, dest) {
return BIMSURFER.math.divScalarVec3(1.0, v, dest);
},
/**
* @param v vec4
* @param dest vec4 - optional destination
* @return [] dest if specified, v otherwise
*
*/
normalizeVec4: function (v, dest) {
var f = 1.0 / BIMSURFER.math.lenVec4(v);
return BIMSURFER.math.mulVec4Scalar(v, f, dest);
},
/** */
normalizeVec3: function (v, dest) {
var f = 1.0 / BIMSURFER.math.lenVec3(v);
return BIMSURFER.math.mulVec3Scalar(v, f, dest);
},
//
normalizeVec2: function (v, dest) {
var f = 1.0 / BIMSURFER.math.lenVec2(v);
return BIMSURFER.math.mulVec2Scalar(v, f, dest);
},
/** */
/** */
dupMat4: function (m) {
return m.slice(0, 16);
},
/** */
mat4To3: function (m) {
return [
m[0], m[1], m[2],
m[4], m[5], m[6],
m[8], m[9], m[10]
];
},
/** */
m4s: function (s) {
return [
s, s, s, s,
s, s, s, s,
s, s, s, s,
s, s, s, s
];
},
/** */
setMat4ToZeroes: function () {
return BIMSURFER.math.m4s(0.0);
},
/** */
setMat4ToOnes: function () {
return BIMSURFER.math.m4s(1.0);
},
/** */
diagonalMat4v: function (v) {
return [
v[0], 0.0, 0.0, 0.0,
0.0, v[1], 0.0, 0.0,
0.0, 0.0, v[2], 0.0,
0.0, 0.0, 0.0, v[3]
];
},
/** */
diagonalMat4c: function (x, y, z, w) {
return BIMSURFER.math.diagonalMat4v([x, y, z, w]);
},
/** */
diagonalMat4s: function (s) {
return BIMSURFER.math.diagonalMat4c(s, s, s, s);
},
/** */
identityMat4: function () {
return BIMSURFER.math.diagonalMat4v([1.0, 1.0, 1.0, 1.0]);
},
/** */
isIdentityMat4: function (m) {
if (m[0] !== 1.0 || m[1] !== 0.0 || m[2] !== 0.0 || m[3] !== 0.0 ||
m[4] !== 0.0 || m[5] !== 1.0 || m[6] !== 0.0 || m[7] !== 0.0 ||
m[8] !== 0.0 || m[9] !== 0.0 || m[10] !== 1.0 || m[11] !== 0.0 ||
m[12] !== 0.0 || m[13] !== 0.0 || m[14] !== 0.0 || m[15] !== 1.0) {
return false;
}
return true;
},
/**
* @param m mat4
* @param dest mat4 - optional destination
* @return {mat4} dest if specified, m otherwise
*
*/
negateMat4: function (m, dest) {
if (!dest) {
dest = m;
}
dest[0] = -m[0];
dest[1] = -m[1];
dest[2] = -m[2];
dest[3] = -m[3];
dest[4] = -m[4];
dest[5] = -m[5];
dest[6] = -m[6];
dest[7] = -m[7];
dest[8] = -m[8];
dest[9] = -m[9];
dest[10] = -m[10];
dest[11] = -m[11];
dest[12] = -m[12];
dest[13] = -m[13];
dest[14] = -m[14];
dest[15] = -m[15];
return dest;
},
/**
* @param a mat4
* @param b mat4
* @param dest mat4 - optional destination
* @return {mat4} dest if specified, a otherwise
*
*/
addMat4: function (a, b, dest) {
if (!dest) {
dest = a;
}
dest[0] = a[0] + b[0];
dest[1] = a[1] + b[1];
dest[2] = a[2] + b[2];
dest[3] = a[3] + b[3];
dest[4] = a[4] + b[4];
dest[5] = a[5] + b[5];
dest[6] = a[6] + b[6];
dest[7] = a[7] + b[7];
dest[8] = a[8] + b[8];
dest[9] = a[9] + b[9];
dest[10] = a[10] + b[10];
dest[11] = a[11] + b[11];
dest[12] = a[12] + b[12];
dest[13] = a[13] + b[13];
dest[14] = a[14] + b[14];
dest[15] = a[15] + b[15];
return dest;
},
/**
* @param m mat4
* @param s scalar
* @param dest mat4 - optional destination
* @return {mat4} dest if specified, m otherwise
*
*/
addMat4Scalar: function (m, s, dest) {
if (!dest) {
dest = m;
}
dest[0] = m[0] + s;
dest[1] = m[1] + s;
dest[2] = m[2] + s;
dest[3] = m[3] + s;
dest[4] = m[4] + s;
dest[5] = m[5] + s;
dest[6] = m[6] + s;
dest[7] = m[7] + s;
dest[8] = m[8] + s;
dest[9] = m[9] + s;
dest[10] = m[10] + s;
dest[11] = m[11] + s;
dest[12] = m[12] + s;
dest[13] = m[13] + s;
dest[14] = m[14] + s;
dest[15] = m[15] + s;
return dest;
},
/** */
addScalarMat4: function (s, m, dest) {
return BIMSURFER.math.addMat4Scalar(m, s, dest);
},
/**
* @param a mat4
* @param b mat4
* @param dest mat4 - optional destination
* @return {mat4} dest if specified, a otherwise
*
*/
subMat4: function (a, b, dest) {
if (!dest) {
dest = a;
}
dest[0] = a[0] - b[0];
dest[1] = a[1] - b[1];
dest[2] = a[2] - b[2];
dest[3] = a[3] - b[3];
dest[4] = a[4] - b[4];
dest[5] = a[5] - b[5];
dest[6] = a[6] - b[6];
dest[7] = a[7] - b[7];
dest[8] = a[8] - b[8];
dest[9] = a[9] - b[9];
dest[10] = a[10] - b[10];
dest[11] = a[11] - b[11];
dest[12] = a[12] - b[12];
dest[13] = a[13] - b[13];
dest[14] = a[14] - b[14];
dest[15] = a[15] - b[15];
return dest;
},
/**
* @param m mat4
* @param s scalar
* @param dest mat4 - optional destination
* @return {mat4} dest if specified, m otherwise
*
*/
subMat4Scalar: function (m, s, dest) {
if (!dest) {
dest = m;
}
dest[0] = m[0] - s;
dest[1] = m[1] - s;
dest[2] = m[2] - s;
dest[3] = m[3] - s;
dest[4] = m[4] - s;
dest[5] = m[5] - s;
dest[6] = m[6] - s;
dest[7] = m[7] - s;
dest[8] = m[8] - s;
dest[9] = m[9] - s;
dest[10] = m[10] - s;
dest[11] = m[11] - s;
dest[12] = m[12] - s;
dest[13] = m[13] - s;
dest[14] = m[14] - s;
dest[15] = m[15] - s;
return dest;
},
/**
* @param s scalar
* @param m mat4
* @param dest mat4 - optional destination
* @return {mat4} dest if specified, m otherwise
*
*/
subScalarMat4: function (s, m, dest) {
if (!dest) {
dest = m;
}
dest[0] = s - m[0];
dest[1] = s - m[1];
dest[2] = s - m[2];
dest[3] = s - m[3];
dest[4] = s - m[4];
dest[5] = s - m[5];
dest[6] = s - m[6];
dest[7] = s - m[7];
dest[8] = s - m[8];
dest[9] = s - m[9];
dest[10] = s - m[10];
dest[11] = s - m[11];
dest[12] = s - m[12];
dest[13] = s - m[13];
dest[14] = s - m[14];
dest[15] = s - m[15];
return dest;
},
/**
* @param a mat4
* @param b mat4
* @param dest mat4 - optional destination
* @return {mat4} dest if specified, a otherwise
*
*/
mulMat4: function (a, b, dest) {
if (!dest) {
dest = a;
}
// Cache the matrix values (makes for huge speed increases!)
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
var b00 = b[0], b01 = b[1], b02 = b[2], b03 = b[3];
var b10 = b[4], b11 = b[5], b12 = b[6], b13 = b[7];
var b20 = b[8], b21 = b[9], b22 = b[10], b23 = b[11];
var b30 = b[12], b31 = b[13], b32 = b[14], b33 = b[15];
dest[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30;
dest[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31;
dest[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32;
dest[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33;
dest[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30;
dest[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31;
dest[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32;
dest[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33;
dest[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30;
dest[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31;
dest[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32;
dest[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33;
dest[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30;
dest[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31;
dest[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32;
dest[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33;
return dest;
},
/**
* @param m mat4
* @param s scalar
* @param dest mat4 - optional destination
* @return {mat4} dest if specified, m otherwise
*
*/
mulMat4Scalar: function (m, s, dest) {
if (!dest) {
dest = m;
}
dest[0] = m[0] * s;
dest[1] = m[1] * s;
dest[2] = m[2] * s;
dest[3] = m[3] * s;
dest[4] = m[4] * s;
dest[5] = m[5] * s;
dest[6] = m[6] * s;
dest[7] = m[7] * s;
dest[8] = m[8] * s;
dest[9] = m[9] * s;
dest[10] = m[10] * s;
dest[11] = m[11] * s;
dest[12] = m[12] * s;
dest[13] = m[13] * s;
dest[14] = m[14] * s;
dest[15] = m[15] * s;
return dest;
},
/**
* @param m mat4
* @param v vec4
* @return []
*
*/
mulMat4v4: function (m, v) {
var v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
return [
m[0] * v0 + m[4] * v1 + m[8] * v2 + m[12] * v3,
m[1] * v0 + m[5] * v1 + m[9] * v2 + m[13] * v3,
m[2] * v0 + m[6] * v1 + m[10] * v2 + m[14] * v3,
m[3] * v0 + m[7] * v1 + m[11] * v2 + m[15] * v3
];
},
/**
* @param mat mat4
* @param dest mat4 - optional destination
* @return {mat4} dest if specified, mat otherwise
*
*/
transposeMat4: function (mat, dest) {
// If we are transposing ourselves we can skip a few steps but have to cache some values
var m4 = mat[4], m14 = mat[14], m8 = mat[8];
var m13 = mat[13], m12 = mat[12], m9 = mat[9];
if (!dest || mat === dest) {
var a01 = mat[1], a02 = mat[2], a03 = mat[3];
var a12 = mat[6], a13 = mat[7];
var a23 = mat[11];
mat[1] = m4;
mat[2] = m8;
mat[3] = m12;
mat[4] = a01;
mat[6] = m9;
mat[7] = m13;
mat[8] = a02;
mat[9] = a12;
mat[11] = m14;
mat[12] = a03;
mat[13] = a13;
mat[14] = a23;
return mat;
}
dest[0] = mat[0];
dest[1] = m4;
dest[2] = m8;
dest[3] = m12;
dest[4] = mat[1];
dest[5] = mat[5];
dest[6] = m9;
dest[7] = m13;
dest[8] = mat[2];
dest[9] = mat[6];
dest[10] = mat[10];
dest[11] = m14;
dest[12] = mat[3];
dest[13] = mat[7];
dest[14] = mat[11];
dest[15] = mat[15];
return dest;
},
/** */
determinantMat4: function (mat) {
// Cache the matrix values (makes for huge speed increases!)
var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3];
var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7];
var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11];
var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15];
return a30 * a21 * a12 * a03 - a20 * a31 * a12 * a03 - a30 * a11 * a22 * a03 + a10 * a31 * a22 * a03 +
a20 * a11 * a32 * a03 - a10 * a21 * a32 * a03 - a30 * a21 * a02 * a13 + a20 * a31 * a02 * a13 +
a30 * a01 * a22 * a13 - a00 * a31 * a22 * a13 - a20 * a01 * a32 * a13 + a00 * a21 * a32 * a13 +
a30 * a11 * a02 * a23 - a10 * a31 * a02 * a23 - a30 * a01 * a12 * a23 + a00 * a31 * a12 * a23 +
a10 * a01 * a32 * a23 - a00 * a11 * a32 * a23 - a20 * a11 * a02 * a33 + a10 * a21 * a02 * a33 +
a20 * a01 * a12 * a33 - a00 * a21 * a12 * a33 - a10 * a01 * a22 * a33 + a00 * a11 * a22 * a33;
},
/**
* @param mat mat4
* @param dest mat4 - optional destination
* @return {mat4} dest if specified, mat otherwise
*
*/
inverseMat4: function (mat, dest) {
if (!dest) {
dest = mat;
}
// Cache the matrix values (makes for huge speed increases!)
var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3];
var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7];
var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11];
var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15];
var b00 = a00 * a11 - a01 * a10;
var b01 = a00 * a12 - a02 * a10;
var b02 = a00 * a13 - a03 * a10;
var b03 = a01 * a12 - a02 * a11;
var b04 = a01 * a13 - a03 * a11;
var b05 = a02 * a13 - a03 * a12;
var b06 = a20 * a31 - a21 * a30;
var b07 = a20 * a32 - a22 * a30;
var b08 = a20 * a33 - a23 * a30;
var b09 = a21 * a32 - a22 * a31;
var b10 = a21 * a33 - a23 * a31;
var b11 = a22 * a33 - a23 * a32;
// Calculate the determinant (inlined to avoid double-caching)
var invDet = 1 / (b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06);
dest[0] = (a11 * b11 - a12 * b10 + a13 * b09) * invDet;
dest[1] = (-a01 * b11 + a02 * b10 - a03 * b09) * invDet;
dest[2] = (a31 * b05 - a32 * b04 + a33 * b03) * invDet;
dest[3] = (-a21 * b05 + a22 * b04 - a23 * b03) * invDet;
dest[4] = (-a10 * b11 + a12 * b08 - a13 * b07) * invDet;
dest[5] = (a00 * b11 - a02 * b08 + a03 * b07) * invDet;
dest[6] = (-a30 * b05 + a32 * b02 - a33 * b01) * invDet;
dest[7] = (a20 * b05 - a22 * b02 + a23 * b01) * invDet;
dest[8] = (a10 * b10 - a11 * b08 + a13 * b06) * invDet;
dest[9] = (-a00 * b10 + a01 * b08 - a03 * b06) * invDet;
dest[10] = (a30 * b04 - a31 * b02 + a33 * b00) * invDet;
dest[11] = (-a20 * b04 + a21 * b02 - a23 * b00) * invDet;
dest[12] = (-a10 * b09 + a11 * b07 - a12 * b06) * invDet;
dest[13] = (a00 * b09 - a01 * b07 + a02 * b06) * invDet;
dest[14] = (-a30 * b03 + a31 * b01 - a32 * b00) * invDet;
dest[15] = (a20 * b03 - a21 * b01 + a22 * b00) * invDet;
return dest;
},
/** */
traceMat4: function (m) {
return (m[0] + m[5] + m[10] + m[15]);
},
/** */
translationMat4v: function (v) {
var m = BIMSURFER.math.identityMat4();
m[12] = v[0];
m[13] = v[1];
m[14] = v[2];
return m;
},
/** */
translationMat4c: function (x, y, z) {
return BIMSURFER.math.translationMat4v([x, y, z]);
},
/** */
translationMat4s: function (s) {
return BIMSURFER.math.translationMat4c(s, s, s);
},
/** */
rotationMat4v: function (anglerad, axis) {
var ax = BIMSURFER.math.normalizeVec4([axis[0], axis[1], axis[2], 0.0], []);
var s = Math.sin(anglerad);
var c = Math.cos(anglerad);
var q = 1.0 - c;
var x = ax[0];
var y = ax[1];
var z = ax[2];
var xy, yz, zx, xs, ys, zs;
//xx = x * x; used once
//yy = y * y; used once
//zz = z * z; used once
xy = x * y;
yz = y * z;
zx = z * x;
xs = x * s;
ys = y * s;
zs = z * s;
var m = BIMSURFER.math.mat4();
m[0] = (q * x * x) + c;
m[1] = (q * xy) + zs;
m[2] = (q * zx) - ys;
m[3] = 0.0;
m[4] = (q * xy) - zs;
m[5] = (q * y * y) + c;
m[6] = (q * yz) + xs;
m[7] = 0.0;
m[8] = (q * zx) + ys;
m[9] = (q * yz) - xs;
m[10] = (q * z * z) + c;
m[11] = 0.0;
m[12] = 0.0;
m[13] = 0.0;
m[14] = 0.0;
m[15] = 1.0;
return m;
},
/** */
rotationMat4c: function (anglerad, x, y, z) {
return BIMSURFER.math.rotationMat4v(anglerad, [x, y, z]);
},
/** */
scalingMat4v: function (v) {
var m = BIMSURFER.math.identityMat4();
m[0] = v[0];
m[5] = v[1];
m[10] = v[2];
return m;
},
/** */
scalingMat4c: function (x, y, z) {
return BIMSURFER.math.scalingMat4v([x, y, z]);
},
/** */
scalingMat4s: function (s) {
return BIMSURFER.math.scalingMat4c(s, s, s);
},
/**
* @param pos vec3 position of the viewer
* @param target vec3 point the viewer is looking at
* @param up vec3 pointing "up"
* @param dest mat4 Optional, mat4 frustum matrix will be written into
*
* @return {mat4} dest if specified, a new mat4 otherwise
*/
lookAtMat4v: function (pos, target, up, dest) {
if (!dest) {
dest = BIMSURFER.math.mat4();
}
var posx = pos[0],
posy = pos[1],
posz = pos[2],
upx = up[0],
upy = up[1],
upz = up[2],
targetx = target[0],
targety = target[1],
targetz = target[2];
if (posx === targetx && posy === targety && posz === targetz) {
return BIMSURFER.math.identityMat4();
}
var z0, z1, z2, x0, x1, x2, y0, y1, y2, len;
//vec3.direction(eye, center, z);
z0 = posx - targetx;
z1 = posy - targety;
z2 = posz - targetz;
// normalize (no check needed for 0 because of early return)
len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
z0 *= len;
z1 *= len;
z2 *= len;
//vec3.normalize(vec3.cross(up, z, x));
x0 = upy * z2 - upz * z1;
x1 = upz * z0 - upx * z2;
x2 = upx * z1 - upy * z0;
len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
if (!len) {
x0 = 0;
x1 = 0;
x2 = 0;
} else {
len = 1 / len;
x0 *= len;
x1 *= len;
x2 *= len;
}
//vec3.normalize(vec3.cross(z, x, y));
y0 = z1 * x2 - z2 * x1;
y1 = z2 * x0 - z0 * x2;
y2 = z0 * x1 - z1 * x0;
len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
if (!len) {
y0 = 0;
y1 = 0;
y2 = 0;
} else {
len = 1 / len;
y0 *= len;
y1 *= len;
y2 *= len;
}
dest[0] = x0;
dest[1] = y0;
dest[2] = z0;
dest[3] = 0;
dest[4] = x1;
dest[5] = y1;
dest[6] = z1;
dest[7] = 0;
dest[8] = x2;
dest[9] = y2;
dest[10] = z2;
dest[11] = 0;
dest[12] = -(x0 * posx + x1 * posy + x2 * posz);
dest[13] = -(y0 * posx + y1 * posy + y2 * posz);
dest[14] = -(z0 * posx + z1 * posy + z2 * posz);
dest[15] = 1;
return dest;
},
/** */
lookAtMat4c: function (posx, posy, posz, targetx, targety, targetz, upx, upy, upz) {
return BIMSURFER.math.lookAtMat4v([posx, posy, posz], [targetx, targety, targetz], [upx, upy, upz], []);
},
/** */
orthoMat4c: function (left, right, bottom, top, near, far, dest) {
if (!dest) {
dest = BIMSURFER.math.mat4();
}
var rl = (right - left);
var tb = (top - bottom);
var fn = (far - near);
dest[0] = 2.0 / rl;
dest[1] = 0.0;
dest[2] = 0.0;
dest[3] = 0.0;
dest[4] = 0.0;
dest[5] = 2.0 / tb;
dest[6] = 0.0;
dest[7] = 0.0;
dest[8] = 0.0;
dest[9] = 0.0;
dest[10] = -2.0 / fn;
dest[11] = 0.0;
dest[12] = -(left + right) / rl;
dest[13] = -(top + bottom) / tb;
dest[14] = -(far + near) / fn;
dest[15] = 1.0;
return dest;
},
/** */
frustumMat4v: function (fmin, fmax) {
var fmin4 = [fmin[0], fmin[1], fmin[2], 0.0];
var fmax4 = [fmax[0], fmax[1], fmax[2], 0.0];
var vsum = BIMSURFER.math.mat4();
BIMSURFER.math.addVec4(fmax4, fmin4, vsum);
var vdif = BIMSURFER.math.mat4();
BIMSURFER.math.subVec4(fmax4, fmin4, vdif);
var t = 2.0 * fmin4[2];
var m = BIMSURFER.math.mat4();
var vdif0 = vdif[0], vdif1 = vdif[1], vdif2 = vdif[2];
m[0] = t / vdif0;
m[1] = 0.0;
m[2] = 0.0;
m[3] = 0.0;
m[4] = 0.0;
m[5] = t / vdif1;
m[6] = 0.0;
m[7] = 0.0;
m[8] = vsum[0] / vdif0;
m[9] = vsum[1] / vdif1;
m[10] = -vsum[2] / vdif2;
m[11] = -1.0;
m[12] = 0.0;
m[13] = 0.0;
m[14] = -t * fmax4[2] / vdif2;
m[15] = 0.0;
return m;
},
/** */
frustumMatrix4: function (left, right, bottom, top, near, far, dest) {
if (!dest) {
dest = BIMSURFER.math.mat4();
}
var rl = (right - left);
var tb = (top - bottom);
var fn = (far - near);
dest[0] = (near * 2) / rl;
dest[1] = 0;
dest[2] = 0;
dest[3] = 0;
dest[4] = 0;
dest[5] = (near * 2) / tb;
dest[6] = 0;
dest[7] = 0;
dest[8] = (right + left) / rl;
dest[9] = (top + bottom) / tb;
dest[10] = -(far + near) / fn;
dest[11] = -1;
dest[12] = 0;
dest[13] = 0;
dest[14] = -(far * near * 2) / fn;
dest[15] = 0;
return dest;
},
/** */
perspectiveMatrix4: function (fovyrad, aspectratio, znear, zfar) {
var pmin = [];
var pmax = [];
pmin[2] = znear;
pmax[2] = zfar;
pmax[1] = pmin[2] * Math.tan(fovyrad / 2.0);
pmin[1] = -pmax[1];
pmax[0] = pmax[1] * aspectratio;
pmin[0] = -pmax[0];
return BIMSURFER.math.frustumMat4v(pmin, pmax);
},
/** */
transformPoint3: function (m, p, q) {
var p0 = p[0], p1 = p[1], p2 = p[2];
q = q || [0, 0, 0, 0];
q[0] = (m[0] * p0) + (m[4] * p1) + (m[8] * p2) + m[12];
q[1] = (m[1] * p0) + (m[5] * p1) + (m[9] * p2) + m[13];
q[2] = (m[2] * p0) + (m[6] * p1) + (m[10] * p2) + m[14];
q[3] = (m[3] * p0) + (m[7] * p1) + (m[11] * p2) + m[15];
return q;
},
/** */
transformPoints3: function (m, points) {
var result = new Array(points.length);
var len = points.length;
var p0, p1, p2;
var pi;
// cache values
var m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3];
var m4 = m[4], m5 = m[5], m6 = m[6], m7 = m[7];
var m8 = m[8], m9 = m[9], m10 = m[10], m11 = m[11];
var m12 = m[12], m13 = m[13], m14 = m[14], m15 = m[15];
for (var i = 0; i < len; ++i) {
// cache values
pi = points[i];
p0 = pi[0];
p1 = pi[1];
p2 = pi[2];
result[i] = [
(m0 * p0) + (m4 * p1) + (m8 * p2) + m12,
(m1 * p0) + (m5 * p1) + (m9 * p2) + m13,
(m2 * p0) + (m6 * p1) + (m10 * p2) + m14,
(m3 * p0) + (m7 * p1) + (m11 * p2) + m15
];
}
return result;
},
/** */
transformVec3: function (m, v) {
var v0 = v[0], v1 = v[1], v2 = v[2];
return [
(m[0] * v0) + (m[4] * v1) + (m[8] * v2),
(m[1] * v0) + (m[5] * v1) + (m[9] * v2),
(m[2] * v0) + (m[6] * v1) + (m[10] * v2)
];
},
transformVec4: function (m, v) {
var v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
return [
m[ 0] * v0 + m[ 4] * v1 + m[ 8] * v2 + m[12] * v3,
m[ 1] * v0 + m[ 5] * v1 + m[ 9] * v2 + m[13] * v3,
m[ 2] * v0 + m[ 6] * v1 + m[10] * v2 + m[14] * v3,
m[ 3] * v0 + m[ 7] * v1 + m[11] * v2 + m[15] * v3
];
},
/** */
projectVec4: function (v) {
var f = 1.0 / v[3];
return [v[0] * f, v[1] * f, v[2] * f, 1.0];
},
/**
*
*/
vec3ObjToArray: function (v, dest) {
var result = dest || BIMSURFER.math.vec3();
result[0] = v.x;
result[1] = v.y;
result[2] = v.z;
return result;
},
/**
*
*/
vec3ArrayToObj: function (v) {
return { x: v[0], y: v[1], z: v[2] };
},
/**
*
* @param min
* @param max
*/
AxisBox3: function (min, max) {
this.verts = [
[min[0], min[1], min[2]],
[max[0], min[1], min[2]],
[max[0], max[1], min[2]],
[min[0], max[1], min[2]],
[min[0], min[1], max[2]],
[max[0], min[1], max[2]],
[max[0], max[1], max[2]],
[min[0], max[1], max[2]]
];
this.toBox3 = function () {
var box = new Human.math.Box3();
for (var i = 0; i < 8; i++) {
var v = this.verts[i];
for (var j = 0; j < 3; j++) {
if (v[j] < box.min[j]) {
box.min[j] = v[j];
}
if (v[j] > box.max[j]) {
box.max[j] = v[j];
}
}
}
};
this.toBoundary = function () {
var box = new Human.math.Box3();
for (var i = 0; i < 8; i++) {
var v = this.verts[i];
for (var j = 0; j < 3; j++) {
if (v[j] < box.min[j]) {
box.min[j] = v[j];
}
if (v[j] > box.max[j]) {
box.max[j] = v[j];
}
}
}
};
},
lerpVec3: function (t, t1, t2, p1, p2, dest) {
var result = dest || this.vec3();
var f = (t - t1) / (t2 - t1);
result[0] = p1[0] + (f * (p2[0] - p1[0]));
result[1] = p1[1] + (f * (p2[1] - p1[1]));
result[2] = p1[2] + (f * (p2[2] - p1[2]));
return result;
},
getBoundaryDiag: function (boundary) {
var min = this.vec3();
var max = this.vec3();
min[0] = boundary.xmin;
min[1] = boundary.ymin;
min[2] = boundary.zmin;
max[0] = boundary.xmax;
max[1] = boundary.ymax;
max[2] = boundary.zmax;
var tempVec = this.vec3();
this.subVec3(max, min, tempVec);
return Math.abs(this.lenVec3(tempVec));
},
getBoundaryCenter: function (boundary, dest) {
var r = dest || this.vec3();
r[0] = (boundary.xmax + boundary.xmin ) * 0.5;
r[1] = (boundary.ymax + boundary.ymin ) * 0.5;
r[2] = (boundary.zmax + boundary.zmin ) * 0.5;
return r;
}
};
})();