var Shape = require('./Shape')
, vec2 = require('../math/vec2');
module.exports = Circle;
/**
* Circle shape class.
* @class Circle
* @extends Shape
* @constructor
* @param {options} [options] (Note that this options object will be passed on to the {{#crossLink "Shape"}}{{/crossLink}} constructor.)
* @param {number} [options.radius=1] The radius of this circle
*
* @example
* var circleShape = new Circle({ radius: 1 });
* body.addShape(circleShape);
*/
function Circle(options){
if(typeof(arguments[0]) === 'number'){
options = {
radius: arguments[0]
};
console.warn('The Circle constructor signature has changed. Please use the following format: new Circle({ radius: 1 })');
}
options = options || {};
/**
* The radius of the circle.
* @property radius
* @type {number}
*/
this.radius = options.radius || 1;
options.type = Shape.CIRCLE;
Shape.call(this, options);
}
Circle.prototype = new Shape();
Circle.prototype.constructor = Circle;
/**
* @method computeMomentOfInertia
* @param {Number} mass
* @return {Number}
*/
Circle.prototype.computeMomentOfInertia = function(mass){
var r = this.radius;
return mass * r * r / 2;
};
/**
* @method updateBoundingRadius
* @return {Number}
*/
Circle.prototype.updateBoundingRadius = function(){
this.boundingRadius = this.radius;
};
/**
* @method updateArea
* @return {Number}
*/
Circle.prototype.updateArea = function(){
this.area = Math.PI * this.radius * this.radius;
};
/**
* @method computeAABB
* @param {AABB} out The resulting AABB.
* @param {Array} position
* @param {Number} angle
*/
Circle.prototype.computeAABB = function(out, position, angle){
var r = this.radius;
vec2.set(out.upperBound, r, r);
vec2.set(out.lowerBound, -r, -r);
if(position){
vec2.add(out.lowerBound, out.lowerBound, position);
vec2.add(out.upperBound, out.upperBound, position);
}
};
var Ray_intersectSphere_intersectionPoint = vec2.create();
var Ray_intersectSphere_normal = vec2.create();
/**
* @method raycast
* @param {RaycastResult} result
* @param {Ray} ray
* @param {array} position
* @param {number} angle
*/
Circle.prototype.raycast = function(result, ray, position, angle){
var from = ray.from,
to = ray.to,
r = this.radius;
var a = Math.pow(to[0] - from[0], 2) + Math.pow(to[1] - from[1], 2);
var b = 2 * ((to[0] - from[0]) * (from[0] - position[0]) + (to[1] - from[1]) * (from[1] - position[1]));
var c = Math.pow(from[0] - position[0], 2) + Math.pow(from[1] - position[1], 2) - Math.pow(r, 2);
var delta = Math.pow(b, 2) - 4 * a * c;
var intersectionPoint = Ray_intersectSphere_intersectionPoint;
var normal = Ray_intersectSphere_normal;
if(delta < 0){
// No intersection
return;
} else if(delta === 0){
// single intersection point
vec2.lerp(intersectionPoint, from, to, delta);
vec2.sub(normal, intersectionPoint, position);
vec2.normalize(normal,normal);
ray.reportIntersection(result, delta, normal, -1);
} else {
var sqrtDelta = Math.sqrt(delta);
var inv2a = 1 / (2 * a);
var d1 = (- b - sqrtDelta) * inv2a;
var d2 = (- b + sqrtDelta) * inv2a;
if(d1 >= 0 && d1 <= 1){
vec2.lerp(intersectionPoint, from, to, d1);
vec2.sub(normal, intersectionPoint, position);
vec2.normalize(normal,normal);
ray.reportIntersection(result, d1, normal, -1);
if(result.shouldStop(ray)){
return;
}
}
if(d2 >= 0 && d2 <= 1){
vec2.lerp(intersectionPoint, from, to, d2);
vec2.sub(normal, intersectionPoint, position);
vec2.normalize(normal,normal);
ray.reportIntersection(result, d2, normal, -1);
}
}
};