Skip to content

Instantly share code, notes, and snippets.

@GoToLoop
Last active February 13, 2023 05:21
Show Gist options
  • Save GoToLoop/acbf106aa784820aff23 to your computer and use it in GitHub Desktop.
Save GoToLoop/acbf106aa784820aff23 to your computer and use it in GitHub Desktop.
PVector Class Refactoring for PJS
//module.exports = function(options, undef) {
"use strict";
const TAU = 2 * Math.PI,
lerp = (start, stop, amt = 0) => +start + amt*(stop - start),
sq = n => n*n,
pjsCheck = obj => obj != null && 'noLoop' in obj,
argsErr = (mtd, len, min) => {
throw `Too few args passed to ${mtd}() [${len} < ${min}].`;
};
function PVector(x, y, z) {
this.x = x || 0, this.y = y || 0, this.z = z || 0;
}
PVector.fromAngle = (ang, t) =>
t? t.set(Math.cos(ang), Math.sin(ang))
: new PVector(Math.cos(ang), Math.sin(ang));
PVector.random2D = (t, p) => {
const isPjs = pjsCheck(t), rnd = p? p : isPjs && t || Math;
return PVector.fromAngle(TAU * rnd.random(), !isPjs && t || void 0);
};
PVector.random3D = (t, p) => {
const isPjs = pjsCheck(t),
rnd = p? p : isPjs && t || Math,
ang = TAU * rnd.random(),
vz = 2*rnd.random() - 1,
vzr = Math.sqrt(1 - vz*vz),
vx = vzr * Math.cos(ang),
vy = vzr * Math.sin(ang);
return t && !isPjs? t.set(vx, vy, vz) : new PVector(vx, vy, vz);
};
PVector.dist = (v1, v2) => Math.sqrt(PVector.distSq(v1, v2));
PVector.distSq = (v1, v2) => sq(v1.x-v2.x) + sq(v1.y-v2.y) + sq(v1.z-v2.z);
PVector.dot = (v1, v2) => v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
PVector.cross = (v1, v2, t) => {
const cx = v1.y*v2.z - v2.y*v1.z,
cy = v1.z*v2.x - v2.z*v1.x,
cz = v1.x*v2.y - v2.x*v1.y;
return t && t.set(cx, cy, cz) || new PVector(cx, cy, cz);
};
PVector.angleBetween = (v1, v2) => {
if (!v1.x && !v1.y && !v1.z || !v2.x && !v2.y && !v2.z) return 0;
const amt = PVector.dot(v1, v2) / Math.sqrt(v1.magSq() * v2.magSq());
return amt <= -1? Math.PI : amt >= 1? 0 : Math.acos(amt);
};
PVector.lerp = (v1, v2, amt, t) =>
(t && t.set(v1) || v1.copy()).lerp(v2, amt);
PVector.add = (v1, v2, t) =>
t? t.set(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z)
: new PVector(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
PVector.sub = (v1, v2, t) =>
t? t.set(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z)
: new PVector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
PVector.mult = (v, n, t) => {
if (typeof n === 'object')
return t? t.set(v.x*n.x, v.y*n.y, v.z*n.z)
: new PVector(v.x*n.x, v.y*n.y, v.z*n.z);
else
return t? t.set(v.x*n, v.y*n, v.z*n)
: new PVector(v.x*n, v.y*n, v.z*n);
};
PVector.div = (v, n, t) => {
if (typeof n === 'object')
return t? t.set(v.x/n.x, v.y/n.y, v.z/n.z)
: new PVector(v.x/n.x, v.y/n.y, v.z/n.z);
else
return t? t.set (v.x/n, v.y/n, v.z/n)
: new PVector(v.x/n, v.y/n, v.z/n);
};
PVector.mod = (v, n, t) => {
if (typeof n === 'object')
return t? t.set(v.x%n.x, v.y%n.y, v.z%n.z)
: new PVector(v.x%n.x, v.y%n.y, v.z%n.z);
else
return t? t.set(v.x%n, v.y%n, v.z%n)
: new PVector(v.x%n, v.y%n, v.z%n);
};
PVector.compare = (a, b) => a.x - b.x || a.y - b.y || a.z - b.z;
PVector.prototype = {
compareTo(v) {
return this.x - v.x || this.y - v.y || this.z - v.z;
},
array() { return [this.x, this.y, this.z]; },
object() { return { x: this.x, y: this.y, z: this.z }; },
copy() { return new PVector(this.x, this.y, this.z); },
clone: null,
get(t) {
if (!t) return t === void 0 && this.copy() || this.array();
else if ('z' in t) t.x = this.x, t.y = this.y, t.z = this.z;
else t[0] = this.x, t[1] = this.y, t[2] = this.z;
return t;
},
set(v, y, z) {
if (y != void 0) this.x = +v, this.y = +y, z != void 0 && (this.z = +z);
else this.set(v[0] || v.x || 0, v[1] || v.y || 0, v[2] || v.z);
return this;
},
normalize(t, mag) {
const m = +mag || this.mag(), canDivide = m === m && m !== 0 && m !== 1;
if (!arguments.length) return canDivide && this.div(m) || this;
return canDivide? PVector.div(this, m, t)
: t && t.set(this) || this.copy();
},
limit(max, t, magSq) {
const mSq = magSq || this.magSq(), overMax = mSq > max*max;
t === null && (t = new PVector);
return !t? overMax && this.normalize().mult(max) || this
: overMax && this.normalize(t, Math.sqrt(mSq)).mult(max)
|| t.set(this);
},
heading() { return Math.atan2(this.y, this.x); },
heading2D: null, // @Deprecated
mag() { return Math.sqrt(this.magSq()); },
magSq() { return this.x*this.x + this.y*this.y + this.z*this.z; },
setMag(t, len, mag) {
return typeof t === 'object'?
this.normalize(t, mag).mult(len) : this.normalize().mult(t);
},
rotate(ang, t) {
const c = Math.cos(ang),
s = Math.sin(ang),
x = c*this.x - s*this.y,
y = s*this.x + c*this.y;
t === null && (t = new PVector);
return (t || this).set(x, y);
},
rotateX(ang, t) {
const c = Math.cos(ang),
s = Math.sin(ang),
y = c*this.y - s*this.z,
z = s*this.y + c*this.z;
t === null && (t = new PVector);
return (t || this).set(this.x, y, z);
},
rotateY(ang, t) {
const c = Math.cos(ang),
s = Math.sin(ang),
x = s*this.z + c*this.x,
z = c*this.z - s*this.x;
t === null && (t = new PVector);
return (t || this).set(x, this.y, z);
},
rotateZ: null,
fromAngle(ang, t) {
return PVector.fromAngle(ang, t || this);
},
random2D(t, p) {
return pjsCheck(t) && PVector.random2D(this, t)
|| PVector.random2D(t === void 0 && this || t, p);
},
random3D(t, p) {
return pjsCheck(t) && PVector.random3D(this, t)
|| PVector.random3D(t === void 0 && this || t, p);
},
dist(v1, v2) {
return v2? PVector.dist(v1, v2) : PVector.dist(this, v1);
},
distSq(v1, v2) {
return v2? PVector.distSq(v1, v2) : PVector.distSq(this, v1);
},
dot(v, y, z) {
return typeof v != 'object'? this.x*v + this.y*+y + this.z*z :
y == void 0? PVector.dot(this, v) : PVector.dot(v, y);
},
cross(v1, v2, t) {
return t && PVector.cross(v1, v2, t) || PVector.cross(this, v1, v2);
},
angleBetween(v) { return PVector.angleBetween(this, v); },
lerp(a, b, c, d) {
let x, y, z, amt;
const len = arguments.length;
if (len < 2) argsErr('lerp', len, 2);
if (len === 2) { // given vector and amt
({x, y, z} = a), amt = b;
} else if (len === 3) { // given vector 1, vector 2 and amt
return PVector.lerp(a, b, c);
} else { // given x, y, z and amt
[x, y, z, amt] = arguments;
}
return this.set(lerp(this.x, x, amt),
lerp(this.y, y, amt),
lerp(this.z, z, amt));
},
add(v, y, z) {
if (y != void 0) {
if (typeof y === 'object') return PVector.add(v, y, z);
this.x += +v, this.y += +y, z != void 0 && (this.z += +z);
} else if (typeof v === 'object')
this.x += v.x, this.y += v.y, this.z += v.z;
else
this.x += +v, this.y += +v, this.z += +v;
return this;
},
sub(v, y, z) {
if (y != void 0) {
if (typeof y === 'object') return PVector.sub(v, y, z);
this.x -= v, this.y -= y, z != void 0 && (this.z -= z);
} else if (typeof v === 'object')
this.x -= v.x, this.y -= v.y, this.z -= v.z;
else
this.x -= v, this.y -= v, this.z -= v;
return this;
},
mult(v, n, t) {
if (n != void 0) return PVector.mult(v, n, t);
if (typeof v === 'object') this.x *= v.x, this.y *= v.y, this.z *= v.z;
else this.x *= v, this.y *= v, this.z *= v;
return this;
},
div(v, n, t) {
if (n != void 0) return PVector.div(v, n, t);
if (typeof v === 'object') this.x /= v.x, this.y /= v.y, this.z /= v.z;
else this.x /= v, this.y /= v, this.z /= v;
return this;
},
mod(v, n, t) {
if (n != void 0) return PVector.mod(v, n, t);
if (typeof v === 'object') this.x %= v.x, this.y %= v.y, this.z %= v.z;
else this.x %= v, this.y %= v, this.z %= v;
return this;
},
negate() {
this.x *= -1, this.y *= -1, this.z *= -1;
return this;
},
clear() {
this.x = this.y = this.z = 0;
return this;
},
isNaN() {
return this.x !== this.x || this.y !== this.y || this.z !== this.z;
},
toString() { return `[ ${this.x}, ${this.y}, ${this.z} ]`; },
valueOf() { return this.x; },
hashCode() { return this.x + this.y + this.z; },
equals(o) {
return o === this? true : o instanceof PVector &&
o.x === this.x && o.y === this.y && o.z === this.z;
}
};
PVector.prototype.clone = PVector.prototype.copy;
PVector.prototype.heading2D = PVector.prototype.heading; // @Deprecated
PVector.prototype.rotateZ = PVector.prototype.rotate;
//return PVector;
//};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment