js-2dmath
Version:
Fast 2d geometry math: Vector2, Rectangle, Circle, Matrix2x3 (2D transformation), Circle, BoundingBox, Line2, Segment2, Intersections, Distances, Transitions (animation/tween), Random numbers, Noise
276 lines (241 loc) • 5.89 kB
JavaScript
/**
* Stability: 1 (Only additions & fixes)
*
* Circle is represented as a two coordinates array
* [c:Vec2, r:Number]
*/
var Vec2 = require("./vec2.js"),
vec2_sub = Vec2.sub,
vec2_distance = Vec2.distance,
vec2_distance_sq = Vec2.distanceSq,
vec2_midpoint = Vec2.midPoint,
Rectangle = require("./rectangle.js"),
rectangle_center = Rectangle.center,
Triangle = require("./triangle.js"),
triangle_circumcenter = Triangle.circumcenter,
triangle_center = Triangle.center,
triangle_abmidpoint = Triangle.abMidPoint,
triangle_bcmidpoint = Triangle.bcMidPoint,
triangle_camidpoint = Triangle.caMidPoint,
max = Math.max,
TWOPI = Math.TWOPI,
QUATER_PI = Math.PI * 0.25,
PI = Math.PI,
sqrt = Math.sqrt,
aux_vec2 = [0, 0],
aux_num,
aux_num2;
/**
* @param {Number} x
* @param {Number} y
* @param {Number} radius
* @return {Circle}
*/
function create(x, y, radius) {
return [[x, y], radius];
}
/**
* @param {Vec2} vec2
* @param {Number} radius
* @return {Circle}
*/
function fromVec2(vec2, radius) {
return [[vec2[0], vec2[1]], radius];
}
/**
* Create a Circle with seg2 as diameter
*
* @param {Segment2} seg2
* @return {Circle}
*/
function fromSegment2(seg2) {
var out = [[0, 0], 0];
out[0][0] = (seg2[0] + seg2[2]) * 0.5;
out[0][1] = (seg2[1] + seg2[3]) * 0.5;
//subtract
aux_num = out[0][0] - seg2[0];
aux_num2 = out[0][1] - seg2[1];
//sqrLength
out[1] = sqrt(aux_num * aux_num + aux_num2 * aux_num2);
return out;
}
/**
* @param {Rectangle} rect
* @param {Boolean=} inside
* @return {Circle}
*/
function fromRectangle(rect, inside) {
var out = [[0, 0], 0];
rectangle_center(out[0], rect);
if (inside) {
aux_vec2[0] = rect[0][0] + (rect[1][0] - rect[0][0]) * 0.5;
aux_vec2[1] = rect[0][1];
out[1] = vec2_distance(out[0], aux_vec2);
} else {
out[1] = vec2_distance(out[0], rect[0]);
}
return out;
}
/**
* @todo review inside cases
* @param {Triangle} tri
* @param {Boolean=} inside
* @param {Boolean=} circumcenter
* @return {Circle}
*/
function fromTriangle(tri, inside, circumcenter) {
var out = [[0, 0], 0];
if (circumcenter && !inside) {
triangle_circumcenter(out[0], tri);
// use distance^2 for comparison
out[1] = vec2_distance_sq(out[0], tri[0]);
aux_num = vec2_distance_sq(out[0], tri[1]);
if (aux_num > out[1]) {
out[1] = aux_num;
}
out[1] = vec2_distance_sq(out[0], tri[2]);
if (aux_num > out[1]) {
out[1] = aux_num;
}
// and now return the good one :)
out[1] = sqrt(out[1]);
return out;
}
triangle_center(out[0], tri);
// use distance^2 for comparison
triangle_abmidpoint(aux_vec2, tri);
out[1] = vec2_distance_sq(out[0], aux_vec2);
triangle_bcmidpoint(aux_vec2, tri);
aux_num = vec2_distance_sq(out[0], aux_vec2);
if (aux_num < out[1]) {
out[1] = aux_num;
}
triangle_camidpoint(aux_vec2, tri);
aux_num = vec2_distance_sq(out[0], aux_vec2);
if (aux_num < out[1]) {
out[1] = aux_num;
}
// and now return the good one :)
out[1] = sqrt(out[1]);
return out;
}
/**
* @param {Circle} circle
* @return {Circle}
*/
function clone(circle) {
return [[circle[0][0], circle[0][1]], circle[1]];
}
/**
* @param {Circle} out
* @param {Circle} circle
* @return {Circle}
*/
function copy(out, circle) {
out[0][0] = circle[0][0];
out[0][1] = circle[0][1];
out[1] = circle[1];
return out;
}
/**
* @param {Circle} out
* @param {Circle} circle
* @param {Vec2} vec2
* @return {Circle}
*/
function translate(out, circle, vec2) {
out[0][0] = circle[0][0] + vec2[0];
out[0][1] = circle[0][1] + vec2[1];
out[1] = circle[1];
return out;
}
/**
* @param {Circle} out
* @param {Circle} circle
* @param {Vec2} vec2
* @return {Circle}
*/
function moveTo(out, circle, vec2) {
out[0][0] = vec2[0];
out[0][1] = vec2[1];
out[1] = circle[1];
return out;
}
/**
* @param {Circle} circle
* @param {Circle} circle_2
* @return {Number}
*/
function distance(circle, circle_2) {
return max(0, vec2_distance(circle[0], circle_2[0]) - circle[1] - circle_2[1]);
}
/**
* @param {Circle} circle
* @return {Number}
*/
function length(circle) {
return TWOPI * circle[1];
}
/**
* @param {Circle} circle
* @return {Number}
*/
function area(circle) {
return PI * circle[1] * circle[1];
}
/**
* @param {Circle} circle
* @param {Vec2} vec2
* @return {Boolean}
*/
function isVec2Inside(circle, vec2) {
return vec2_distance(circle[0], vec2) < circle[1];
}
/**
* @param {Vec2} out_vec2
* @param {Circle} circle
* @param {Vec2} vec2
* @return {Vec2}
*/
function closestPoint(out_vec2, circle, vec2) {
//const Vector& P, const Vector& Centre, float radius, bool* inside)
vec2_sub(out_vec2, vec2 - cirlce[0]);
var dist2 = vec2_length(out_vec2);
// is inside? (dist2 <= radius * radius);
//if(dist2 > EPS) Delta /= sqrt(dist2);
vec2_scale(out_vec2, out_vec2, scale);
vec2_add(out_vec2, cirlce[0], scale);
return out_vec2;
}
/**
* @param {Circle} circle
* @param {Number} mass
*/
function momentOfInertia(circle, mass) {
var r = circle[1];
return mass * r * r * 0.5;
}
/**
* @class Circle
*/
var Circle = {
create: create,
fromVec2: fromVec2,
fromSegment2: fromSegment2,
fromRectangle: fromRectangle,
fromTriangle: fromTriangle,
clone: clone,
copy: copy,
translate: translate,
moveTo: moveTo,
distance: distance,
length: length,
area: area,
isVec2Inside: isVec2Inside,
//physics
momentOfInertia: momentOfInertia,
// alias
perimeter: length,
move: moveTo
};
module.exports = Circle;