@threeify/math
Version:
Computer graphics oriented, High performance, tree-shakeable, TypeScript 3D vector math library.
164 lines (135 loc) • 3.59 kB
text/typescript
import { Euler3, EulerOrder3 } from './Euler3.js';
import { clamp, delta, parseSafeFloats, toSafeString } from './Functions.js';
import { mat4ToMat3, quatToMat3 } from './Mat3.Functions.js';
import { Mat3 } from './Mat3.js';
import { Mat4 } from './Mat4.js';
import { Quat } from './Quat.js';
export function euler3Delta(a: Euler3, b: Euler3): number {
return delta(a.x, b.x) + delta(a.y, b.y) + delta(a.z, b.z);
}
export function mat4ToEuler3(
m: Mat4,
order: EulerOrder3 = EulerOrder3.XYZ,
result = new Euler3()
): Euler3 {
return mat3ToEuler3(mat4ToMat3(m), order, result);
}
export function mat3ToEuler3(
m: Mat3,
order: EulerOrder3 = EulerOrder3.XYZ,
result = new Euler3()
): Euler3 {
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
const te = m.elements;
const m11 = te[0];
const m12 = te[3];
const m13 = te[6];
const m21 = te[1];
const m22 = te[4];
const m23 = te[7];
const m31 = te[2];
const m32 = te[5];
const m33 = te[8];
let x = 0;
let y = 0;
let z = 0;
switch (order) {
case EulerOrder3.XYZ:
y = Math.asin(clamp(m13, -1, 1));
if (Math.abs(m13) < 0.9999999) {
x = Math.atan2(-m23, m33);
z = Math.atan2(-m12, m11);
} else {
x = Math.atan2(m32, m22);
z = 0;
}
break;
case EulerOrder3.YXZ:
x = Math.asin(-clamp(m23, -1, 1));
if (Math.abs(m23) < 0.9999999) {
y = Math.atan2(m13, m33);
z = Math.atan2(m21, m22);
} else {
y = Math.atan2(-m31, m11);
z = 0;
}
break;
case EulerOrder3.ZXY:
x = Math.asin(clamp(m32, -1, 1));
if (Math.abs(m32) < 0.9999999) {
y = Math.atan2(-m31, m33);
z = Math.atan2(-m12, m22);
} else {
y = 0;
z = Math.atan2(m21, m11);
}
break;
case EulerOrder3.ZYX:
y = Math.asin(-clamp(m31, -1, 1));
if (Math.abs(m31) < 0.9999999) {
x = Math.atan2(m32, m33);
z = Math.atan2(m21, m11);
} else {
x = 0;
z = Math.atan2(-m12, m22);
}
break;
case EulerOrder3.YZX:
z = Math.asin(clamp(m21, -1, 1));
if (Math.abs(m21) < 0.9999999) {
x = Math.atan2(-m23, m22);
y = Math.atan2(-m31, m11);
} else {
x = 0;
y = Math.atan2(m13, m33);
}
break;
case EulerOrder3.XZY:
z = Math.asin(-clamp(m12, -1, 1));
if (Math.abs(m12) < 0.9999999) {
x = Math.atan2(m32, m22);
y = Math.atan2(m13, m11);
} else {
x = Math.atan2(-m23, m33);
y = 0;
}
break;
}
return result.set(x, y, z, order);
}
export function quatToEuler3(
q: Quat,
order: EulerOrder3 = EulerOrder3.XYZ,
result = new Euler3()
): Euler3 {
const m = quatToMat3(q);
return mat3ToEuler3(m, order, result);
}
export function arrayToEuler3(
array: Float32Array | number[],
offset = 0,
result = new Euler3()
): Euler3 {
return result.set(
array[offset + 0],
array[offset + 1],
array[offset + 2],
array[offset + 3] as EulerOrder3
);
}
export function euler33ToArray(
a: Euler3,
array: Float32Array | number[],
offset = 0
): void {
array[offset + 0] = a.x;
array[offset + 1] = a.y;
array[offset + 2] = a.z;
array[offset + 2] = a.order as number;
}
export function euler3ToString(e: Euler3): string {
return toSafeString([e.x, e.y, e.z, e.order]);
}
export function stringToEuler3(text: string, result = new Euler3()): Euler3 {
return arrayToEuler3(parseSafeFloats(text), 0, result);
}