@js-basics/vector
Version:
A 3D Vector lib including arithmetic operator overloading (+ - * / % **).
226 lines (213 loc) • 4.98 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ZERO = exports.Point = exports.LEFT = exports.IPoint = exports.FORWARD = void 0;
exports.calc = calc;
exports.point = exports.ipoint = void 0;
var _math = require("./utils/math.cjs");
var _operator = require("./operator.cjs");
var _css = require("./utils/css.cjs");
const X = 0;
const Y = 1;
const AXES = Symbol('axes');
function angleOverGround(y1, x1, y2, x2) {
const atanOne = Math.atan2(y1, x1);
const atanTwo = Math.atan2(y2, x2);
return (0, _math.normRad)(atanOne - atanTwo);
}
function square(val) {
return val * val;
}
class APoint {
constructor(...args) {
if (typeof args[0] === 'function') {
(0, _operator.operatorCalc)(args[0], (nx, ny) => {
this[AXES] = [nx, ny];
});
} 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];
} else {
this[AXES] = [args[0] || 0, args[1] || 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);
}
/**
* @returns {this}
*/
norm() {
return this.normalize();
}
// methods ispired by
// https://evanw.github.io/lightgl.js/docs/point.html
dot(v) {
return this.x * v.x + this.y * v.y;
}
getRad() {
return (0, _math.normRad)(Math.atan2(this.y, this.x));
}
/**
* @param {APoint} v
*/
angleTo(v) {
return angleOverGround(this.y, this.x, v.y, v.x);
}
/**
* @param {number} angle
* @returns {this}
*/
rotate(angle) {
const sa = Math.sin(angle);
const ca = Math.cos(angle);
const x = this.x * ca - this.y * sa;
const y = this.x * sa + this.y * ca;
return new this.constructor(x, y);
}
/**
* @param {APoint} v
*/
distance(v) {
return Math.sqrt(square(this.x - v.x) + square(this.y - v.y));
}
/**
* @param {APoint} v
*/
dist(v) {
return this.distance(v);
}
/**
* @returns {[number, number]}
*/
toArray() {
return [this.x, this.y];
}
// eslint-disable-next-line no-unused-vars
calc(alg) {
throw new Error('calc() not implemented');
}
clone() {
throw new Error('clone() not implemented');
}
equals(v) {
return this.x === v.x && this.y === v.y;
}
toJSON() {
return {
x: this.x,
y: this.y
};
}
toString() {
return JSON.stringify(this.toJSON());
}
toCSSVars(name, target) {
return (0, _css.convertToCSSVars)(name, this.toJSON(), target);
}
get lengthSq() {
return this.dot(this);
}
get length() {
return Math.sqrt(this.lengthSq);
}
get lensq() {
return this.lengthSq;
}
get len() {
return this.length;
}
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() {
throw new Error('get z() not implemented');
}
set z(_) {
throw new Error('set z() not implemented');
}
[Symbol.iterator]() {
return this[AXES].values();
}
}
(0, _operator.cachedValueOf)(APoint);
(0, _operator.defineVectorLength)(APoint, 2);
(0, _operator.cachedMethod)(APoint, 'dot');
(0, _operator.cachedMethod)(APoint, 'angleTo');
(0, _operator.cachedMethod)(APoint, 'distance');
(0, _operator.cachedMethod)(APoint, 'toArray');
(0, _operator.cachedMethod)(APoint, 'getRad');
(0, _operator.cachedGetter)(APoint, 'length');
(0, _operator.cachedGetter)(APoint, 'lengthSq');
class Point extends APoint {
set x(x) {
this[AXES][X] = x;
}
set y(y) {
this[AXES][Y] = y;
}
get x() {
return this[AXES][X];
}
get y() {
return this[AXES][Y];
}
calc(alg) {
return (0, _operator.operatorCalc)(alg, this);
}
clone() {
return new Point(this.x, this.y);
}
}
exports.Point = Point;
class IPoint extends APoint {
/**
* @returns {Point & number}
*/
toPoint() {
return new Point(this.x, this.y);
}
}
exports.IPoint = IPoint;
function calc(alg) {
return (0, _operator.operatorCalc)(alg);
}
const pointFactory = (0, _operator.cachedFunction)((x, y) => new Point(x, y));
/**
* @param {number | () => number} x
* @param {number} [y]
* @returns {Point & number}
*/
const point = (x, y) => pointFactory(x, y);
exports.point = point;
const ipointFactory = (0, _operator.cachedFunction)((x, y) => new IPoint(x, y));
/**
* @param {number | () => number} x
* @param {number} [y]
* @returns {IPoint & number}
*/
const ipoint = (x, y) => ipointFactory(x, y);
exports.ipoint = ipoint;
const ZERO = exports.ZERO = ipoint(0, 0);
const FORWARD = exports.FORWARD = ipoint(0, -1);
const LEFT = exports.LEFT = ipoint(-1, 0);