2014-01-23 12:32:08 +01:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
// Vector2D
|
|
|
|
//
|
|
|
|
// Class for representing and manipulating 2D vectors
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// TODO: Type errors if v not instanceof Vector classes
|
|
|
|
// TODO: Possibly implement in C++
|
|
|
|
|
|
|
|
function Vector2D(x, y)
|
|
|
|
{
|
|
|
|
if (arguments.length == 2)
|
|
|
|
this.set(x, y);
|
|
|
|
else
|
|
|
|
this.set(0, 0);
|
|
|
|
}
|
|
|
|
|
2014-01-24 20:51:00 +01:00
|
|
|
// Mutating 2D functions
|
|
|
|
//
|
|
|
|
// These functions modify the current object,
|
|
|
|
// and always return this object to allow chaining
|
2014-01-23 12:32:08 +01:00
|
|
|
|
|
|
|
Vector2D.prototype.set = function(x, y)
|
|
|
|
{
|
|
|
|
this.x = x;
|
|
|
|
this.y = y;
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector2D.prototype.add = function(v)
|
|
|
|
{
|
|
|
|
this.x += v.x;
|
|
|
|
this.y += v.y;
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector2D.prototype.sub = function(v)
|
|
|
|
{
|
|
|
|
this.x -= v.x;
|
|
|
|
this.y -= v.y;
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector2D.prototype.mult = function(f)
|
|
|
|
{
|
|
|
|
this.x *= f;
|
|
|
|
this.y *= f;
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector2D.prototype.div = function(f)
|
|
|
|
{
|
|
|
|
this.x /= f;
|
|
|
|
this.y /= f;
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2014-01-24 20:51:00 +01:00
|
|
|
Vector2D.prototype.normalize = function()
|
|
|
|
{
|
|
|
|
var mag = this.length();
|
|
|
|
if (!mag)
|
|
|
|
return this;
|
|
|
|
|
|
|
|
return this.div(mag);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Rotate a radians anti-clockwise
|
|
|
|
*/
|
|
|
|
Vector2D.prototype.rotate = function(a)
|
|
|
|
{
|
|
|
|
var sin = Math.sin(a);
|
|
|
|
var cos = Math.cos(a);
|
|
|
|
var x = this.x * cos + this.y * sin;
|
|
|
|
var y = this.y * cos - this.x * sin;
|
|
|
|
this.x = x;
|
|
|
|
this.y = y;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Numeric 2D info functions (non-mutating)
|
|
|
|
//
|
|
|
|
// These methods serve to get numeric info on the vector, they don't modify the vector
|
|
|
|
|
2014-01-23 12:32:08 +01:00
|
|
|
Vector2D.prototype.dot = function(v)
|
|
|
|
{
|
|
|
|
return this.x * v.x + this.y * v.y;
|
|
|
|
};
|
|
|
|
|
|
|
|
// get the non-zero coordinate of the vector cross
|
|
|
|
Vector2D.prototype.cross = function(v)
|
|
|
|
{
|
|
|
|
return this.x * v.y - this.y * v.x;
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector2D.prototype.lengthSquared = function()
|
|
|
|
{
|
|
|
|
return this.dot(this);
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector2D.prototype.length = function()
|
|
|
|
{
|
|
|
|
return Math.sqrt(this.lengthSquared());
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Compare this length to the length of v,
|
|
|
|
* @return 0 if the lengths are equal
|
|
|
|
* @return 1 if this is longer than v
|
|
|
|
* @return -1 if this is shorter than v
|
|
|
|
* @return NaN if the vectors aren't comparable
|
|
|
|
*/
|
|
|
|
Vector2D.prototype.compareLength = function(v)
|
|
|
|
{
|
|
|
|
var dDist = this.lengthSquared() - v.lengthSquared();
|
|
|
|
if (!dDist)
|
|
|
|
return dDist == 0 ? 0 : NaN;
|
|
|
|
return dDist < 0 ? -1 : 1;
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector2D.prototype.distanceToSquared = function(v)
|
|
|
|
{
|
|
|
|
var dx = this.x - v.x;
|
|
|
|
var dy = this.y - v.y;
|
|
|
|
return dx * dx + dy * dy;
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector2D.prototype.distanceTo = function(v)
|
|
|
|
{
|
|
|
|
return Math.sqrt(this.distanceToSquared(v));
|
|
|
|
};
|
|
|
|
|
2014-01-24 20:51:00 +01:00
|
|
|
// Static 2D functions
|
|
|
|
//
|
|
|
|
// Static functions that return a new vector object.
|
|
|
|
// Note that object creation is slow in JS, so use them only when necessary
|
|
|
|
|
|
|
|
Vector2D.clone = function(v)
|
2014-01-23 12:32:08 +01:00
|
|
|
{
|
2014-01-24 20:51:00 +01:00
|
|
|
return new Vector2D(v.x, v.y);
|
|
|
|
};
|
2014-01-23 12:32:08 +01:00
|
|
|
|
2014-01-24 20:51:00 +01:00
|
|
|
Vector2D.from3D = function(v)
|
|
|
|
{
|
|
|
|
return new Vector2D(v.x, v.z);
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector2D.add = function(v1, v2)
|
|
|
|
{
|
|
|
|
return new Vector2D(v1.x + v2.x, v1.y + v2.y);
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector2D.sub = function(v1, v2)
|
|
|
|
{
|
|
|
|
return new Vector2D(v1.x - v2.x, v1.y - v2.y);
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector2D.mult = function(v, f)
|
|
|
|
{
|
|
|
|
return new Vector2D(v.x * f, v.y * f);
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector2D.div = function(v, f)
|
|
|
|
{
|
|
|
|
return new Vector2D(v.x / f, v.y / f);
|
2014-01-23 12:32:08 +01:00
|
|
|
};
|
|
|
|
|
2014-01-27 13:34:59 +01:00
|
|
|
Vector2D.avg = function(vectorList)
|
|
|
|
{
|
|
|
|
return Vector2D.sum(vectorList).div(vectorList.length);
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector2D.sum = function(vectorList)
|
|
|
|
{
|
|
|
|
var sum = new Vector2D();
|
|
|
|
vectorList.forEach(function(v) {sum.add(v);});
|
|
|
|
return sum;
|
|
|
|
};
|
|
|
|
|
2014-01-23 12:32:08 +01:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
// Vector3D
|
|
|
|
//
|
|
|
|
// Class for representing and manipulating 3D vectors
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
function Vector3D(x, y, z)
|
|
|
|
{
|
|
|
|
if (arguments.length == 3)
|
2014-01-24 20:51:00 +01:00
|
|
|
this.set(x, y, z);
|
2014-01-23 12:32:08 +01:00
|
|
|
else
|
|
|
|
this.set(0, 0, 0);
|
|
|
|
}
|
|
|
|
|
2014-01-24 20:51:00 +01:00
|
|
|
// Mutating 3D functions
|
|
|
|
//
|
|
|
|
// These functions modify the current object,
|
|
|
|
// and always return this object to allow chaining
|
2014-01-23 12:32:08 +01:00
|
|
|
|
|
|
|
Vector3D.prototype.set = function(x, y, z)
|
|
|
|
{
|
|
|
|
this.x = x;
|
|
|
|
this.y = y;
|
|
|
|
this.z = z;
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector3D.prototype.add = function(v)
|
|
|
|
{
|
|
|
|
this.x += v.x;
|
|
|
|
this.y += v.y;
|
|
|
|
this.z += v.z;
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector3D.prototype.sub = function(v)
|
|
|
|
{
|
|
|
|
this.x -= v.x;
|
|
|
|
this.y -= v.y;
|
|
|
|
this.z -= v.z;
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector3D.prototype.mult = function(f)
|
|
|
|
{
|
|
|
|
this.x *= f;
|
|
|
|
this.y *= f;
|
|
|
|
this.z *= f;
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector3D.prototype.div = function(f)
|
|
|
|
{
|
|
|
|
this.x /= f;
|
|
|
|
this.y /= f;
|
|
|
|
this.z /= f;
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2014-01-24 20:51:00 +01:00
|
|
|
Vector3D.prototype.normalize = function()
|
|
|
|
{
|
|
|
|
var mag = this.length();
|
|
|
|
if (!mag)
|
|
|
|
return this;
|
|
|
|
|
|
|
|
return this.div(mag);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Numeric 3D info functions (non-mutating)
|
|
|
|
//
|
|
|
|
// These methods serve to get numeric info on the vector, they don't modify the vector
|
|
|
|
|
2014-01-23 12:32:08 +01:00
|
|
|
Vector3D.prototype.dot = function(v)
|
|
|
|
{
|
|
|
|
return this.x * v.x + this.y * v.y + this.z * v.z;
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector3D.prototype.lengthSquared = function()
|
|
|
|
{
|
|
|
|
return this.dot(this);
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector3D.prototype.length = function()
|
|
|
|
{
|
|
|
|
return Math.sqrt(this.lengthSquared());
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Compare this length to the length of v,
|
|
|
|
* @return 0 if the lengths are equal
|
|
|
|
* @return 1 if this is longer than v
|
|
|
|
* @return -1 if this is shorter than v
|
|
|
|
* @return NaN if the vectors aren't comparable
|
|
|
|
*/
|
|
|
|
Vector3D.prototype.compareLength = function(v)
|
|
|
|
{
|
|
|
|
var dDist = this.lengthSquared() - v.lengthSquared();
|
|
|
|
if (!dDist)
|
|
|
|
return dDist == 0 ? 0 : NaN;
|
|
|
|
return dDist < 0 ? -1 : 1;
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector3D.prototype.distanceToSquared = function(v)
|
|
|
|
{
|
|
|
|
var dx = this.x - v.x;
|
|
|
|
var dy = this.y - v.y;
|
|
|
|
var dz = this.z - v.z;
|
|
|
|
return dx * dx + dy * dy + dz * dz;
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector3D.prototype.distanceTo = function(v)
|
|
|
|
{
|
|
|
|
return Math.sqrt(this.distanceToSquared(v));
|
|
|
|
};
|
|
|
|
|
2014-01-24 20:51:00 +01:00
|
|
|
Vector3D.prototype.horizDistanceToSquared = function(v)
|
2014-01-23 12:32:08 +01:00
|
|
|
{
|
2014-01-24 20:51:00 +01:00
|
|
|
var dx = this.x - v.x;
|
|
|
|
var dz = this.z - v.z;
|
|
|
|
return dx * dx + dz * dz;
|
2014-01-23 12:32:08 +01:00
|
|
|
};
|
|
|
|
|
2014-01-24 20:51:00 +01:00
|
|
|
Vector3D.prototype.horizDistanceTo = function(v)
|
|
|
|
{
|
|
|
|
return Math.sqrt(this.horizDistanceToSquared(v));
|
|
|
|
};
|
|
|
|
|
|
|
|
// Static 3D functions
|
|
|
|
//
|
|
|
|
// Static functions that return a new vector object.
|
|
|
|
// Note that object creation is slow in JS, so use them only when really necessary
|
|
|
|
|
|
|
|
Vector3D.clone = function(v)
|
|
|
|
{
|
|
|
|
return new Vector3D(v.x, v.y, v.z);
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector3D.add = function(v1, v2)
|
|
|
|
{
|
|
|
|
return new Vector3D(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector3D.sub = function(v1, v2)
|
|
|
|
{
|
|
|
|
return new Vector3D(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector3D.mult = function(v, f)
|
|
|
|
{
|
|
|
|
return new Vector3D(v.x * f, v.y * f, v.z * f);
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector3D.div = function(v, f)
|
|
|
|
{
|
|
|
|
return new Vector3D(v.x / f, v.y / f, v.z / f);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-01-23 12:32:08 +01:00
|
|
|
// make the prototypes easily accessible to C++
|
|
|
|
const Vector2Dprototype = Vector2D.prototype;
|
|
|
|
const Vector3Dprototype = Vector3D.prototype;
|