Files
node-metaverse/lib/tsm/mat3.ts

516 lines
14 KiB
TypeScript

/**
* @fileoverview TSM - A TypeScript vector and matrix math library
* @author Matthias Ferch
* @version 0.6
*/
/*
* Copyright (c) 2012 Matthias Ferch
*
* Project homepage: https://github.com/matthiasferch/tsm
*
* 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.
*/
///<reference path='./common.ts' />
import { TSMVec2 } from './vec2';
import { TSMVec3 } from './vec3';
import { TSMMat4 } from './mat4';
import { TSMQuat } from './quat';
export class TSMMat3
{
static identity = new TSMMat3().setIdentity();
private values = new Float32Array(9);
static product(m1: TSMMat3, m2: TSMMat3, result: TSMMat3 | null = null): TSMMat3
{
const a00 = m1.at(0), a01 = m1.at(1), a02 = m1.at(2),
a10 = m1.at(3), a11 = m1.at(4), a12 = m1.at(5),
a20 = m1.at(6), a21 = m1.at(7), a22 = m1.at(8);
const b00 = m2.at(0), b01 = m2.at(1), b02 = m2.at(2),
b10 = m2.at(3), b11 = m2.at(4), b12 = m2.at(5),
b20 = m2.at(6), b21 = m2.at(7), b22 = m2.at(8);
if (result)
{
result.init([
b00 * a00 + b01 * a10 + b02 * a20,
b00 * a01 + b01 * a11 + b02 * a21,
b00 * a02 + b01 * a12 + b02 * a22,
b10 * a00 + b11 * a10 + b12 * a20,
b10 * a01 + b11 * a11 + b12 * a21,
b10 * a02 + b11 * a12 + b12 * a22,
b20 * a00 + b21 * a10 + b22 * a20,
b20 * a01 + b21 * a11 + b22 * a21,
b20 * a02 + b21 * a12 + b22 * a22
]);
return result;
}
else
{
return new TSMMat3([
b00 * a00 + b01 * a10 + b02 * a20,
b00 * a01 + b01 * a11 + b02 * a21,
b00 * a02 + b01 * a12 + b02 * a22,
b10 * a00 + b11 * a10 + b12 * a20,
b10 * a01 + b11 * a11 + b12 * a21,
b10 * a02 + b11 * a12 + b12 * a22,
b20 * a00 + b21 * a10 + b22 * a20,
b20 * a01 + b21 * a11 + b22 * a21,
b20 * a02 + b21 * a12 + b22 * a22
]);
}
}
constructor(values: number[] | null = null)
{
if (values)
{
this.init(values);
}
}
at(index: number): number
{
return this.values[index];
}
init(values: number[]): TSMMat3
{
for (let i = 0; i < 9; i++)
{
this.values[i] = values[i];
}
return this;
}
reset(): void
{
for (let i = 0; i < 9; i++)
{
this.values[i] = 0;
}
}
copy(dest: TSMMat3 | null = null): TSMMat3
{
if (!dest)
{
dest = new TSMMat3();
}
for (let i = 0; i < 9; i++)
{
dest.values[i] = this.values[i];
}
return dest;
}
all(): number[]
{
const data: number[] = [];
for (let i = 0; i < 9; i++)
{
data[i] = this.values[i];
}
return data;
}
row(index: number): number[]
{
return [
this.values[index * 3 + 0],
this.values[index * 3 + 1],
this.values[index * 3 + 2]
];
}
col(index: number): number[]
{
return [
this.values[index],
this.values[index + 3],
this.values[index + 6]
];
}
equals(matrix: TSMMat3, threshold = EPSILON): boolean
{
for (let i = 0; i < 9; i++)
{
if (Math.abs(this.values[i] - matrix.at(i)) > threshold)
{
return false;
}
}
return true;
}
determinant(): number
{
const a00 = this.values[0], a01 = this.values[1], a02 = this.values[2],
a10 = this.values[3], a11 = this.values[4], a12 = this.values[5],
a20 = this.values[6], a21 = this.values[7], a22 = this.values[8];
const det01 = a22 * a11 - a12 * a21,
det11 = -a22 * a10 + a12 * a20,
det21 = a21 * a10 - a11 * a20;
return a00 * det01 + a01 * det11 + a02 * det21;
}
setIdentity(): TSMMat3
{
this.values[0] = 1;
this.values[1] = 0;
this.values[2] = 0;
this.values[3] = 0;
this.values[4] = 1;
this.values[5] = 0;
this.values[6] = 0;
this.values[7] = 0;
this.values[8] = 1;
return this;
}
transpose(): TSMMat3
{
const temp01 = this.values[1],
temp02 = this.values[2],
temp12 = this.values[5];
this.values[1] = this.values[3];
this.values[2] = this.values[6];
this.values[3] = temp01;
this.values[5] = this.values[7];
this.values[6] = temp02;
this.values[7] = temp12;
return this;
}
inverse(): TSMMat3 | null
{
const a00 = this.values[0], a01 = this.values[1], a02 = this.values[2],
a10 = this.values[3], a11 = this.values[4], a12 = this.values[5],
a20 = this.values[6], a21 = this.values[7], a22 = this.values[8];
const det01 = a22 * a11 - a12 * a21,
det11 = -a22 * a10 + a12 * a20,
det21 = a21 * a10 - a11 * a20;
let det = a00 * det01 + a01 * det11 + a02 * det21;
if (!det)
{
return null;
}
det = 1.0 / det;
this.values[0] = det01 * det;
this.values[1] = (-a22 * a01 + a02 * a21) * det;
this.values[2] = (a12 * a01 - a02 * a11) * det;
this.values[3] = det11 * det;
this.values[4] = (a22 * a00 - a02 * a20) * det;
this.values[5] = (-a12 * a00 + a02 * a10) * det;
this.values[6] = det21 * det;
this.values[7] = (-a21 * a00 + a01 * a20) * det;
this.values[8] = (a11 * a00 - a01 * a10) * det;
return this;
}
multiply(matrix: TSMMat3): TSMMat3
{
const a00 = this.values[0], a01 = this.values[1], a02 = this.values[2],
a10 = this.values[3], a11 = this.values[4], a12 = this.values[5],
a20 = this.values[6], a21 = this.values[7], a22 = this.values[8];
const b00 = matrix.at(0), b01 = matrix.at(1), b02 = matrix.at(2),
b10 = matrix.at(3), b11 = matrix.at(4), b12 = matrix.at(5),
b20 = matrix.at(6), b21 = matrix.at(7), b22 = matrix.at(8);
this.values[0] = b00 * a00 + b01 * a10 + b02 * a20;
this.values[1] = b00 * a01 + b01 * a11 + b02 * a21;
this.values[2] = b00 * a02 + b01 * a12 + b02 * a22;
this.values[3] = b10 * a00 + b11 * a10 + b12 * a20;
this.values[4] = b10 * a01 + b11 * a11 + b12 * a21;
this.values[5] = b10 * a02 + b11 * a12 + b12 * a22;
this.values[6] = b20 * a00 + b21 * a10 + b22 * a20;
this.values[7] = b20 * a01 + b21 * a11 + b22 * a21;
this.values[8] = b20 * a02 + b21 * a12 + b22 * a22;
return this;
}
multiplyTSMVec2(vector: TSMVec2, result: TSMVec2 | null = null): TSMVec2
{
const x = vector.x,
y = vector.y;
if (result)
{
result.xy = [
x * this.values[0] + y * this.values[3] + this.values[6],
x * this.values[1] + y * this.values[4] + this.values[7]
];
return result;
}
else
{
return new TSMVec2([
x * this.values[0] + y * this.values[3] + this.values[6],
x * this.values[1] + y * this.values[4] + this.values[7]
]);
}
}
multiplyTSMVec3(vector: TSMVec3, result: TSMVec3 | null = null): TSMVec3
{
const x = vector.x,
y = vector.y,
z = vector.z;
if (result)
{
result.xyz = [
x * this.values[0] + y * this.values[3] + z * this.values[6],
x * this.values[1] + y * this.values[4] + z * this.values[7],
x * this.values[2] + y * this.values[5] + z * this.values[8]
];
return result;
}
else
{
return new TSMVec3([
x * this.values[0] + y * this.values[3] + z * this.values[6],
x * this.values[1] + y * this.values[4] + z * this.values[7],
x * this.values[2] + y * this.values[5] + z * this.values[8]
]);
}
}
toTSMMat4(result: TSMMat4 | null = null): TSMMat4
{
if (result)
{
result.init([
this.values[0],
this.values[1],
this.values[2],
0,
this.values[3],
this.values[4],
this.values[5],
0,
this.values[6],
this.values[7],
this.values[8],
0,
0,
0,
0,
1
]);
return result;
}
else
{
return new TSMMat4([
this.values[0],
this.values[1],
this.values[2],
0,
this.values[3],
this.values[4],
this.values[5],
0,
this.values[6],
this.values[7],
this.values[8],
0,
0,
0,
0,
1
]);
}
}
toQuat(): TSMQuat
{
const m00 = this.values[0], m01 = this.values[1], m02 = this.values[2],
m10 = this.values[3], m11 = this.values[4], m12 = this.values[5],
m20 = this.values[6], m21 = this.values[7], m22 = this.values[8];
const fourXSquaredMinus1 = m00 - m11 - m22;
const fourYSquaredMinus1 = m11 - m00 - m22;
const fourZSquaredMinus1 = m22 - m00 - m11;
const fourWSquaredMinus1 = m00 + m11 + m22;
let biggestIndex = 0;
let fourBiggestSquaredMinus1 = fourWSquaredMinus1;
if (fourXSquaredMinus1 > fourBiggestSquaredMinus1)
{
fourBiggestSquaredMinus1 = fourXSquaredMinus1;
biggestIndex = 1;
}
if (fourYSquaredMinus1 > fourBiggestSquaredMinus1)
{
fourBiggestSquaredMinus1 = fourYSquaredMinus1;
biggestIndex = 2;
}
if (fourZSquaredMinus1 > fourBiggestSquaredMinus1)
{
fourBiggestSquaredMinus1 = fourZSquaredMinus1;
biggestIndex = 3;
}
const biggestVal = Math.sqrt(fourBiggestSquaredMinus1 + 1) * 0.5;
const mult = 0.25 / biggestVal;
const result = new TSMQuat();
switch (biggestIndex)
{
case 0:
result.w = biggestVal;
result.x = (m12 - m21) * mult;
result.y = (m20 - m02) * mult;
result.z = (m01 - m10) * mult;
break;
case 1:
result.w = (m12 - m21) * mult;
result.x = biggestVal;
result.y = (m01 + m10) * mult;
result.z = (m20 + m02) * mult;
break;
case 2:
result.w = (m20 - m02) * mult;
result.x = (m01 + m10) * mult;
result.y = biggestVal;
result.z = (m12 + m21) * mult;
break;
case 3:
result.w = (m01 - m10) * mult;
result.x = (m20 + m02) * mult;
result.y = (m12 + m21) * mult;
result.z = biggestVal;
break;
}
return result;
}
rotate(angle: number, axis: TSMVec3): TSMMat3 | null
{
let x = axis.x,
y = axis.y,
z = axis.z;
let length = Math.sqrt(x * x + y * y + z * z);
if (!length)
{
return null;
}
if (length !== 1)
{
length = 1 / length;
x *= length;
y *= length;
z *= length;
}
const s = Math.sin(angle);
const c = Math.cos(angle);
const t = 1.0 - c;
const a00 = this.values[0], a01 = this.values[1], a02 = this.values[2],
a10 = this.values[4], a11 = this.values[5], a12 = this.values[6],
a20 = this.values[8], a21 = this.values[9], a22 = this.values[10];
const b00 = x * x * t + c, b01 = y * x * t + z * s, b02 = z * x * t - y * s,
b10 = x * y * t - z * s, b11 = y * y * t + c, b12 = z * y * t + x * s,
b20 = x * z * t + y * s, b21 = y * z * t - x * s, b22 = z * z * t + c;
this.values[0] = a00 * b00 + a10 * b01 + a20 * b02;
this.values[1] = a01 * b00 + a11 * b01 + a21 * b02;
this.values[2] = a02 * b00 + a12 * b01 + a22 * b02;
this.values[3] = a00 * b10 + a10 * b11 + a20 * b12;
this.values[4] = a01 * b10 + a11 * b11 + a21 * b12;
this.values[5] = a02 * b10 + a12 * b11 + a22 * b12;
this.values[6] = a00 * b20 + a10 * b21 + a20 * b22;
this.values[7] = a01 * b20 + a11 * b21 + a21 * b22;
this.values[8] = a02 * b20 + a12 * b21 + a22 * b22;
return this;
}
}