vectors-co
Version:
A library for handling multi dimensional vectors
352 lines (284 loc) • 6.92 kB
text/typescript
export type TPoints<Length extends number> = [number, ...number[]] & { length: Length }
export class MismatchedSizeError {
private message: string
private name: string
constructor(lhsWidth: number, rhsWidth: number) {
this.message = `The left hand side, and the right hand side have mis-matched sizes. ${lhsWidth} and ${rhsWidth} respectively`
this.name = 'MismatchedSizeError'
}
}
/**
* This is the super class. A generically lengthened vector that takes in a type argument for the length.
*/
export class Vec<Length extends number> {
constructor(public points: TPoints<Length>, public length: Length) {
}
/**
* This function creates a vector where each element is the same value
* @param value The value for each element to be
* @param length The length of the vector
*/
static fromScalar<Length extends number>(value: number, length: Length): Vec<Length> {
return new Vec<Length>(new Array(length).fill(value) as TPoints<Length>, length)
}
/**
*
* @param rhs
* @protected
* @throws MismatchedSizeError
*/
protected _add(rhs: Vec<Length>) {
if (this.length !== rhs.length) {
throw new MismatchedSizeError(this.length, rhs.length)
}
return this.points.map((point, index) => point + rhs.points[index]) as TPoints<Length>
}
/**
* Adds two vectors together
* @param rhs
* @throws MismatchedSizeError
*/
add(rhs: Vec<Length>) {
return new Vec(this._add(rhs), this.length)
}
/**
*
* @param rhs
* @protected
* @throws MismatchedSizeError
*/
protected _sub(rhs: Vec<Length>) {
if (this.length !== rhs.length) {
throw new MismatchedSizeError(this.length, rhs.length)
}
return this.points.map((point, index) => point - rhs.points[index]) as TPoints<Length>
}
/**
* Subtracts two vectors togethers
* @param rhs
* @throws MismatchedSizeError
*/
sub(rhs: Vec<Length>) {
return new Vec(this._sub(rhs), this.length)
}
/**
*
* @param rhs
* @protected
* @throws MismatchedSizeError
*/
protected _mul(rhs: Vec<Length>) {
if (this.length !== rhs.length) {
throw new MismatchedSizeError(this.length, rhs.length)
}
return this.points.map((point, index) => point * rhs.points[index]) as TPoints<Length>
}
/**
* Multiples each value of two vectors together
* @param rhs
* @throws MismatchedSizeError
*/
mul(rhs: Vec<Length>) {
return new Vec(this._mul(rhs), this.length)
}
/**
*
* @param rhs
* @protected
* @throws MismatchedSizeError
*/
protected _div(rhs: Vec<Length>) {
if (this.length !== rhs.length) {
throw new MismatchedSizeError(this.length, rhs.length)
}
return this.points.map((point, index) => point / rhs.points[index]) as TPoints<Length>
}
protected _pow(power: number) {
return this.points.map((point) => point ** power) as TPoints<Length>
}
/**
* Raises each element to the power given
* @param power
*/
pow(power: number) {
return new Vec(this._pow(power), this.length)
}
/**
* Divides each value of two vectors together
* @param rhs
* @protected
* @throws MismatchedSizeError
*/
div(rhs: Vec<Length>) {
return new Vec(this._div(rhs), this.length)
}
/**
* Gives the dot product of two vectors
* @param rhs
* @throws MismatchedSizeError
*/
dot(rhs: Vec<Length>) {
return this._mul(rhs).reduce((n, acc) => n + acc, 0)
}
/**
* Gives the magnitude of the vector
*/
get size() {
return this.dot(this) ** 0.5
}
/**
* Gives the values of the vector summed up
*/
get sum() {
return this.points.reduce((n, acc) => n + acc, 0)
}
get _unit() {
const size = this.size
return this.points.map((point) => point / size) as TPoints<Length>
}
/**
* Returns a unit vector of the current vector
*/
get unit() {
return new Vec<Length>(this._unit, this.length)
}
}
export class Vec2 extends Vec<2> {
constructor(points: TPoints<2>) {
super(points, 2)
}
add(rhs: Vec<2>) {
return new Vec2(this._add(rhs))
}
sub(rhs: Vec<2>) {
return new Vec2(this._sub(rhs))
}
mul(rhs: Vec<2>) {
return new Vec2(this._mul(rhs))
}
div(rhs: Vec<2>) {
return new Vec2(this._div(rhs))
}
pow(power: number) {
return new Vec2(this._pow(power))
}
get x() {
return this.points[0]
}
set x(val) {
this.points[0] = val
}
get y() {
return this.points[1]
}
set y(val) {
this.points[1] = val
}
get unit() {
return new Vec2(this._unit)
}
}
export class Vec3 extends Vec<3> {
constructor(points: TPoints<3>) {
super(points, 3)
}
add(rhs: Vec<3>) {
return new Vec3(this._add(rhs))
}
sub(rhs: Vec<3>) {
return new Vec3(this._sub(rhs))
}
mul(rhs: Vec<3>) {
return new Vec3(this._mul(rhs))
}
div(rhs: Vec<3>) {
return new Vec3(this._div(rhs))
}
pow(power: number) {
return new Vec3(this._pow(power))
}
/**
* Calculates a cross product
* @param _rhs
* @throws MismatchedSizeError
*/
cross(_rhs: Vec<3>) {
if (this.length !== _rhs.length) {
throw new MismatchedSizeError(this.length, _rhs.length)
}
const rhs = new Vec3(_rhs.points)
return new Vec3([
this.y * rhs.z - this.z * rhs.y,
this.z * rhs.x - this.x * rhs.z,
this.z * rhs.y - this.y * rhs.x
])
}
get x() {
return this.points[0]
}
set x(val) {
this.points[0] = val
}
get y() {
return this.points[1]
}
set y(val) {
this.points[1] = val
}
get z() {
return this.points[2]
}
set z(val) {
this.points[2] = val
}
get unit() {
return new Vec3(this._unit)
}
}
export class Vec4 extends Vec<4> {
constructor(points: TPoints<4>) {
super(points, 4)
}
add(rhs: Vec<4>) {
return new Vec4(this._add(rhs))
}
sub(rhs: Vec<4>) {
return new Vec4(this._sub(rhs))
}
mul(rhs: Vec<4>) {
return new Vec4(this._mul(rhs))
}
div(rhs: Vec<4>) {
return new Vec4(this._div(rhs))
}
pow(power: number) {
return new Vec4(this._pow(power))
}
get x() {
return this.points[0]
}
set x(val) {
this.points[0] = val
}
get y() {
return this.points[1]
}
set y(val) {
this.points[1] = val
}
get z() {
return this.points[2]
}
set z(val) {
this.points[2] = val
}
get w() {
return this.points[3]
}
set w(val) {
this.points[3] = val
}
get unit() {
return new Vec4(this._unit)
}
}