UNPKG

planck-js

Version:

2D physics engine for JavaScript/HTML5 game development

428 lines (375 loc) 8.48 kB
/* * Copyright (c) 2016 Ali Shakiba http://shakiba.me/planck.js * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ module.exports = Vec2; var Math = require('./Math'); function Vec2(x, y) { if (!(this instanceof Vec2)) { return new Vec2(x, y); } if (typeof x === 'undefined') { this.x = 0, this.y = 0; } else if (typeof x === 'object') { this.x = x.x, this.y = x.y; } else { this.x = x, this.y = y; } Vec2.Assert(this); }; Vec2.prototype.toString = function() { return JSON.stringify(this); }; /** * Does this vector contain finite coordinates? */ Vec2.IsValid = function(v) { return v && Math.isFinite(v.x) && Math.isFinite(v.y); } Vec2.Assert = function(o) { if (!Vec2.IsValid(o)) { console.log(o); throw new Error('Invalid Vec2!'); } } Vec2.prototype.Clone = function(clone) { return Vec2.Clone(this, clone); } /** * Set this vector to all zeros. * * @returns this */ Vec2.prototype.SetZero = function() { this.x = 0.0; this.y = 0.0; return this; } /** * Set this vector to some specified coordinates. * * @returns this */ Vec2.prototype.Set = function(x, y) { Vec2.Set(this, x, y); return this; } Vec2.prototype.WSet = function(a, v, b, w) { Math.Assert(a); Vec2.Assert(v); this.x = a * v.x; this.y = a * v.y; if (typeof b !== 'undefined' || typeof w !== 'undefined') { Math.Assert(b); Vec2.Assert(w); this.x += b * w.x; this.y += b * w.y; } return this; } /** * Add a vector to this vector. * * @returns this */ Vec2.prototype.Add = function(w) { Vec2.Assert(w); this.x += w.x; this.y += w.y; return this; } Vec2.prototype.WAdd = function(a, v, b, w) { Math.Assert(a); Vec2.Assert(v); this.x += a * v.x; this.y += a * v.y; if (typeof b !== 'undefined' || typeof w !== 'undefined') { Math.Assert(b); Vec2.Assert(w); this.x += b * w.x; this.y += b * w.y; } return this; } Vec2.prototype.WSub = function(a, v, b, w) { Math.Assert(a); Vec2.Assert(v); this.x -= a * v.x; this.y -= a * v.y; if (typeof b !== 'undefined' || typeof w !== 'undefined') { Math.Assert(b); Vec2.Assert(w); this.x -= b * w.x; this.y -= b * w.y; } return this; } /** * Subtract a vector from this vector * * @returns this */ Vec2.prototype.Sub = function(w) { Vec2.Assert(w); this.x -= w.x; this.y -= w.y; return this; } /** * Multiply this vector by a scalar. * * @returns this */ Vec2.prototype.Mul = function(m) { Math.Assert(m); this.x *= m; this.y *= m; return this; } /** * Get the length of this vector (the norm). * * For performance, use this instead of LengthSquared (if possible). */ Vec2.prototype.Length = function() { return Vec2.Length(this); } /** * Get the length squared. */ Vec2.prototype.LengthSquared = function() { return Vec2.LengthSquared(this); } /** * Convert this vector into a unit vector. * * @returns old length */ Vec2.prototype.Normalize = function() { var length = this.Length(); if (length < Math.EPSILON) { return 0.0; } var invLength = 1.0 / length; this.x *= invLength; this.y *= invLength; return length; } Vec2.Clone = function(v, w) { Vec2.Assert(v); if (typeof w !== 'object') { return new Vec2(v.x, v.y); } w.x = v.x; w.y = v.y; return w; } /** * Get the length of this vector (the norm). * * For performance, use this instead of LengthSquared (if possible). */ Vec2.Length = function(v) { Vec2.Assert(v); return Math.sqrt(v.x * v.x + v.y * v.y); } /** * Get the length squared. */ Vec2.LengthSquared = function(v) { Vec2.Assert(v); return v.x * v.x + v.y * v.y; } Vec2.Distance = function(v, w) { Vec2.Assert(v); Vec2.Assert(w); var dx = v.x - w.x, dy = v.y - w.y; return Math.sqrt(dx * dx + dy * dy); } Vec2.DistanceSquared = function(v, w) { Vec2.Assert(v); Vec2.Assert(w); var dx = v.x - w.x, dy = v.y - w.y; return dx * dx + dy * dy; } Vec2.Equals = function(v, w) { Vec2.Assert(v); Vec2.Assert(w); return Vec2.IsEq(v, w); } Vec2.IsEq = function(v, w) { Vec2.Assert(v); Vec2.Assert(w); return v == w || typeof w === 'object' && w !== null && v.x == w.x && v.y == w.y; } /** * Get the skew vector such that dot(skew_vec, other) == cross(vec, other) */ Vec2.Skew = function(v) { Vec2.Assert(v); return new Vec2(-v.y, v.x); } /** * Perform the dot product on two vectors. */ Vec2.Dot = function(v, w) { Vec2.Assert(v); Vec2.Assert(w); return v.x * w.x + v.y * w.y; } /** * Perform the cross product on two vectors. In 2D this produces a scalar. * * Perform the cross product on a vector and a scalar. In 2D this produces a * vector. */ Vec2.Cross = function(v, w) { if (typeof w === 'number') { Vec2.Assert(v); Math.Assert(w); return new Vec2(w * v.y, -w * v.x); } else if (typeof v === 'number') { Math.Assert(v); Vec2.Assert(w); return new Vec2(-v * w.y, v * w.x); } else { Vec2.Assert(v); Vec2.Assert(w); return v.x * w.y - v.y * w.x } } Vec2.AddCross = function(a, v, w) { if (typeof w === 'number') { Vec2.Assert(v); Math.Assert(w); return new Vec2(w * v.y + a.x, -w * v.x + a.y); } else if (typeof v === 'number') { Math.Assert(v); Vec2.Assert(w); return new Vec2(-v * w.y + a.x, v * w.x + a.y); } Assert(false); } Vec2.Add = function(v, w) { Vec2.Assert(v); Vec2.Assert(w); return new Vec2(v.x + w.x, v.y + w.y); } Vec2.WAdd = function(a, v, b, w) { var r = Vec2(); r.WAdd(a, v); r.WAdd(b, w); return r; } Vec2.WGet = function(a, v) { var r = Vec2(); r.WAdd(a, v); return r; } Vec2.Sub = function(v, w) { Vec2.Assert(v); Vec2.Assert(w); return new Vec2(v.x - w.x, v.y - w.y); } Vec2.Mul = function(a, b) { if (typeof a === 'object') { Vec2.Assert(a); Math.Assert(b); return Vec2(a.x * b, a.y * b); } else if (typeof b === 'object') { Math.Assert(a); Vec2.Assert(b); return Vec2(a * b.x, a * b.y); } } Vec2.prototype.Neg = function() { this.x = -this.x; this.y = -this.y; } Vec2.Neg = function(v) { Vec2.Assert(v); return new Vec2(-v.x, -v.y); } Vec2.Abs = function(v) { Vec2.Assert(v); return new Vec2(Math.abs(v.x), Math.abs(v.y)); } Vec2.Mid = function(v, w) { Vec2.Assert(v); Vec2.Assert(w); return new Vec2((v.x + w.x) * 0.5, (v.y + w.y) * 0.5); } Vec2.SetZero = function(v) { Vec2.Assert(v); v.x = 0, v.y = 0; return v; } Vec2.Set = function(v, x, y) { Vec2.Assert(v); if (typeof x === 'object') { Vec2.Assert(x); v.x = x.x, v.y = x.y; } else { Math.Assert(x); Math.Assert(y); v.x = x, v.y = y; } return v; } Vec2.AddSet = function(v, w) { Vec2.Assert(v); Vec2.Assert(w); this.x += w.x, this.y += w.y; return v; } Vec2.SubSet = function(v, w) { Vec2.Assert(v); Vec2.Assert(w); v.x -= w.x, v.y -= w.y; return v; } Vec2.MulSet = function(v, m) { Vec2.Assert(v); Math.Assert(m); v.x *= m.x, v.y *= m.y; return v; } Vec2.Upper = function(v, w) { Vec2.Assert(v); Vec2.Assert(w); return new Vec2(Math.max(v.x, w.x), Math.max(v.y, w.y)); } Vec2.Lower = function(v, w) { Vec2.Assert(v); Vec2.Assert(w); return new Vec2(Math.min(v.x, w.x), Math.min(v.y, w.y)); } Vec2.prototype.Clamp = function(max) { var lengthSqr = this.x * this.x + this.y * this.y; if (lengthSqr > max * max) { var invLength = Math.invSqrt(lengthSqr); this.x *= invLength * max; this.y *= invLength * max; } return this; } Vec2.Clamp = function(v, max) { v = new Vec2(v.x, v.y); v.Clamp(max); return v; }