40 lines
1.1 KiB
TypeScript
40 lines
1.1 KiB
TypeScript
export type Vec3 = { x: number; y: number; z: number }
|
|
|
|
/** Plain 3D vector math. Every operation returns a fresh object (no in-place
|
|
* mutation) to keep call sites easy to reason about. */
|
|
export namespace Vec3 {
|
|
export function add(a: Vec3, b: Vec3): Vec3 {
|
|
return { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z }
|
|
}
|
|
|
|
export function sub(a: Vec3, b: Vec3): Vec3 {
|
|
return { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z }
|
|
}
|
|
|
|
export function scale(v: Vec3, s: number): Vec3 {
|
|
return { x: v.x * s, y: v.y * s, z: v.z * s }
|
|
}
|
|
|
|
export function dot(a: Vec3, b: Vec3): number {
|
|
return a.x * b.x + a.y * b.y + a.z * b.z
|
|
}
|
|
|
|
export function cross(a: Vec3, b: Vec3): Vec3 {
|
|
return {
|
|
x: a.y * b.z - a.z * b.y,
|
|
y: a.z * b.x - a.x * b.z,
|
|
z: a.x * b.y - a.y * b.x,
|
|
}
|
|
}
|
|
|
|
export function length(v: Vec3): number {
|
|
return Math.sqrt(dot(v, v))
|
|
}
|
|
|
|
export function normalize(v: Vec3): Vec3 {
|
|
const len = length(v)
|
|
// Fresh zero (not the input alias) to keep the namespace-wide no-aliasing
|
|
// guarantee even on the degenerate case.
|
|
return len === 0 ? { x: 0, y: 0, z: 0 } : scale(v, 1 / len)
|
|
}
|
|
}
|