server/ui/js/vec2d.js

774 lines
17 KiB
JavaScript

// Copyright (c) 2013 Evan Shortiss
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
(function() {
// Default is to not use objects
var useObjects = false;
// Default is to use standard array
var AxesArray = Array;
/**
* Parse the arguments passed into Vec2D and Vec3D.
* @param {Mixed} args The argument array from caller function.
* @return {Array} The resulting axes array.
*/
function parseArgs(args) {
// User passed x and y
if (args.length === 2) {
return new Array(args[0], args[1]);
}
// User passed an array
else if (Object.prototype.toString.call(args[0]) === '[object Array]') {
return args[0];
}
// User passed x and y in an object
else if (typeof(args[0]) === 'object') {
return [args[0].x, args[0].y];
} else {
return [0, 0];
}
}
/**
* Check is the passed param a Vec2D instance.
* @param {Mixed} v The var to check.
* @return {Boolean} The result of check.
*/
function isVector(v) {
return v instanceof Vector || v instanceof ObjectVector;
};
/****************************************************************************
* Main array based vector class. Has instance methods attached to prototype.
* @constructor
* @param {Array} axes
****************************************************************************/
var Vector = function(axes) {
// Constructor for each array type is different. (Float32Array vs Array)
if (AxesArray.name === 'Float32Array') {
this._axes = new AxesArray([axes[0], axes[1]]);
} else {
this._axes = new AxesArray(axes[0], axes[1]);
}
};
Vector.prototype = {
/**
* Set both x and y
* @param x New x val
* @param y New y val
*/
setAxes: function(x, y) {
this._axes[0] = x;
this._axes[1] = y;
},
/**
* Getter for x axis.
* @return {Number}
*/
getX: function() {
return this._axes[0];
},
/**
* Setter for x axis.
*/
setX: function(x) {
this._axes[0] = x;
},
/**
* Getter for y axis.
* @return {Number}
*/
getY: function() {
return this._axes[1];
},
/**
* Setter for y axis.
*/
setY: function(y) {
this._axes[1] = y;
},
/**
* View vector as a string such as "Vec2D: (0, 4)"
* @param {Boolean}
* @return {String}
*/
toString: function(round) {
if (round) {
return '(' + Math.round(this.getX()) + ', ' + Math.round(this.getY()) + ')'
}
return '(' + this.getX() + ', ' + this.getY() + ')'
},
/**
* Return an array containing the vector axes.
* @return {Array}
*/
toArray: function() {
return new Array(this.getX(), this.getY());
},
/**
* Return an array containing the vector axes.
* @return {Object}
*/
toObject: function() {
return {
"x": this.getX(),
"y": this.getY()
};
},
/**
* Add the provided Vector to this one.
* @param {Vector} vec
*/
add: function(vec) {
this._axes[0] += vec._axes[0];
this._axes[1] += vec._axes[1];
return this;
},
/**
* Subtract the provided vector from this one.
* @param {Vector} vec
*/
subtract: function(vec) {
this._axes[0] -= vec._axes[0];
this._axes[1] -= vec._axes[1];
return this;
},
/**
* Check is the vector provided equal to this one.
* @param {Vec2D} vec
* @return {Boolean}
*/
equals: function(vec) {
return (vec._axes[0] == this._axes[0] && vec._axes[1] == this._axes[1]);
},
/**
* Multiply this vector by the provided vector.
* @param {Vector} vec
*/
multiplyByVector: function(vec) {
this._axes[0] *= vec._axes[0];
this._axes[1] *= vec._axes[1];
return this;
},
/**
* Multiply this vector by the provided vector.
* @param {Vector} vec
*/
divideByVector: function(vec) {
this._axes[0] /= vec._axes[0];
this._axes[1] /= vec._axes[1];
return this;
},
/**
* Multiply this vector by the provided number
* @param {Number} n
*/
multiplyByScalar: function(n) {
this._axes[0] *= n;
this._axes[1] *= n;
return this;
},
/**
* Divive this vector by the provided number
* @param {Number} n
*/
divideByScalar: function(n) {
this._axes[0] /= n;
this._axes[1] /= n;
return this;
},
/**
* Normalise this vector. Directly affects this vector.
* Use Vec2D.normalise(vector) to create a normalised clone of this.
*/
normalise: function() {
return this.multiplyByScalar(1 / this.magnitude());
},
/**
* For American spelling.
* Same as unit/normalise function.
*/
normalize: function() {
return this.normalise();
},
/**
* The same as normalise.
*/
unit: function() {
return this.normalise();
},
/**
* Return the magnitude (length) of this vector.
* @return {Number}
*/
magnitude: function() {
return Math.sqrt((this._axes[0] * this._axes[0]) + (this._axes[1] * this._axes[1]));
},
/**
* Return the magnitude (length) of this vector.
* @return {Number}
*/
length: function() {
return this.magnitude();
},
/**
* Get the dot product of this vector by another.
* @param {Vector} vec
* @return {Number}
*/
dot: function(vec) {
return (vec._axes[0] * this._axes[0]) + (vec._axes[1] * this._axes[1]);
},
/**
* Get the cross product of this vector by another.
* @param {Vector} vec
* @return {Number}
*/
cross: function(vec) {
return ((this._axes[0] * vec._axes[1]) - (this._axes[1] * vec._axes[0]));
},
/**
* Returns the reverse of the provided vector.
* @param {Vector} vec
*/
reverse: function(vec) {
this._axes[0] = -this._axes[0];
this._axes[1] = -this._axes[1];
return this;
},
/**
* Create a copy of this vector.
* @return {Vector}
*/
clone: function() {
return new Vector([this._axes[0], this._axes[1]]);
}
};
/****************************************************************************
* Main object based vector class. Has instance methods attached to prototype.
* @constructor
* @param {Array} axes
****************************************************************************/
var ObjectVector = function(axes) {
// Constructor for each array type is different. (Float32Array vs Array)
this._axes = {
x: axes[0],
y: axes[1]
};
};
ObjectVector.prototype = {
/**
* Set both x and y
* @param x New x val
* @param y New y val
*/
setAxes: function(x, y) {
this._axes.x = x;
this._axes.y = y;
},
/**
* Getter for x axis.
* @return {Number}
*/
getX: function() {
return this._axes.x;
},
/**
* Setter for x axis.
*/
setX: function(x) {
this._axes.x = x;
},
/**
* Getter for y axis.
* @return {Number}
*/
getY: function() {
return this._axes.y;
},
/**
* Setter for y axis.
*/
setY: function(y) {
this._axes.y = y;
},
/**
* View vector as a string such as "Vec2D: (0, 4)"
* @param {Boolean}
* @return {String}
*/
toString: function(round) {
if (round) {
return '(' + Math.round(this.getX()) + ', ' + Math.round(this.getY()) + ')'
}
return '(' + this.getX() + ', ' + this.getY() + ')'
},
/**
* Return an array containing the vector axes.
* @return {Array}
*/
toArray: function() {
return new Array(this.getX(), this.getY());
},
/**
* Return an array containing the vector axes.
* @return {Object}
*/
toObject: function() {
return {
"x": this.getX(),
"y": this.getY()
};
},
/**
* Add the provided Vector to this one.
* @param {Vector} vec
*/
add: function(vec) {
this._axes.x += vec._axes.x;
this._axes.y += vec._axes.y;
return this;
},
/**
* Subtract the provided vector from this one.
* @param {Vector} vec
*/
subtract: function(vec) {
this._axes.x -= vec._axes.x;
this._axes.y -= vec._axes.y;
return this;
},
/**
* Check is the vector provided equal to this one.
* @param {Vec2D} vec
* @return {Boolean}
*/
equals: function(vec) {
return (vec._axes.x == this._axes.x && vec._axes.y == this._axes.y);
},
/**
* Multiply this vector by the provided vector.
* @param {Vector} vec
*/
multiplyByVector: function(vec) {
this._axes.x *= vec._axes.x;
this._axes.y *= vec._axes.y;
return this;
},
/**
* Multiply this vector by the provided vector.
* @param {Vector} vec
*/
divideByVector: function(vec) {
this._axes.x /= vec._axes.x;
this._axes.y /= vec._axes.y;
return this;
},
/**
* Multiply this vector by the provided number
* @param {Number} n
*/
multiplyByScalar: function(n) {
this._axes.x *= n;
this._axes.y *= n;
return this;
},
/**
* Divive this vector by the provided number
* @param {Number} n
*/
divideByScalar: function(n) {
this._axes.x /= n;
this._axes.y /= n;
return this;
},
/**
* Normalise this vector. Directly affects this vector.
* Use Vec2D.normalise(vector) to create a normalised clone of this.
*/
normalise: function() {
return this.multiplyByScalar(1 / this.magnitude());
},
/**
* For American spelling.
* Same as unit/normalise function.
*/
normalize: function() {
return this.normalise();
},
/**
* The same as normalise.
*/
unit: function() {
return this.normalise();
},
/**
* Return the magnitude (length) of this vector.
* @return {Number}
*/
magnitude: function() {
return Math.sqrt((this._axes.x * this._axes.x) + (this._axes.y * this._axes.y));
},
/**
* Return the magnitude (length) of this vector.
* @return {Number}
*/
length: function() {
return this.magnitude();
},
/**
* Get the dot product of this vector by another.
* @param {Vector} vec
* @return {Number}
*/
dot: function(vec) {
return (vec._axes.x * this._axes.x) + (vec._axes.y * this._axes.y);
},
/**
* Get the cross product of this vector by another.
* @param {Vector} vec
* @return {Number}
*/
cross: function(vec) {
return ((this._axes.x * vec._axes.y) - (this._axes.y * vec._axes.x));
},
/**
* Returns the reverse of the provided vector.
* @param {Vector} vec
*/
reverse: function(vec) {
this._axes.x = -this._axes.x;
this._axes.y = -this._axes.y;
return this;
},
/**
* Create a copy of this vector.
* @return {Vector}
*/
clone: function() {
return new ObjectVector([this._axes.x, this._axes.y]);
}
};
/****************************************************************************
Publically exposed Vector interface.
****************************************************************************/
var Vec2D = function() {
};
Vec2D.prototype = {
Vector: Vector,
ObjectVector: ObjectVector,
/**
* Create a new Vector.
* @param {Number} [x]
* @param {Number} [y]
* @param {Object} [axes]
* @param {Array} [axes]
*/
create: function() {
if(useObjects) {
return new this.ObjectVector(parseArgs(arguments));
}
return new this.Vector(parseArgs(arguments));
},
/**
* Instruct the library to use standard JavaScript arrays.
* Otherwise the library will try use Float32Arrays if available. (This is default)
*/
useStandardArrays: function() {
useObjects = false;
AxesArray = Array;
},
/**
* Instruct the library to use Float32 JavaScript arrays. (This is default)
* Otherwise the library will use standard array.
*/
useFloat32Arrays: function() {
useObjects = false;
AxesArray = Float32Array;
},
/**
* Instruct library to use Objects to represent vectors.
*/
useObjects: function() {
useObjects = true;
},
/**
* Add v0 to v1 to produce a new vector
* @param {Vector} v0
* @param {Vector} v1
* @return {Vector}
*/
add: function(v0, v1) {
return this.create(v0.getX() + v1.getX(), v0.getY() + v1.getY())
},
/**
* Subtract v0 from v1 to produce a new Vector.
* @param {Vector} v0
* @param {Vector} v1
* @return {Vector}
*/
subtract: function(v0, v1) {
return this.create(v0.getX() - v1.getX(), v0.getY()- v1.getY())
},
/**
* Check are the provided vectors equal.
* @param {Vector} v0
* @param {Vector} v1
* @return {Boolean}
*/
equals: function(v0, v1) {
return v0.equals(v1);
},
/**
* Multiply a vector by a vector to produce a new Vector
* @param {Vector} v0
* @param {Vector} v1
* @return {Vector}
*/
vectorTimesVector: function(v0, v1) {
return this.create(v0.getX() * v1.getX(), v0.getY() * v1.getY());
},
/**
* Multiply a vector by a number to produce a new vector.
* @param {Vector} vec The var to store a result in.
* @param {Number} n The Vector to subtract from this one.
* @return {Vector}
*/
vectorTimesScalar: function(vec, n) {
return this.create(vec.getX() * n, vec.getY() * n);
},
/**
* Return a normalised version of provided vector.
* @param {Vector} vec
* @return {Vector}
*/
nomalise: function(vec) {
return this.timesScalar(vec, 1 / vec.magnitude());
},
/**
* Same as normalise
*/
normalize: function(vec) {
return this.normalise(vec);
},
/**
* Same as normalise.
*/
unit: function(vec) {
return this.normalise(vec);
},
/**
* Return the dot product of two vectors or this vector dot another.
* @param {Vector} v0
* @param {Vector} v1
* @return {Number}
*/
dot: function(v0, v1) {
return (v0.getX() * v1.getX()) + (v0.getY() * v1.getY());
},
/**
* Calculate the cross product of two vectors.
* @param {Vector} v0
* @param {Vector} v1
* @param {Vector}
*/
cross: function(v0, v1) {
return ((v0.getX() * v1.getY()) - (v0.getY() * v1.getX()));
},
/**
* Return the magnitude (length) of a vector.
* @param {Vector} vec
* @return {Number}
*/
magnitude: function(vec) {
return vec.magnitude();
},
/**
* Same as the magnitude.
*/
length: function(vec) {
return vec.magnitude();
},
/**
* Find sqaure distance between two vectors.
* @param {Vector} v0
* @param {Vector} v1
* @return {Number}
*/
distance: function(v0, v1) {
return Math.sqrt((v0.getX() - v1.getX()) * (v0.getX() - v1.getX()) + (v0.getY() - v1.getY()) * (v0.getY() - v1.getY()))
},
/**
* Returns the reverse of the provided vector.
* @param {Vector} vec
* @return {Vector}
*/
reverse: function(vec) {
return this.create(-vec.getX(), -vec.getY());
}
};
// Expose publically
if (typeof window !== 'undefined') {
window.Vec2D = new Vec2D();
} else {
module.exports = new Vec2D();
}
})();