Last active
January 5, 2017 00:29
-
-
Save SeijiEmery/c483196ea317eab3a328 to your computer and use it in GitHub Desktop.
Lightweight js vec3 impl with experimental dynamic type checking
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Defines a better type querry function that enables object prototypes to define their own type repr | |
$typeof = function(value) { | |
return value.__proto__.type || typeof(value); | |
} | |
// Switch to 'release' (or any other value) to disable expensive typechecking. | |
releaseMode = 'debug'; | |
__handleTypeError = function (errMsg) { window.print("Type check failed: " + errMsg); } | |
Function.prototype.withTypeSignature = function (/* type arguments... */) { | |
var _this = this; | |
var numArgs = arguments.length(); | |
var argTypes = arguments.join(); | |
return function (/* arguments... */) { | |
if (numArgs !== arguments.length) { | |
__handleTypeError("Invalid argument count - expected " + | |
numArgs + " (" + argTypes + ") , got " + | |
arguments.length + " (" + arguments.map($typeof).join() + ")"); | |
return null; | |
} else { | |
args = arguments.map($typeof).join(); | |
if (argTypes !== args) { | |
__handleTypeError("Invalid argument types - expected (" + argTypes + "), got (" + args ")"); | |
return null; | |
} | |
} | |
return _this.apply(_this, arguments); | |
} | |
} | |
Function.prototype.withArgRange = function (minArgs, maxArgs) { | |
var _this = this; | |
return function (/* arguments... */) { | |
if (minArgs > arguments.length() || maxArgs < arguments.length()) { | |
__handleTypeError("Expected between " + minArgs + " and " + maxArgs + " arguments, not " + arguments.length()) | |
return null; | |
} | |
return _this.apply(_this, arguments); | |
} | |
} | |
if (releaseMode != 'debug') { | |
var passthrough = function () { return this; } | |
Function.prototype.typecheck = passthrough; | |
Function.prototype.withArgRange = passthrough; | |
} | |
Vec3 = function (x, y, z) { | |
this.x = x || 0.0f; | |
this.y = y || 0.0f; | |
this.z = z || 0.0f; | |
}.withArgRange(0, 3) | |
Vec3.prototype = {} | |
Vec3.prototype.type = 'Vec3' | |
Vec3.prototype.toString = function () { | |
return "Vec3(" + this.x + ", " + this.y + ", " + this.z + ")"; | |
} | |
Vec3.prototype.add = function (Vec3) { | |
this.x += Vec3.x; | |
this.y += Vec3.y; | |
this.z += Vec3.z; | |
return this; | |
}.withTypeSignature('Vec3') | |
Vec3.prototype.sub = function (Vec3) { | |
this.x -= Vec3.x; | |
this.y -= Vec3.y; | |
this.z -= Vec3.z; | |
return this; | |
}.withTypeSignature('Vec3') | |
Vec3.prototype.negate = function () { | |
this.x = -this.x; | |
this.y = -this.y; | |
this.z = -this.z; | |
return this; | |
}.withTypeSignature() | |
Vec3.prototype.mul = function (scalar) { | |
this.x *= scalar; | |
this.y *= scalar; | |
this.y *= scalar; | |
return this; | |
}.withTypeSignature('float') | |
Vec3.prototype.div = function (scalar) { | |
this.x /= scalar; | |
this.y /= scalar; | |
this.z /= scalar; | |
return this; | |
}.withTypeSignature('float') | |
Vec3.prototype.dot = function (Vec3) { | |
return this.x * Vec3.x + this.y * Vec3.y + this.z * Vec3.z; | |
}.withTypeSignature('Vec3') | |
Vec3.prototype.cross = function (Vec3) { | |
return new Vec3( | |
this.y * Vec3.z - this.z * Vec3.y, | |
this.z * Vec3.x - this.x * Vec3.z, | |
this.x * Vec3.y - this.y * Vec3.x | |
); | |
}.withTypeSignature('Vec3') | |
Vec3.prototype.distance = function (Vec3) { | |
var dx = this.x - Vec3.x; | |
var dy = this.y - Vec3.y; | |
var dz = this.z - Vec3.z; | |
return Math.sqrt(dx * dx + dy * dy + dz * dz); | |
}.withTypeSignature('Vec3') | |
Vec3.prototype.magnitude = function () { | |
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); | |
} | |
Vec3.prototype.normalize = function () { | |
this.div(this.magnitude()); | |
return this; | |
} | |
Vec3.prototype.copy = function () { | |
return new Vec3(this.x, this.y, this.z); | |
} | |
// Returns the component of this parallel to other (projection/parallel component) | |
Vec3.prototype.projection = function (Vec3) { | |
var projection = Vec3.copy(); | |
projection.mul(this.dot(Vec3) / Vec3.dot(Vec3)); | |
return projection; | |
} | |
// Returns the component of this perpendicular to other (rejection/tangential component) | |
Vec3.prototype.rejection = function (Vec3) { | |
var projection = this.projection(Vec3); | |
return projection.negate().add(this); | |
} | |
Vec3.cosTheta = function (Vec3) { | |
var a = this.copy(), b = Vec3; | |
return a.div(a.magnitude() * b.magnitude()).dot(b); | |
} | |
Vec3.add = function (a, b) { | |
return a.clone().add(b); | |
} | |
Vec3.sub = function (a, b) { | |
return a.clone().sub(b); | |
} | |
Vec3.mul = function (a, s) { | |
return a.clone().mul(s); | |
} | |
Vec3.div = function (a, s) { | |
return a.clone().div(s); | |
} | |
Vec3.normalized = function (a) { | |
return a.clone().normalize(); | |
} | |
Vec3.distance = function (a, b) { | |
return a.distance(b); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment