planck-js
Version:
2D physics engine for JavaScript/HTML5 game development
428 lines (375 loc) • 8.48 kB
JavaScript
/*
* 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;
}