Files
node-metaverse/lib/classes/Matrix3.ts
2025-01-17 23:53:31 +00:00

464 lines
12 KiB
TypeScript

import { Vector2 } from './Vector2';
import { Vector3 } from './Vector3';
import { Matrix4 } from './Matrix4';
import { Quaternion } from './Quaternion';
export class Matrix3
{
public static readonly identity: Matrix3 = new Matrix3().setIdentity();
private static readonly EPSILON: number = 1e-6;
private values: Float32Array = new Float32Array(9);
public constructor(values?: number[])
{
if (values)
{
this.init(values);
}
}
public at(index: number): number
{
return this.values[index];
}
public init(values: number[]): this
{
if (values.length !== 9)
{
throw new Error("Matrix3 requires exactly 9 values.");
}
let i = 0;
for (const value of values)
{
this.values[i] = value;
i++;
}
return this;
}
public reset(): void
{
let i = 0;
for (const _ of this.values)
{
this.values[i] = 0;
i++;
}
}
public copy(dest?: Matrix3): Matrix3
{
if (!dest)
{
dest = new Matrix3();
}
let i = 0;
for (const value of this.values)
{
dest.values[i] = value;
i++;
}
return dest;
}
public all(): number[]
{
const data: number[] = [];
for (const value of this.values)
{
data.push(value);
}
return data;
}
public row(index: number): number[]
{
return [
this.values[index * 3],
this.values[index * 3 + 1],
this.values[index * 3 + 2]
];
}
public col(index: number): number[]
{
return [
this.values[index],
this.values[index + 3],
this.values[index + 6]
];
}
public equals(matrix: Matrix3, threshold: number = Matrix3.EPSILON): boolean
{
let i = 0;
for (const value of this.values)
{
if (Math.abs(value - matrix.at(i)) > threshold)
{
return false;
}
i++;
}
return true;
}
public determinant(): number
{
const a00: number = this.values[0];
const a01: number = this.values[1];
const a02: number = this.values[2];
const a10: number = this.values[3];
const a11: number = this.values[4];
const a12: number = this.values[5];
const a20: number = this.values[6];
const a21: number = this.values[7];
const a22: number = this.values[8];
const det01: number = a22 * a11 - a12 * a21;
const det11: number = -a22 * a10 + a12 * a20;
const det21: number = a21 * a10 - a11 * a20;
return a00 * det01 + a01 * det11 + a02 * det21;
}
public setIdentity(): this
{
this.reset();
this.values[0] = 1;
this.values[4] = 1;
this.values[8] = 1;
return this;
}
public transpose(): Matrix3
{
const transposedValues: number[] = [
this.values[0],
this.values[3],
this.values[6],
this.values[1],
this.values[4],
this.values[7],
this.values[2],
this.values[5],
this.values[8]
];
return new Matrix3(transposedValues);
}
public inverse(): Matrix3 | null
{
const a00: number = this.values[0];
const a01: number = this.values[1];
const a02: number = this.values[2];
const a10: number = this.values[3];
const a11: number = this.values[4];
const a12: number = this.values[5];
const a20: number = this.values[6];
const a21: number = this.values[7];
const a22: number = this.values[8];
const det01: number = a22 * a11 - a12 * a21;
const det11: number = -a22 * a10 + a12 * a20;
const det21: number = a21 * a10 - a11 * a20;
let det: number = a00 * det01 + a01 * det11 + a02 * det21;
if (Math.abs(det) < Matrix3.EPSILON)
{
return null;
}
det = 1.0 / det;
const invValues: number[] = [
det01 * det,
(-a22 * a01 + a02 * a21) * det,
(a12 * a01 - a02 * a11) * det,
det11 * det,
(a22 * a00 - a02 * a20) * det,
(-a12 * a00 + a02 * a10) * det,
det21 * det,
(-a21 * a00 + a01 * a20) * det,
(a11 * a00 - a01 * a10) * det
];
return new Matrix3(invValues);
}
public multiply(matrix: Matrix3): Matrix3
{
const a00: number = this.values[0];
const a01: number = this.values[1];
const a02: number = this.values[2];
const a10: number = this.values[3];
const a11: number = this.values[4];
const a12: number = this.values[5];
const a20: number = this.values[6];
const a21: number = this.values[7];
const a22: number = this.values[8];
const b00: number = matrix.at(0);
const b01: number = matrix.at(1);
const b02: number = matrix.at(2);
const b10: number = matrix.at(3);
const b11: number = matrix.at(4);
const b12: number = matrix.at(5);
const b20: number = matrix.at(6);
const b21: number = matrix.at(7);
const b22: number = matrix.at(8);
const resultValues: number[] = [
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 new Matrix3(resultValues);
}
public multiplyVector2(vector: Vector2, result?: Vector2): Vector2
{
const x: number = vector.x;
const y: number = vector.y;
if (result)
{
result.x = x * this.values[0] + y * this.values[3] + this.values[6];
result.y = x * this.values[1] + y * this.values[4] + this.values[7];
return result;
}
else
{
return new Vector2([
x * this.values[0] + y * this.values[3] + this.values[6],
x * this.values[1] + y * this.values[4] + this.values[7]
]);
}
}
public multiplyVector3(vector: Vector3, result?: Vector3): Vector3
{
const x: number = vector.x;
const y: number = vector.y;
const z: number = vector.z;
if (result)
{
result.x = x * this.values[0] + y * this.values[3] + z * this.values[6];
result.y = x * this.values[1] + y * this.values[4] + z * this.values[7];
result.z = x * this.values[2] + y * this.values[5] + z * this.values[8];
return result;
}
else
{
return new Vector3([
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]
]);
}
}
public toMatrix4(result?: Matrix4): Matrix4
{
const mat4Values: number[] = [
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
];
if (result)
{
result.init(mat4Values);
return result;
}
else
{
return new Matrix4(mat4Values);
}
}
public toQuaternion(): Quaternion
{
const m00: number = this.values[0];
const m01: number = this.values[1];
const m02: number = this.values[2];
const m10: number = this.values[3];
const m11: number = this.values[4];
const m12: number = this.values[5];
const m20: number = this.values[6];
const m21: number = this.values[7];
const m22: number = this.values[8];
const fourXSquaredMinus1: number = m00 - m11 - m22;
const fourYSquaredMinus1: number = m11 - m00 - m22;
const fourZSquaredMinus1: number = m22 - m00 - m11;
const fourWSquaredMinus1: number = m00 + m11 + m22;
let biggestIndex = 0;
let fourBiggestSquaredMinus1: number = fourWSquaredMinus1;
if (fourXSquaredMinus1 > fourBiggestSquaredMinus1)
{
fourBiggestSquaredMinus1 = fourXSquaredMinus1;
biggestIndex = 1;
}
if (fourYSquaredMinus1 > fourBiggestSquaredMinus1)
{
fourBiggestSquaredMinus1 = fourYSquaredMinus1;
biggestIndex = 2;
}
if (fourZSquaredMinus1 > fourBiggestSquaredMinus1)
{
fourBiggestSquaredMinus1 = fourZSquaredMinus1;
biggestIndex = 3;
}
const biggestVal: number = Math.sqrt(fourBiggestSquaredMinus1 + 1) * 0.5;
const mult: number = 0.25 / biggestVal;
const quat: Quaternion = new Quaternion();
switch (biggestIndex)
{
case 0:
quat.w = biggestVal;
quat.x = (m12 - m21) * mult;
quat.y = (m20 - m02) * mult;
quat.z = (m01 - m10) * mult;
break;
case 1:
quat.w = (m12 - m21) * mult;
quat.x = biggestVal;
quat.y = (m01 + m10) * mult;
quat.z = (m20 + m02) * mult;
break;
case 2:
quat.w = (m20 - m02) * mult;
quat.x = (m01 + m10) * mult;
quat.y = biggestVal;
quat.z = (m12 + m21) * mult;
break;
case 3:
quat.w = (m01 - m10) * mult;
quat.x = (m20 + m02) * mult;
quat.y = (m12 + m21) * mult;
quat.z = biggestVal;
break;
}
return quat;
}
public rotate(angle: number, axis: Vector3): Matrix3 | null
{
let x: number = axis.x;
let y: number = axis.y;
let z: number = axis.z;
let length: number = Math.sqrt(x * x + y * y + z * z);
if (length < Matrix3.EPSILON)
{
return null;
}
if (length !== 1)
{
length = 1 / length;
x *= length;
y *= length;
z *= length;
}
const s: number = Math.sin(angle);
const c: number = Math.cos(angle);
const t: number = 1.0 - c;
const b00: number = x * x * t + c;
const b01: number = y * x * t + z * s;
const b02: number = z * x * t - y * s;
const b10: number = x * y * t - z * s;
const b11: number = y * y * t + c;
const b12: number = z * y * t + x * s;
const b20: number = x * z * t + y * s;
const b21: number = y * z * t - x * s;
const b22: number = z * z * t + c;
const a00: number = this.values[0];
const a01: number = this.values[1];
const a02: number = this.values[2];
const a10: number = this.values[3];
const a11: number = this.values[4];
const a12: number = this.values[5];
const a20: number = this.values[6];
const a21: number = this.values[7];
const a22: number = this.values[8];
const resultValues: number[] = [
a00 * b00 + a10 * b01 + a20 * b02,
a01 * b00 + a11 * b01 + a21 * b02,
a02 * b00 + a12 * b01 + a22 * b02,
a00 * b10 + a10 * b11 + a20 * b12,
a01 * b10 + a11 * b11 + a21 * b12,
a02 * b10 + a12 * b11 + a22 * b12,
a00 * b20 + a10 * b21 + a20 * b22,
a01 * b20 + a11 * b21 + a21 * b22,
a02 * b20 + a12 * b21 + a22 * b22
];
return new Matrix3(resultValues);
}
}