const DIM_NAMES = ["xr", "yg", "zb", "wa"]; const ARRAY_TYPES = [ Int8Array, Int16Array, Int32Array, Uint8Array, Uint16Array, Uint32Array, Float32Array, Float64Array, BigInt64Array, BigUint64Array // Note: These requires values to be of type BigInt ]; export class Vector { constructor(...values) { this.type = Float32Array; for (const value of values) { if (ARRAY_TYPES.includes(value)) { this.type = value; break; } } this.values = new this.type(values.filter(v => !ARRAY_TYPES.includes(v))); const defineMacro = (index, key) => { Object.defineProperty(this, key, { get() { return this.values[index] }, set(value) { this.values[index] = value } }); }; for (const i in this.values) { defineMacro(i, i); if (i >= DIM_NAMES.length) continue; for (const names of DIM_NAMES[i]) { for (const char of names) { defineMacro(i, char); } } } } clone() { return new Vector(this.type, ...this.values); } static _requireSameVector(vecA, vecB) { if (!(vecA instanceof Vector)) throw new TypeError("vecA has to be instance of `Vector`"); if (!(vecB instanceof Vector)) throw new TypeError("vecB has to be instance of `Vector`"); if (vecA.values.length !== vecB.values.length) throw new TypeError("Vectors are of different lengths"); if (vecA.type !== vecB.type) console.warn("Vectors are not of same array type.. be careful!"); } _modifyComponents(vec, func) { if (vec instanceof Vector) { Vector._requireSameVector(this, vec); for (const i in vec.values) { this[i] = func(this[i], vec[i]); } return this; } for (const i in this.values) { this[i] = func(this[i], vec); // vec is number here } return this; } // Basic operations add = (vec) => this._modifyComponents(vec, (a, b) => a + b); subtract = (vec) => this._modifyComponents(vec, (a, b) => a - b); multiply = (vec) => this._modifyComponents(vec, (a, b) => a * b); divide = (vec) => this._modifyComponents(vec, (a, b) => a / b); // Basic algebra length() { return Math.sqrt( this.values.map(v => v * v).reduce((a, b) => a + b, 0) ); } static normalize(vec) { return vec.clone().divide(vec.length()); } static distance(vecA, vecB) { Vector._requireSameVector(vecA, vecB); return Math.sqrt( vecA.values.map((v, i) => v - vecB[i]).map(v => v * v).reduce((a, b) => a + b, 0) ); } static dot(vecA, vecB) { Vector._requireSameVector(vecA, vecB); return vecA.values.map((v, i) => v * vecB[i]).reduce((a, b) => a + b, 0); } static cross(vecA, vecB) { Vector._requireSameVector(vecA, vecB); if (vecA.values.length !== 3) throw TypeError(`Vector3 required, got Vector${vecA.values.length}`); return new Vector(vecA.type, vecA.y * vecB.z - vecA.z * vecB.y, vecA.z * vecB.x - vecA.x * vecB.z, vecA.x * vecB.y - vecA.y * vecB.x ); } }