UNPKG

@js-basics/vector

Version:

A 3D Vector lib including arithmetic operator overloading (+ - * / % **).

326 lines (310 loc) 7.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ZERO = exports.Victor = exports.Vector = exports.UP = exports.RIGHT = exports.ONE = exports.LEFT = exports.FORWARD = exports.BOTTOM = exports.BACK = void 0; exports.calc = calc; exports.victor = exports.vector = void 0; var _math = require("./utils/math.cjs"); var _operator = require("./operator.cjs"); var _point = require("./point.cjs"); var _css = require("./utils/css.cjs"); const X = 0; const Y = 1; const Z = 2; const AXES = Symbol('axes'); function square(val) { return val * val; } class AVector { constructor(...args) { if (typeof args[0] === 'function') { (0, _operator.operatorCalc)(args[0], (nx, ny, nz) => { this[AXES] = [nx, ny, nz]; }); } else if ((0, _math.isArray)(args[0])) { this[AXES] = [...args[0]]; } else if (args[0] && (0, _math.isNumber)(args[0].x)) { this[AXES] = [args[0].x || 0, args[0].y || 0, args[0].z || 0]; } else { this[AXES] = [args[0] || 0, args[1] || 0, args[2] || 0]; } } valueOf() { throw new Error('valueOf() not implemented, looks like you try to calculate outside of calc'); } /** * @returns {this} */ normalize() { const { length } = this; return new this.constructor(this.x / length, this.y / length, this.z / length); } /** * @returns {this} */ norm() { return this.normalize(); } // methods ispired by // https://evanw.github.io/lightgl.js/docs/vector.html dot(v) { return this.x * v.x + this.y * v.y + this.z * v.z; } /** * @param {AVector} v * @returns {this} */ cross(v) { return new this.constructor(this.y * v.z - this.z * v.y, this.z * v.x - this.x * v.z, this.x * v.y - this.y * v.x); } /** * @param {AVector} v * @returns {this} */ crossNormalize(v) { const vec = this.cross(v); const { length } = vec; vec[AXES][X] /= length; vec[AXES][Y] /= length; vec[AXES][Z] /= length; return vec; } /** * @param {AVector} v * @returns {this} */ cn(v) { return this.crossNormalize(v); } toAngles() { return { theta: Math.atan2(this.z, this.x), phi: Math.asin(this.y / this.length) }; } /** * @param {AVector} v */ angleTo(v) { return (0, _math.normRad)((0, _math.acos)(this.dot(v) / (this.length * v.length))); } multiply(quat) { if (quat.x === undefined) { return this.multiplyMat3(quat); } if (quat.w === undefined) { return this.multiplyVec3(quat); } return (0, _math.multQuatVec)(quat, this); } multiplyMat3(other) { return (0, _math.multiplyVecMat3)(this, other); } multiplyVec3({ x, y, z }) { return new this.constructor(this.x * x, this.y * y, this.z * z); } /** * @param {AVector} v */ distance(v) { return Math.sqrt(square(this.x - v.x) + square(this.y - v.y) + square(this.z - v.z)); } /** * @param {AVector} v */ dist(v) { return this.distance(v); } /** * @returns {[number, number, number]} */ toArray() { return [this.x, this.y, this.z]; } swizzle(target) { const data = target.split('').map(t => this[t]); if (data.length === 2) { return new _point.IPoint(data[0], data[1]); } return new this.constructor(data[0], data[1], data[2]); } // eslint-disable-next-line no-unused-vars calc(arg) { throw new Error('calc() not implemented'); } clone() { throw new Error('clone() not implemented'); } equals(v) { return this.x === v.x && this.y === v.y && this.z === v.z; } toJSON() { return { x: this.x, y: this.y, z: this.z }; } toString() { return JSON.stringify(this.toJSON()); } toCSSVars(name, target = {}) { return (0, _css.convertToCSSVars)(name, this.toJSON(), target); } get lengthSq() { return this.dot(this); } set lengthSq(_) { throw new Error('set lengthSq() not implemented'); } get length() { return Math.sqrt(this.lengthSq); } set length(_) { throw new Error('set length() not implemented'); } get lensq() { return this.lengthSq; } set lensq(_) { throw new Error('set lensq() not implemented'); } get len() { return this.length; } set len(_) { throw new Error('set len() not implemented'); } get x() { return this[AXES][X]; } set x(_) { throw new Error('set x() not implemented'); } get y() { return this[AXES][Y]; } set y(_) { throw new Error('set y() not implemented'); } get z() { return this[AXES][Z]; } set z(_) { throw new Error('set z() not implemented'); } get xy() { return new _point.IPoint(this[AXES][X], this[AXES][Y]); } set xy(_) { throw new Error('set xz() not implemented'); } get xz() { return new _point.IPoint(this[AXES][X], this[AXES][Z]); } set xz(_) { throw new Error('set xz() not implemented'); } get yz() { return new _point.IPoint(this[AXES][Y], this[AXES][Z]); } set yz(_) { throw new Error('set yz() not implemented'); } [Symbol.iterator]() { return this[AXES].values(); } } (0, _operator.cachedValueOf)(AVector); (0, _operator.defineVectorLength)(AVector, 3); (0, _operator.cachedMethod)(AVector, 'dot'); (0, _operator.cachedMethod)(AVector, 'cross'); (0, _operator.cachedMethod)(AVector, 'crossNormalize'); (0, _operator.cachedMethod)(AVector, 'toAngles'); (0, _operator.cachedMethod)(AVector, 'angleTo'); (0, _operator.cachedMethod)(AVector, 'rotate'); (0, _operator.cachedMethod)(AVector, 'distance'); (0, _operator.cachedMethod)(AVector, 'toArray'); (0, _operator.cachedGetter)(AVector, 'length'); (0, _operator.cachedGetter)(AVector, 'lengthSq'); class Vector extends AVector { set x(x) { this[AXES][X] = x; } set y(y) { this[AXES][Y] = y; } set z(z) { this[AXES][Z] = z; } get x() { return this[AXES][X]; } get y() { return this[AXES][Y]; } get z() { return this[AXES][Z]; } /** * @param {() => number} alg * @returns {Vector & number} */ calc(alg) { return (0, _operator.operatorCalc)(alg, this); } clone() { return new Vector(this.x, this.y, this.z); } } exports.Vector = Vector; class Victor extends AVector { /** * @returns {Vector & number} */ toVector() { return new Vector(this.x, this.y, this.z); } clone() { return this; } } exports.Victor = Victor; function calc(alg) { return (0, _operator.operatorCalc)(alg); } const vectorFactory = (0, _operator.cachedFunction)((x, y, z) => new Vector(x, y, z)); /** * @param {number | () => number} x * @param {number} [y] * @param {number} [z] * @returns {Vector & number} */ const vector = (x, y, z) => vectorFactory(x, y, z); exports.vector = vector; const victorFactory = (0, _operator.cachedFunction)((x, y, z) => new Victor(x, y, z)); /** * @param {number | () => number} x * @param {number} [y] * @param {number} [z] * @returns {Victor & number} */ const victor = (x, y, z) => victorFactory(x, y, z); exports.victor = victor; const ZERO = exports.ZERO = victor(0, 0, 0); const FORWARD = exports.FORWARD = victor(0, 0, -1); const BACK = exports.BACK = victor(0, 0, 1); const LEFT = exports.LEFT = victor(-1, 0, 0); const RIGHT = exports.RIGHT = victor(1, 0, 0); const UP = exports.UP = victor(0, 1, 0); const BOTTOM = exports.BOTTOM = victor(0, -1, 0); const ONE = exports.ONE = victor(1, 1, 1);