UNPKG

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

1,454 lines (1,248 loc) 1.1 MB
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({"js-2dmath":[function(require,module,exports){ module.exports=require('Focm2+'); },{}],"Focm2+":[function(require,module,exports){ require("./lib/math.js"); module.exports = { Vec2: require("./lib/vec2.js"), Line2: require("./lib/line2.js"), Segment2: require("./lib/segment2.js"), //geom Rectangle: require("./lib/rectangle.js"), AABB2: require("./lib/aabb2.js"), Circle: require("./lib/circle.js"), Triangle: require("./lib/triangle.js"), Polygon: require("./lib/polygon.js"), Beizer: require("./lib/beizer.js"), Matrix23: require("./lib/matrix23.js"), Matrix22: require("./lib/matrix22.js"), Collide: require("./lib/collide.js"), Intersection: require("./lib/intersection.js"), Transitions: require("./lib/transitions.js"), Xorshift: require("./lib/xorshift.js"), Noise: require("./lib/noise.js"), Draw: require("./lib/draw.js"), NMtree: require("./lib/nmtree.js"), Collision : { Response: require("./lib/collision/response.js"), GJK: require("./lib/collision/gjk.js"), EPA: require("./lib/collision/epa.js"), Manifold: require("./lib/collision/manifold.js"), SAT: require("./lib/collision/sat.js"), Resolve: require("./lib/collision/resolve.js") }, NumericalIntegration: { RK4: require("./lib/numerical-integration/rk4.js"), Verlet: require("./lib/numerical-integration/verlet.js"), Euler: require("./lib/numerical-integration/euler.js") } }; module.exports.globalize = function (object) { var i; for (i in module.exports) { if ("globalize" !== i) { object[i] = module.exports[i]; } } }; },{"./lib/aabb2.js":3,"./lib/beizer.js":4,"./lib/circle.js":5,"./lib/collide.js":6,"./lib/collision/epa.js":7,"./lib/collision/gjk.js":8,"./lib/collision/manifold.js":9,"./lib/collision/resolve.js":10,"./lib/collision/response.js":11,"./lib/collision/sat.js":12,"./lib/draw.js":14,"./lib/intersection.js":15,"./lib/line2.js":16,"./lib/math.js":17,"./lib/matrix22.js":18,"./lib/matrix23.js":19,"./lib/nmtree.js":20,"./lib/noise.js":21,"./lib/numerical-integration/euler.js":22,"./lib/numerical-integration/rk4.js":23,"./lib/numerical-integration/verlet.js":24,"./lib/polygon.js":25,"./lib/rectangle.js":26,"./lib/segment2.js":27,"./lib/transitions.js":28,"./lib/triangle.js":29,"./lib/vec2.js":30,"./lib/xorshift.js":31}],3:[function(require,module,exports){ /** * Stability: 1 (Only additions & fixes) * * BoundingBox2 is represented as a 5 coordinates array * [left: Number, bottom: Number, right: Number, top: Number, normalized: Boolean] */ var min = Math.min, max = Math.max, TOPLEFT = 1, TOPMIDDLE = 2, TOPRIGHT = 3, CENTERLEFT = 4, CENTER = 5, CENTERRIGHT = 6, BOTTOMLEFT = 7, BOTTOM = 8, BOTTOMRIGHT = 9, r = 0, x = 0, y = 0, min_x = 0, max_x = 0, min_y = 0, max_y = 0; /** * @param {Number} l * @param {Number} b * @param {Number} r * @param {Number} t * @return {AABB2} */ function create(l, b, r, t) { if (l == undefined || Number.isNaN(l) || 'number' !== typeof l) { throw new Error("l is undefined or null") } if (b == undefined || Number.isNaN(b) || 'number' !== typeof b) { throw new Error("b is undefined or null") } if (r == undefined || Number.isNaN(r) || 'number' !== typeof r) { throw new Error("r is undefined or null") } if (t == undefined || Number.isNaN(t) || 'number' !== typeof t) { throw new Error("t is undefined or null") } var out = [l, b, r, t, false]; normalize(out, out); return out; } /** * @param {AABB2} aabb2 * @param {Number} x * @param {Number} y * @return {Array<AABB2>} */ function fromAABB2Division(aabb2, x, y) { if (!Array.isArray(aabb2) || aabb2[0] == undefined || Number.isNaN(aabb2[0]) || 'number' !== typeof aabb2[0] || aabb2[1] == undefined || Number.isNaN(aabb2[1]) || 'number' !== typeof aabb2[1] || aabb2[2] == undefined || Number.isNaN(aabb2[2]) || 'number' !== typeof aabb2[2] || aabb2[3] == undefined || Number.isNaN(aabb2[3]) || 'number' !== typeof aabb2[3]) { throw new Error("invalid AABB2 aabb2") } if (x == undefined || Number.isNaN(x) || 'number' !== typeof x) { throw new Error("x is undefined or null") } if (y == undefined || Number.isNaN(y) || 'number' !== typeof y) { throw new Error("y is undefined or null") } var out = [], i, j, l = aabb2[0], b = aabb2[1], r = aabb2[2], t = aabb2[3], w = (r - l) / x, h = (t - b) / y; for (i = 0; i < x; ++i) { for (j = 0; j < y; ++j) { out.push([l + i * w, b + j * h, l + (i + 1) * w, b + (j + 1) * h]); } } return out; } /** * @param {Segment2} seg2 * @return {AABB2} */ function fromSegment2(seg2) { var out = [seg2[0], seg2[1], seg2[2], seg2[3], false]; normalize(out, out); return out; } /** * @param {Circle} circle * @return {AABB2} */ function fromCircle(circle) { r = circle[1]; x = circle[0][0]; y = circle[0][1]; return create( x - r, y - r, x + r, y + r ); } /** * @param {Rectangle} rect * @return {AABB2} */ function fromRectangle(rect) { if (!Array.isArray(rect) || rect[0][0] == undefined || Number.isNaN(rect[0][0]) || 'number' !== typeof rect[0][0] || rect[0][1] == undefined || Number.isNaN(rect[0][1]) || 'number' !== typeof rect[0][1] || rect[1][0] == undefined || Number.isNaN(rect[1][0]) || 'number' !== typeof rect[1][0] || rect[1][1] == undefined || Number.isNaN(rect[1][1]) || 'number' !== typeof rect[1][1]) { throw new Error("invalid Rectangle rect") } var out = [rect[0][0], rect[0][1], rect[1][0], rect[1][1], false]; normalize(out, out); return out; } /** * @todo implement a more robust / fast algorithm http://stackoverflow.com/questions/2587751/an-algorithm-to-find-bounding-box-of-closed-bezier-curves (Timo answer) * * @reference http://jsfiddle.net/4VCVX/3/ * * @param {Beizer} beizer * @param {Number} npoints * @return {AABB2} */ function fromBeizer(beizer, npoints) { if (npoints == undefined || Number.isNaN(npoints) || 'number' !== typeof npoints) { throw new Error("npoints is undefined or null") } npoints = npoints || 40; var vec2_list = Beizer.get(beizer, npoints), i, l = Infinity, b = Infinity, r = -Infinity, t = -Infinity, v, x, y; // loop min, max for (i = 0; i < npoints; ++i) { v = vec2_list[i]; x = v[0]; y = v[1]; if (x > r) { r = x; } else if (x < l) { l = x; } if (y < b) { b = y; } else if (y > t) { t = y; } } return [l, b, r, t, true]; } /** * @return {AABB2} */ function zero() { return [0, 0, 0, 0, true]; } /** * @param {AABB2} aabb2 * @return {AABB2} */ function clone(aabb2) { if (!Array.isArray(aabb2) || aabb2[0] == undefined || Number.isNaN(aabb2[0]) || 'number' !== typeof aabb2[0] || aabb2[1] == undefined || Number.isNaN(aabb2[1]) || 'number' !== typeof aabb2[1] || aabb2[2] == undefined || Number.isNaN(aabb2[2]) || 'number' !== typeof aabb2[2] || aabb2[3] == undefined || Number.isNaN(aabb2[3]) || 'number' !== typeof aabb2[3]) { throw new Error("invalid AABB2 aabb2") } return [aabb2[0], aabb2[1], aabb2[2], aabb2[3], aabb2[4]]; } /** * @param {AABB2} out * @param {AABB2} aabb2 * @return {AABB2} */ function copy(out, aabb2) { if (!Array.isArray(out) || out[0] == undefined || Number.isNaN(out[0]) || 'number' !== typeof out[0] || out[1] == undefined || Number.isNaN(out[1]) || 'number' !== typeof out[1] || out[2] == undefined || Number.isNaN(out[2]) || 'number' !== typeof out[2] || out[3] == undefined || Number.isNaN(out[3]) || 'number' !== typeof out[3]) { throw new Error("invalid AABB2 out") } if (!Array.isArray(aabb2) || aabb2[0] == undefined || Number.isNaN(aabb2[0]) || 'number' !== typeof aabb2[0] || aabb2[1] == undefined || Number.isNaN(aabb2[1]) || 'number' !== typeof aabb2[1] || aabb2[2] == undefined || Number.isNaN(aabb2[2]) || 'number' !== typeof aabb2[2] || aabb2[3] == undefined || Number.isNaN(aabb2[3]) || 'number' !== typeof aabb2[3]) { throw new Error("invalid AABB2 aabb2") } out[0] = aabb2[0]; out[1] = aabb2[1]; out[2] = aabb2[2]; out[3] = aabb2[3]; out[4] = aabb2[4]; return out; } /** * @param {AABB2} out * @param {AABB2} aabb2 * @param {Number} margin * @return {AABB2} */ function expand(out, aabb2, margin) { if (!Array.isArray(out) || out[0] == undefined || Number.isNaN(out[0]) || 'number' !== typeof out[0] || out[1] == undefined || Number.isNaN(out[1]) || 'number' !== typeof out[1] || out[2] == undefined || Number.isNaN(out[2]) || 'number' !== typeof out[2] || out[3] == undefined || Number.isNaN(out[3]) || 'number' !== typeof out[3]) { throw new Error("invalid AABB2 out") } if (!Array.isArray(aabb2) || aabb2[0] == undefined || Number.isNaN(aabb2[0]) || 'number' !== typeof aabb2[0] || aabb2[1] == undefined || Number.isNaN(aabb2[1]) || 'number' !== typeof aabb2[1] || aabb2[2] == undefined || Number.isNaN(aabb2[2]) || 'number' !== typeof aabb2[2] || aabb2[3] == undefined || Number.isNaN(aabb2[3]) || 'number' !== typeof aabb2[3]) { throw new Error("invalid AABB2 aabb2") } if (margin == undefined || Number.isNaN(margin) || 'number' !== typeof margin) { throw new Error("margin is undefined or null") } out[0] = aabb2[0] - margin; out[1] = aabb2[1] - margin; out[2] = aabb2[2] + margin; out[3] = aabb2[3] + margin; return out; } /** * @param {AABB2} out * @param {AABB2} aabb2_1 * @param {AABB2} aabb2_2 * @return {AABB2} */ function merge(out, aabb2_1, aabb2_2) { if (!Array.isArray(out) || out[0] == undefined || Number.isNaN(out[0]) || 'number' !== typeof out[0] || out[1] == undefined || Number.isNaN(out[1]) || 'number' !== typeof out[1] || out[2] == undefined || Number.isNaN(out[2]) || 'number' !== typeof out[2] || out[3] == undefined || Number.isNaN(out[3]) || 'number' !== typeof out[3]) { throw new Error("invalid AABB2 out") } if (!Array.isArray(aabb2_1) || aabb2_1[0] == undefined || Number.isNaN(aabb2_1[0]) || 'number' !== typeof aabb2_1[0] || aabb2_1[1] == undefined || Number.isNaN(aabb2_1[1]) || 'number' !== typeof aabb2_1[1] || aabb2_1[2] == undefined || Number.isNaN(aabb2_1[2]) || 'number' !== typeof aabb2_1[2] || aabb2_1[3] == undefined || Number.isNaN(aabb2_1[3]) || 'number' !== typeof aabb2_1[3]) { throw new Error("invalid AABB2 aabb2_1") } if (!Array.isArray(aabb2_2) || aabb2_2[0] == undefined || Number.isNaN(aabb2_2[0]) || 'number' !== typeof aabb2_2[0] || aabb2_2[1] == undefined || Number.isNaN(aabb2_2[1]) || 'number' !== typeof aabb2_2[1] || aabb2_2[2] == undefined || Number.isNaN(aabb2_2[2]) || 'number' !== typeof aabb2_2[2] || aabb2_2[3] == undefined || Number.isNaN(aabb2_2[3]) || 'number' !== typeof aabb2_2[3]) { throw new Error("invalid AABB2 aabb2_2") } out[0] = min(aabb2_1[0], aabb2_2[0]); out[1] = min(aabb2_1[1], aabb2_2[1]); out[2] = max(aabb2_1[2], aabb2_2[2]); out[3] = max(aabb2_1[3], aabb2_2[3]); return out; } /** * @param {AABB2} out * @param {AABB2} aabb2_1 * @param {AABB2} aabb2_2 * @param {Vec2} vec2_offset * @return {AABB2} */ function offsetMerge(out, aabb2_1, aabb2_2, vec2_offset) { if (!Array.isArray(out) || out[0] == undefined || Number.isNaN(out[0]) || 'number' !== typeof out[0] || out[1] == undefined || Number.isNaN(out[1]) || 'number' !== typeof out[1] || out[2] == undefined || Number.isNaN(out[2]) || 'number' !== typeof out[2] || out[3] == undefined || Number.isNaN(out[3]) || 'number' !== typeof out[3]) { throw new Error("invalid AABB2 out") } if (!Array.isArray(aabb2_1) || aabb2_1[0] == undefined || Number.isNaN(aabb2_1[0]) || 'number' !== typeof aabb2_1[0] || aabb2_1[1] == undefined || Number.isNaN(aabb2_1[1]) || 'number' !== typeof aabb2_1[1] || aabb2_1[2] == undefined || Number.isNaN(aabb2_1[2]) || 'number' !== typeof aabb2_1[2] || aabb2_1[3] == undefined || Number.isNaN(aabb2_1[3]) || 'number' !== typeof aabb2_1[3]) { throw new Error("invalid AABB2 aabb2_1") } if (!Array.isArray(aabb2_2) || aabb2_2[0] == undefined || Number.isNaN(aabb2_2[0]) || 'number' !== typeof aabb2_2[0] || aabb2_2[1] == undefined || Number.isNaN(aabb2_2[1]) || 'number' !== typeof aabb2_2[1] || aabb2_2[2] == undefined || Number.isNaN(aabb2_2[2]) || 'number' !== typeof aabb2_2[2] || aabb2_2[3] == undefined || Number.isNaN(aabb2_2[3]) || 'number' !== typeof aabb2_2[3]) { throw new Error("invalid AABB2 aabb2_2") } if (!Array.isArray(vec2_offset) || vec2_offset[0] == undefined || Number.isNaN(vec2_offset[0]) || 'number' !== typeof vec2_offset[0] || vec2_offset[1] == undefined || Number.isNaN(vec2_offset[1]) || 'number' !== typeof vec2_offset[1]) { throw new Error("invalid Vec2 vec2_offset") } out[0] = min(aabb2_1[0], aabb2_2[0] + vec2_offset[0]); out[1] = min(aabb2_1[1], aabb2_2[1] + vec2_offset[1]); out[2] = max(aabb2_1[2], aabb2_2[2] + vec2_offset[0]); out[3] = max(aabb2_1[3], aabb2_2[3] + vec2_offset[1]); return out; } /** * offset & scale merge * @param {AABB2} out * @param {AABB2} aabb2_1 * @param {AABB2} aabb2_2 * @param {Vec2} vec2_offset * @param {Vec2} vec2_scale * @return {AABB2} */ function osMerge(out, aabb2_1, aabb2_2, vec2_offset, vec2_scale) { if (!Array.isArray(out) || out[0] == undefined || Number.isNaN(out[0]) || 'number' !== typeof out[0] || out[1] == undefined || Number.isNaN(out[1]) || 'number' !== typeof out[1] || out[2] == undefined || Number.isNaN(out[2]) || 'number' !== typeof out[2] || out[3] == undefined || Number.isNaN(out[3]) || 'number' !== typeof out[3]) { throw new Error("invalid AABB2 out") } if (!Array.isArray(aabb2_1) || aabb2_1[0] == undefined || Number.isNaN(aabb2_1[0]) || 'number' !== typeof aabb2_1[0] || aabb2_1[1] == undefined || Number.isNaN(aabb2_1[1]) || 'number' !== typeof aabb2_1[1] || aabb2_1[2] == undefined || Number.isNaN(aabb2_1[2]) || 'number' !== typeof aabb2_1[2] || aabb2_1[3] == undefined || Number.isNaN(aabb2_1[3]) || 'number' !== typeof aabb2_1[3]) { throw new Error("invalid AABB2 aabb2_1") } if (!Array.isArray(aabb2_2) || aabb2_2[0] == undefined || Number.isNaN(aabb2_2[0]) || 'number' !== typeof aabb2_2[0] || aabb2_2[1] == undefined || Number.isNaN(aabb2_2[1]) || 'number' !== typeof aabb2_2[1] || aabb2_2[2] == undefined || Number.isNaN(aabb2_2[2]) || 'number' !== typeof aabb2_2[2] || aabb2_2[3] == undefined || Number.isNaN(aabb2_2[3]) || 'number' !== typeof aabb2_2[3]) { throw new Error("invalid AABB2 aabb2_2") } if (!Array.isArray(vec2_offset) || vec2_offset[0] == undefined || Number.isNaN(vec2_offset[0]) || 'number' !== typeof vec2_offset[0] || vec2_offset[1] == undefined || Number.isNaN(vec2_offset[1]) || 'number' !== typeof vec2_offset[1]) { throw new Error("invalid Vec2 vec2_offset") } if (!Array.isArray(vec2_scale) || vec2_scale[0] == undefined || Number.isNaN(vec2_scale[0]) || 'number' !== typeof vec2_scale[0] || vec2_scale[1] == undefined || Number.isNaN(vec2_scale[1]) || 'number' !== typeof vec2_scale[1]) { throw new Error("invalid Vec2 vec2_scale") } out[0] = min(aabb2_1[0], (aabb2_2[0] * vec2_scale[0]) + vec2_offset[0]); out[1] = min(aabb2_1[1], (aabb2_2[1] * vec2_scale[1]) + vec2_offset[1]); out[2] = max(aabb2_1[2], (aabb2_2[2] * vec2_scale[0]) + vec2_offset[0]); out[3] = max(aabb2_1[3], (aabb2_2[3] * vec2_scale[1]) + vec2_offset[1]); return out; } /** * offset & scale merge * @param {AABB2} aabb2 * @return {Number} */ function area(aabb2) { if (!Array.isArray(aabb2) || aabb2[0] == undefined || Number.isNaN(aabb2[0]) || 'number' !== typeof aabb2[0] || aabb2[1] == undefined || Number.isNaN(aabb2[1]) || 'number' !== typeof aabb2[1] || aabb2[2] == undefined || Number.isNaN(aabb2[2]) || 'number' !== typeof aabb2[2] || aabb2[3] == undefined || Number.isNaN(aabb2[3]) || 'number' !== typeof aabb2[3]) { throw new Error("invalid AABB2 aabb2") } return (aabb2[2] - aabb2[0]) * (aabb2[3] - aabb2[1]); } /** * @param {AABB2} out * @param {AABB2} aabb2 * @return {AABB2} */ function normalize(out, aabb2) { if (!Array.isArray(out) || out[0] == undefined || Number.isNaN(out[0]) || 'number' !== typeof out[0] || out[1] == undefined || Number.isNaN(out[1]) || 'number' !== typeof out[1] || out[2] == undefined || Number.isNaN(out[2]) || 'number' !== typeof out[2] || out[3] == undefined || Number.isNaN(out[3]) || 'number' !== typeof out[3]) { throw new Error("invalid AABB2 out") } if (!Array.isArray(aabb2) || aabb2[0] == undefined || Number.isNaN(aabb2[0]) || 'number' !== typeof aabb2[0] || aabb2[1] == undefined || Number.isNaN(aabb2[1]) || 'number' !== typeof aabb2[1] || aabb2[2] == undefined || Number.isNaN(aabb2[2]) || 'number' !== typeof aabb2[2] || aabb2[3] == undefined || Number.isNaN(aabb2[3]) || 'number' !== typeof aabb2[3]) { throw new Error("invalid AABB2 aabb2") } min_x = aabb2[0] > aabb2[2] ? aabb2[2] : aabb2[0]; max_x = aabb2[0] > aabb2[2] ? aabb2[0] : aabb2[2]; min_y = aabb2[1] > aabb2[3] ? aabb2[3] : aabb2[1]; max_y = aabb2[1] > aabb2[3] ? aabb2[1] : aabb2[3]; out[0] = min_x; out[1] = min_y; out[2] = max_x; out[3] = max_y; out[4] = true; } /** * @param {AABB2} out * @param {AABB2} aabb2 * @param {Vec2} vec2 * @return {AABB2} */ function translate(out, aabb2, vec2) { if (!Array.isArray(out) || out[0] == undefined || Number.isNaN(out[0]) || 'number' !== typeof out[0] || out[1] == undefined || Number.isNaN(out[1]) || 'number' !== typeof out[1] || out[2] == undefined || Number.isNaN(out[2]) || 'number' !== typeof out[2] || out[3] == undefined || Number.isNaN(out[3]) || 'number' !== typeof out[3]) { throw new Error("invalid AABB2 out") } if (!Array.isArray(aabb2) || aabb2[0] == undefined || Number.isNaN(aabb2[0]) || 'number' !== typeof aabb2[0] || aabb2[1] == undefined || Number.isNaN(aabb2[1]) || 'number' !== typeof aabb2[1] || aabb2[2] == undefined || Number.isNaN(aabb2[2]) || 'number' !== typeof aabb2[2] || aabb2[3] == undefined || Number.isNaN(aabb2[3]) || 'number' !== typeof aabb2[3]) { throw new Error("invalid AABB2 aabb2") } if (!Array.isArray(vec2) || vec2[0] == undefined || Number.isNaN(vec2[0]) || 'number' !== typeof vec2[0] || vec2[1] == undefined || Number.isNaN(vec2[1]) || 'number' !== typeof vec2[1]) { throw new Error("invalid Vec2 vec2") } x = vec2[0]; y = vec2[1]; out[0] = aabb2[0] + x; out[1] = aabb2[1] + y; out[2] = aabb2[2] + x; out[3] = aabb2[3] + y; return out; } /** * @param {Vec2} out_vec2 * @param {AABB2} aabb2 * @param {Vec2} vec2 * @return {Vec2} */ function clampVec(out_vec2, aabb2, vec2) { if (!Array.isArray(out_vec2) || out_vec2[0] == undefined || Number.isNaN(out_vec2[0]) || 'number' !== typeof out_vec2[0] || out_vec2[1] == undefined || Number.isNaN(out_vec2[1]) || 'number' !== typeof out_vec2[1]) { throw new Error("invalid Vec2 out_vec2") } if (!Array.isArray(aabb2) || aabb2[0] == undefined || Number.isNaN(aabb2[0]) || 'number' !== typeof aabb2[0] || aabb2[1] == undefined || Number.isNaN(aabb2[1]) || 'number' !== typeof aabb2[1] || aabb2[2] == undefined || Number.isNaN(aabb2[2]) || 'number' !== typeof aabb2[2] || aabb2[3] == undefined || Number.isNaN(aabb2[3]) || 'number' !== typeof aabb2[3]) { throw new Error("invalid AABB2 aabb2") } if (!Array.isArray(vec2) || vec2[0] == undefined || Number.isNaN(vec2[0]) || 'number' !== typeof vec2[0] || vec2[1] == undefined || Number.isNaN(vec2[1]) || 'number' !== typeof vec2[1]) { throw new Error("invalid Vec2 vec2") } out_vec2[0] = min(max(aabb2[0], vec2[0]), aabb2[2]); out_vec2[1] = min(max(aabb2[1], vec2[1]), aabb2[3]); return out_vec2; } /** * @param {Vec2} out_vec2 * @param {AABB2} aabb2 */ function center(out_vec2, aabb2) { if (!Array.isArray(out_vec2) || out_vec2[0] == undefined || Number.isNaN(out_vec2[0]) || 'number' !== typeof out_vec2[0] || out_vec2[1] == undefined || Number.isNaN(out_vec2[1]) || 'number' !== typeof out_vec2[1]) { throw new Error("invalid Vec2 out_vec2") } if (!Array.isArray(aabb2) || aabb2[0] == undefined || Number.isNaN(aabb2[0]) || 'number' !== typeof aabb2[0] || aabb2[1] == undefined || Number.isNaN(aabb2[1]) || 'number' !== typeof aabb2[1] || aabb2[2] == undefined || Number.isNaN(aabb2[2]) || 'number' !== typeof aabb2[2] || aabb2[3] == undefined || Number.isNaN(aabb2[3]) || 'number' !== typeof aabb2[3]) { throw new Error("invalid AABB2 aabb2") } out_vec2[0] = (aabb2[0] + aabb2[1]) * 0.5; out_vec2[1] = (aabb2[3] + aabb2[2]) * 0.5; return out_vec2; } /** * alignment values: AABB2.TOPLEFT, AABB2.TOPMIDDLE, AABB2.TOPRIGHT, AABB2.CENTERLEFT, AABB2.CENTER, AABB2.CENTERRIGHT, AABB2.BOTTOMLEFT, AABB2.BOTTOM, AABB2.BOTTOMRIGH * * @param {Vec2} out_vec2 * @param {AABB2} aabb2 * @param {Number} alignment * @return {Vec2} */ function align(out_vec2, aabb2, alignment) { if (!Array.isArray(out_vec2) || out_vec2[0] == undefined || Number.isNaN(out_vec2[0]) || 'number' !== typeof out_vec2[0] || out_vec2[1] == undefined || Number.isNaN(out_vec2[1]) || 'number' !== typeof out_vec2[1]) { throw new Error("invalid Vec2 out_vec2") } if (!Array.isArray(aabb2) || aabb2[0] == undefined || Number.isNaN(aabb2[0]) || 'number' !== typeof aabb2[0] || aabb2[1] == undefined || Number.isNaN(aabb2[1]) || 'number' !== typeof aabb2[1] || aabb2[2] == undefined || Number.isNaN(aabb2[2]) || 'number' !== typeof aabb2[2] || aabb2[3] == undefined || Number.isNaN(aabb2[3]) || 'number' !== typeof aabb2[3]) { throw new Error("invalid AABB2 aabb2") } if (alignment == undefined || Number.isNaN(alignment) || 'number' !== typeof alignment) { throw new Error("alignment is undefined or null") } switch (alignment) { case TOPLEFT: // do nothing! out_vec2[0] = aabb2[0]; out_vec2[1] = aabb2[1]; break; case TOPMIDDLE: out_vec2[0] = (aabb2[2] - aabb2[0]) * 0.5 + aabb2[0]; out_vec2[1] = aabb2[1]; break; case TOPRIGHT: out_vec2[0] = aabb2[2]; out_vec2[1] = aabb2[1]; break; case CENTERLEFT: out_vec2[0] = aabb2[0]; out_vec2[1] = (aabb2[3] - aabb2[1]) * 0.5 + aabb2[1]; break; case CENTER: out_vec2[0] = (aabb2[2] - aabb2[0]) * 0.5 + aabb2[0]; out_vec2[1] = (aabb2[3] - aabb2[1]) * 0.5 + aabb2[1]; break; case CENTERRIGHT: out_vec2[0] = aabb2[2]; out_vec2[1] = (aabb2[3] - aabb2[1]) * 0.5 + aabb2[1]; break; case BOTTOMLEFT: out_vec2[0] = aabb2[0]; out_vec2[1] = aabb2[3]; break; case BOTTOM: out_vec2[0] = (aabb2[2] - aabb2[0]) * 0.5 + aabb2[0]; out_vec2[1] = aabb2[3]; break; case BOTTOMRIGHT: out_vec2[0] = aabb2[2]; out_vec2[1] = aabb2[3]; break; } return out_vec2; } /** * @param {AABB2} aabb2 * @param {Vec2} vec2 * @return {Boolean} */ function isVec2Inside(aabb2, vec2) { if (!Array.isArray(aabb2) || aabb2[0] == undefined || Number.isNaN(aabb2[0]) || 'number' !== typeof aabb2[0] || aabb2[1] == undefined || Number.isNaN(aabb2[1]) || 'number' !== typeof aabb2[1] || aabb2[2] == undefined || Number.isNaN(aabb2[2]) || 'number' !== typeof aabb2[2] || aabb2[3] == undefined || Number.isNaN(aabb2[3]) || 'number' !== typeof aabb2[3]) { throw new Error("invalid AABB2 aabb2") } if (!Array.isArray(vec2) || vec2[0] == undefined || Number.isNaN(vec2[0]) || 'number' !== typeof vec2[0] || vec2[1] == undefined || Number.isNaN(vec2[1]) || 'number' !== typeof vec2[1]) { throw new Error("invalid Vec2 vec2") } return aabb2[0] < vec2[0] && aabb2[2] > vec2[0] && aabb2[1] < vec2[1] && aabb2[3] > vec2[1]; } /** * @param {AABB2} aabb2 * @param {AABB2} aabb2_2 * @return {Boolean} */ function isAABB2Inside(aabb2, aabb2_2) { if (!Array.isArray(aabb2) || aabb2[0] == undefined || Number.isNaN(aabb2[0]) || 'number' !== typeof aabb2[0] || aabb2[1] == undefined || Number.isNaN(aabb2[1]) || 'number' !== typeof aabb2[1] || aabb2[2] == undefined || Number.isNaN(aabb2[2]) || 'number' !== typeof aabb2[2] || aabb2[3] == undefined || Number.isNaN(aabb2[3]) || 'number' !== typeof aabb2[3]) { throw new Error("invalid AABB2 aabb2") } if (!Array.isArray(aabb2_2) || aabb2_2[0] == undefined || Number.isNaN(aabb2_2[0]) || 'number' !== typeof aabb2_2[0] || aabb2_2[1] == undefined || Number.isNaN(aabb2_2[1]) || 'number' !== typeof aabb2_2[1] || aabb2_2[2] == undefined || Number.isNaN(aabb2_2[2]) || 'number' !== typeof aabb2_2[2] || aabb2_2[3] == undefined || Number.isNaN(aabb2_2[3]) || 'number' !== typeof aabb2_2[3]) { throw new Error("invalid AABB2 aabb2_2") } return aabb2[0] <= aabb2_2[0] && aabb2[1] <= aabb2_2[1] && aabb2_2[2] <= aabb2[2] && aabb2_2[3] <= aabb2[3]; } /** * @param {AABB2} aabb2 * @return {Number} */ function perimeter(aabb2) { if (!Array.isArray(aabb2) || aabb2[0] == undefined || Number.isNaN(aabb2[0]) || 'number' !== typeof aabb2[0] || aabb2[1] == undefined || Number.isNaN(aabb2[1]) || 'number' !== typeof aabb2[1] || aabb2[2] == undefined || Number.isNaN(aabb2[2]) || 'number' !== typeof aabb2[2] || aabb2[3] == undefined || Number.isNaN(aabb2[3]) || 'number' !== typeof aabb2[3]) { throw new Error("invalid AABB2 aabb2") } return (aabb2[2] - aabb2[0]) * 2 + (aabb2[3] - aabb2[1]) * 2; } /** * @class AABB2 */ var AABB2 = { // defines TOPLEFT: TOPLEFT, TOPMIDDLE: TOPMIDDLE, TOPRIGHT: TOPRIGHT, CENTERLEFT: CENTERLEFT, CENTER: CENTER, CENTERRIGHT: CENTERRIGHT, BOTTOMLEFT: BOTTOMLEFT, BOTTOM: BOTTOM, BOTTOMRIGHT: BOTTOMRIGHT, create: create, fromAABB2Division: fromAABB2Division, fromSegment2: fromSegment2, fromCircle: fromCircle, fromRectangle: fromRectangle, zero: zero, clone: clone, copy: copy, expand: expand, merge: merge, offsetMerge: offsetMerge, osMerge: osMerge, area: area, normalize: normalize, translate: translate, clampVec: clampVec, center: center, align: align, isVec2Inside: isVec2Inside, isAABB2Inside: isAABB2Inside, perimeter: perimeter, // alias contains: isAABB2Inside }; module.exports = AABB2; },{}],4:[function(require,module,exports){ /** * Stability: 1 (Only additions & fixes) * * @reference http://pomax.github.io/bezierinfo/ * @reference https://github.com/jackcviers/Degrafa/blob/master/Degrafa/com/degrafa/geometry/utilities/BezierUtils.as * @reference http://cagd.cs.byu.edu/~557/text/ch7.pdf * @reference http://algorithmist.wordpress.com/2009/02/02/degrafa-closest-point-on-quad-bezier/ * @reference http://algorithmist.wordpress.com/2009/01/26/degrafa-bezierutils-class/ */ var sqrt = Math.sqrt, cl0 = 0, cl1 = 0, cl2 = 0, cl3 = 0, t1 = 0, t2 = 0, t3 = 0; /** * cp0 - start point * cp1 - start control point * cp2 - end control point * cp3 - end point * * @param {Number} cp0x * @param {Number} cp0y * @param {Number} cp1x * @param {Number} cp1y * @param {Number} cp2x * @param {Number} cp2y * @param {Number} cp3x * @param {Number} cp3y * @return {Beizer} */ function cubic(cp0x, cp0y, cp1x, cp1y, cp2x, cp2y, cp3x, cp3y) { if (cp0x == undefined || Number.isNaN(cp0x) || 'number' !== typeof cp0x) { throw new Error("cp0x is undefined or null") } if (cp0y == undefined || Number.isNaN(cp0y) || 'number' !== typeof cp0y) { throw new Error("cp0y is undefined or null") } if (cp1x == undefined || Number.isNaN(cp1x) || 'number' !== typeof cp1x) { throw new Error("cp1x is undefined or null") } if (cp1y == undefined || Number.isNaN(cp1y) || 'number' !== typeof cp1y) { throw new Error("cp1y is undefined or null") } if (cp2x == undefined || Number.isNaN(cp2x) || 'number' !== typeof cp2x) { throw new Error("cp2x is undefined or null") } if (cp2y == undefined || Number.isNaN(cp2y) || 'number' !== typeof cp2y) { throw new Error("cp2y is undefined or null") } if (cp3x == undefined || Number.isNaN(cp3x) || 'number' !== typeof cp3x) { throw new Error("cp3x is undefined or null") } if (cp3y == undefined || Number.isNaN(cp3y) || 'number' !== typeof cp3y) { throw new Error("cp3y is undefined or null") } return [[cp0x, cp0y], [cp1x, cp1y], [cp2x, cp2y], [cp3x, cp3y]]; } /** * For implementation see Figure 21.2 * @reference http://pomax.github.io/bezierinfo/ * @todo DO IT! * * @param {Number} cp0x * @param {Number} cp0y * @param {Number} cp1x * @param {Number} cp1y * @param {Number} cp2x * @param {Number} cp2y * @return {Beizer} */ function from3Points(cp0x, cp0y, cp1x, cp1y, cp2x, cp2y) { if (cp0x == undefined || Number.isNaN(cp0x) || 'number' !== typeof cp0x) { throw new Error("cp0x is undefined or null") } if (cp0y == undefined || Number.isNaN(cp0y) || 'number' !== typeof cp0y) { throw new Error("cp0y is undefined or null") } if (cp1x == undefined || Number.isNaN(cp1x) || 'number' !== typeof cp1x) { throw new Error("cp1x is undefined or null") } if (cp1y == undefined || Number.isNaN(cp1y) || 'number' !== typeof cp1y) { throw new Error("cp1y is undefined or null") } if (cp2x == undefined || Number.isNaN(cp2x) || 'number' !== typeof cp2x) { throw new Error("cp2x is undefined or null") } if (cp2y == undefined || Number.isNaN(cp2y) || 'number' !== typeof cp2y) { throw new Error("cp2y is undefined or null") } } /** * @param {Number} cp0x * @param {Number} cp0y * @param {Number} cp1x * @param {Number} cp1y * @param {Number} cp2x * @param {Number} cp2y * @return {Beizer} */ function quadric(cp0x, cp0y, cp1x, cp1y, cp2x, cp2y) { if (cp0x == undefined || Number.isNaN(cp0x) || 'number' !== typeof cp0x) { throw new Error("cp0x is undefined or null") } if (cp0y == undefined || Number.isNaN(cp0y) || 'number' !== typeof cp0y) { throw new Error("cp0y is undefined or null") } if (cp1x == undefined || Number.isNaN(cp1x) || 'number' !== typeof cp1x) { throw new Error("cp1x is undefined or null") } if (cp1y == undefined || Number.isNaN(cp1y) || 'number' !== typeof cp1y) { throw new Error("cp1y is undefined or null") } if (cp2x == undefined || Number.isNaN(cp2x) || 'number' !== typeof cp2x) { throw new Error("cp2x is undefined or null") } if (cp2y == undefined || Number.isNaN(cp2y) || 'number' !== typeof cp2y) { throw new Error("cp2y is undefined or null") } return [[cp0x, cp0y], [cp1x, cp1y], [cp2x, cp2y]]; } /** * For implementation see Figure 21.1 * @reference http://pomax.github.io/bezierinfo/ * @param {Number} cp0x * @param {Number} cp0y * @param {Number} cp1x * @param {Number} cp1y * @param {Number} cp2x * @param {Number} cp2y */ function quadricFrom3Points(cp0x, cp0y, cp1x, cp1y, cp2x, cp2y) { if (cp0x == undefined || Number.isNaN(cp0x) || 'number' !== typeof cp0x) { throw new Error("cp0x is undefined or null") } if (cp0y == undefined || Number.isNaN(cp0y) || 'number' !== typeof cp0y) { throw new Error("cp0y is undefined or null") } if (cp1x == undefined || Number.isNaN(cp1x) || 'number' !== typeof cp1x) { throw new Error("cp1x is undefined or null") } if (cp1y == undefined || Number.isNaN(cp1y) || 'number' !== typeof cp1y) { throw new Error("cp1y is undefined or null") } if (cp2x == undefined || Number.isNaN(cp2x) || 'number' !== typeof cp2x) { throw new Error("cp2x is undefined or null") } if (cp2y == undefined || Number.isNaN(cp2y) || 'number' !== typeof cp2y) { throw new Error("cp2y is undefined or null") } } /** * Solves the curve (quadric or cubic) for any given parameter t. * @source https://github.com/hyperandroid/CAAT/blob/master/src/Math/Bezier.js * @param {Vec2} out_vec2 * @param {Beizer} curve * @param {Number} t [0-1] * @return {Vec2} */ function solve(out_vec2, curve, t) { if (!Array.isArray(out_vec2) || out_vec2[0] == undefined || Number.isNaN(out_vec2[0]) || 'number' !== typeof out_vec2[0] || out_vec2[1] == undefined || Number.isNaN(out_vec2[1]) || 'number' !== typeof out_vec2[1]) { throw new Error("invalid Vec2 out_vec2") } if (t == undefined || Number.isNaN(t) || 'number' !== typeof t) { throw new Error("t is undefined or null") } if (curve.length === 4) { //cubic t2 = t * t; t3 = t * t2; cl0 = curve[0]; cl1 = curve[1]; cl2 = curve[2]; cl3 = curve[3]; out_vec2[0] = (cl0[0] + t * (-cl0[0] * 3 + t * (3 * cl0[0] - cl0[0] * t))) + t * (3 * cl1[0] + t * (-6 * cl1[0] + cl1[0] * 3 * t)) + t2 * (cl2[0] * 3 - cl2[0] * 3 * t) + cl3[0] * t3; out_vec2[1] = (cl0[1] + t * (-cl0[1] * 3 + t * (3 * cl0[1] - cl0[1] * t))) + t * (3 * cl1[1] + t * (-6 * cl1[1] + cl1[1] * 3 * t)) + t2 * (cl2[1] * 3 - cl2[1] * 3 * t) + cl3[1] * t3; } else { // quadric cl0 = curve[0]; cl1 = curve[1]; cl2 = curve[2]; t1 = 1 - t; out_vec2[0] = t1 * t1 * cl0[0] + 2 * t1 * t * cl1[0] + t * t * cl2[0]; out_vec2[1] = t1 * t1 * cl0[1] + 2 * t1 * t * cl1[1] + t * t * cl2[1]; } return out_vec2; } /** * Solve the curve npoints times and return the solution array. * * @see Polygon.fromBeizer * * @param {Beizer} curve * @param {Number} npoints * @return {Vec2[]} */ function getPoints(curve, npoints) { if (npoints == undefined || Number.isNaN(npoints) || 'number' !== typeof npoints) { throw new Error("npoints is undefined or null") } var inv_npoints = 1 / npoints, i, output = [], vec2; for (i = 0; i <= 1; i += inv_npoints) { vec2 = [0, 0]; output.push(solve(vec2, curve, i)); } return output; } /** * Calculate the curve length by incrementally solving the curve every substep=CAAT.Curve.k. This value defaults * to .05 so at least 20 iterations will be performed. * @todo some kind of cache maybe it's needed! * @param {Beizer} curve * @param {Number} step * @return {Number} the approximate curve length. */ function length(curve, step) { if (step == undefined || Number.isNaN(step) || 'number' !== typeof step) { throw new Error("step is undefined or null") } step = step || 0.05; var x1, y1, llength = 0, pt = [0, 0], t; x1 = curve[0][0]; y1 = curve[0][1]; for (t = step; t <= 1 + step; t += step) { solve(pt, curve, t); llength += sqrt((pt[0] - x1) * (pt[0] - x1) + (pt[1] - y1) * (pt[1] - y1)); x1 = pt[0]; y1 = pt[1]; } return llength; } /** * credits - CAAT * * @class Beizer */ var Beizer = { cubic: cubic, quadric: quadric, solve: solve, length: length, getPoints: getPoints }; module.exports = Beizer; },{}],5:[function(require,module,exports){ /** * 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) { if (x == undefined || Number.isNaN(x) || 'number' !== typeof x) { throw new Error("x is undefined or null") } if (y == undefined || Number.isNaN(y) || 'number' !== typeof y) { throw new Error("y is undefined or null") } if (radius == undefined || Number.isNaN(radius) || 'number' !== typeof radius) { throw new Error("radius is undefined or null") } return [[x, y], radius]; } /** * @param {Vec2} vec2 * @param {Number} radius * @return {Circle} */ function fromVec2(vec2, radius) { if (!Array.isArray(vec2) || vec2[0] == undefined || Number.isNaN(vec2[0]) || 'number' !== typeof vec2[0] || vec2[1] == undefined || Number.isNaN(vec2[1]) || 'number' !== typeof vec2[1]) { throw new Error("invalid Vec2 vec2") } if (radius == undefined || Number.isNaN(radius) || 'number' !== typeof radius) { throw new Error("radius is undefined or null") } 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) { if (!Array.isArray(rect) || rect[0][0] == undefined || Number.isNaN(rect[0][0]) || 'number' !== typeof rect[0][0] || rect[0][1] == undefined || Number.isNaN(rect[0][1]) || 'number' !== typeof rect[0][1] || rect[1][0] == undefined || Number.isNaN(rect[1][0]) || 'number' !== typeof rect[1][0] || rect[1][1] == undefined || Number.isNaN(rect[1][1]) || 'number' !== typeof rect[1][1]) { throw new Error("invalid Rectangle rect") } if (inside !== undefined) { if ('boolean' !== typeof inside) { throw new Error("inside is not a boolean") } } 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) { if (!Array.isArray(tri) || tri[0][0] == undefined || Number.isNaN(tri[0][0]) || 'number' !== typeof tri[0][0] || tri[0][1] == undefined || Number.isNaN(tri[0][1]) || 'number' !== typeof tri[0][1] || tri[1][0] == undefined || Number.isNaN(tri[1][0]) || 'number' !== typeof tri[1][0] || tri[1][1] == undefined || Number.isNaN(tri[1][1]) || 'number' !== typeof tri[1][1] || tri[2][0] == undefined || Number.isNaN(tri[2][0]) || 'number' !== typeof tri[2][0] || tri[2][1] == undefined || Number.isNaN(tri[2][1]) || 'number' !== typeof tri[2][1]) { throw new Error("invalid Traingle tri") } if (inside !== undefined) { if ('boolean' !== typeof inside) { throw new Error("inside is not a boolean") } } if (circumcenter !== undefined) { if ('boolean' !== typeof circumcenter) { throw new Error("circumcenter is not a boolean") } } 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) { if (!Array.isArray(vec2) || vec2[0] == undefined || Number.isNaN(vec2[0]) || 'number' !== typeof vec2[0] || vec2[1] == undefined || Number.isNaN(vec2[1]) || 'number' !== typeof vec2[1]) { throw new Error("invalid Vec2 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) { if (!Array.isArray(vec2) || vec2[0] == undefined || Number.isNaN(vec2[0]) || 'number' !== typeof vec2[0] || vec2[1] == undefined || Number.isNaN(vec2[1]) || 'number' !== typeof vec2[1]) { throw new Error("invalid Vec2 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) { if (!Array.isArray(vec2) || vec2[0] == undefined || Number.isNaN(vec2[0]) || 'number' !== typeof vec2[0] || vec2[1] == undefined || Number.isNaN(vec2[1]) || 'number' !== typeof vec2[1]) { throw new Error("invalid Vec2 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) { if (!Array.isArray(out_vec2) || out_vec2[0] == undefined || Number.isNaN(out_vec2[0]) || 'number' !== typeof out_vec2[0] || out_vec2[1] == undefined || Number.isNaN(out_vec2[1]) || 'number' !== typeof out_vec2[1]) { throw new Error("invalid Vec2 out_vec2") } if (!Array.isArray(vec2) || vec2[0] == undefined || Number.isNaN(vec2[0]) || 'number' !== typeof vec2[0] || vec2[1] == undefined || Number.isNaN(vec2[1]) || 'number' !== typeof vec2[1]) { throw new Error("invalid Vec2 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) { if (mass == undefined || Number.isNaN(mass) || 'number' !== typeof mass) { throw new Error("mass is undefined or null") } 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; },{"./rectangle.js":26,"./triangle.js":29,"./vec2.js":30}],6:[function(require,module,exports){ /** * Stability: 0 (Anything could happen) * * This need revision. * **inside:Boolean** param must be added to all functions * *Note** this not return the contact points, use intersections for that. * * @source http://members.gamedev.net/oliii/satpost/SpherePolygonCollision.cpp */ var Vec2 = require("./vec2.js"), vec2_distance = Vec2.distance, vec2_distance_sq = Vec2.distanceSq, vec2_midpoint = Vec2.midPoint, vec2_$near = Vec2.$near, vec2_sub = Vec2.sub, vec2_dot = Vec2.dot, Segment2 = require("./segment2.js"), Segment2_$closestPoint = Segment2.$closestPoint, aux_vec2 = [0, 0], ca = [0, 0], ba = [0, 0], pa = [0, 0], EPS = Math.EPS = 0.001; /** * @param {Number} num * @param {Number} num2 * @param {Number} dist */ function _near(num, num2, dist) { if (num == undefined || Number.isNaN(num) || 'number' !== typeof num) { throw new Error("num is undefined or null") } if (num2 == undefined || Number.isNaN(num2) || 'number' !== typeof num2) { throw new Error("num2 is undefined or null") } if (dist == undefined || Number.isNaN(dist) || 'number' !== typeof dist) { throw new Error("dist is undefined or null") } return num > num2 - dist && num < num2 + dist; } /** * @param {Number} x1 * @param {Number} y1 * @param {Number} x2 * @param {Number} y2 * @param {Number} x3 * @param {Number} y3 */ function _rectangle_vec2(x1, y1, x2, y2, x3, y3) { if (x1 == undefined || Number.isNaN(x1) || 'number' !== typeof x1) { throw new Error("x1 is undefined or null") } if (y1 == undefined || Number.isNaN(y1) || 'number' !== typeof y1) { throw new Error("y1 is undefined or null") } if (x2 == undefined || Number.isNaN(x2) || 'number' !== typeof x2) { throw new Error("x2 is undefined or null") } if (y2 == undefined || Number.isNaN(y2) || 'number' !== typeof y2) { throw new Error("y2 is undefined or null") } if (x3 == undefined || Number.isNaN(x3) || 'number' !== typeof x3) { throw new Error("x3 is undefined or null") } if (y3 == undefined || Number.isNaN(y3) || 'number' !== typeof y3) { throw new Error("y3 is undefined or null") } return (x1 > x3 || x2 < x3 || y1 > y3 || y2 < y3) ? false : true; } /** * @param {AABB2} bb2 * @param {Vec2} vec2 * @return {Boolean} */ function bb2_vec2(bb2, vec2) { if (!Array.isArray(bb2) || bb2[0] == undefined || Number.isNaN(bb2[0]) || 'number' !== typeof bb2[0] || bb2[1] == undefined || Number.isNaN(bb2[1]) || 'number' !== typeof bb2[1] || bb2[2] == undefined || Number.isNaN(bb2[2]) || 'number' !== typeof bb2[2] || bb2[3] == undefined || Number.isNaN(bb2[3]) || 'number' !== typeof bb2[3]) { throw new Error("invalid AABB2 bb2") } if (!Array.isArray(vec2) || vec2[0] == undefined || Number.isNaN(vec2[0]) || 'number' !== typeof vec2[0] || vec2[1] == undefined || Number.isNaN(vec2[1]) || 'number' !== typeof vec2[1]) { throw new Error("invalid Vec2 vec2") } return _rectangle_vec2(bb2[0], bb2[1], bb2[2], bb2[3], vec2[0], vec2[1]); } /** * @param {Vec2} vec2 * @param {AABB2} bb2 * @return {Boolean} */ function vec2_bb2(vec2, bb2) { if (!Array.isArray(vec2) || vec2[0] == undefined || Number.isNaN(vec2[0]) || 'number' !== typeof vec2[0] || vec2[1] == undefined || Number.isNaN(vec2[1]) || 'number' !== typeof vec2[1]) { throw new Error("invalid Vec2 vec2") } if (!Array.isArray(bb2) || bb2[0] == undefined || Number.isNaN(bb2[0]) || 'number' !== typeof bb2[0] || bb2[1] == undefined || Number.isNaN(bb2[1]) || 'number' !== typeof bb2[1] || bb2[2] == undefined || Number.isNaN(bb2[2]) || 'number' !== typeof bb2[2] || bb2[3] == undefined || Number.isNaN(bb2[3]) || 'number' !== typeof bb2[3]) { throw new Error("invalid AABB2 bb2") } return _rectangle_vec2(bb2[0], bb2[1], bb2[2], bb2[3], vec2[0], vec2[1]); } /** * @param {Rectangle} rect * @param {Vec2} vec2 * @return {Boolean} */ function rectangle_vec2(rect, vec2) { if (!Array.isArray(rect) || rect[0][0] == undefined || Number.isNaN(rect[0][0]) || 'number' !== typeof rect[0][0] || rect[0][1] == undefined || Number.isNaN(rect[0][1]) || 'number' !== typeof rect[0][1] || rect[1][0] == undefined || Number.isNaN(rect[1][0]) || 'number' !== typeof rect[1][0] || rect[1][1] == undefined || Number.isNaN(rect[1][1]) || 'number' !== typeof rect[1][1]) { throw new Error("invalid Rectangle rect") } if (!Array.isArray(vec2) || vec2[0] == undefined || Number.isNaN(vec2[0]) || 'number' !== typeof vec2[0] || vec2[1] == undefined || Number.isNaN(vec2[1]) || 'number' !== typeof vec2[1]) { throw new Error("invalid Vec2 vec2") } var tl = rect[0], br = rect[1]; return _rectangle_vec2(tl[0], tl[1], br[0], br[1], vec2[0], vec2[1]); } /** * @param {Vec2} vec2 * @param {Rectangle} rect * @return {Boolean} */ function vec2_rectangle(vec2, rect) { if (!Array.isArray(vec2) || vec2[0] == undefined || Number.isNaN(vec2[0]) || 'number' !== typeof vec2[0] || vec2[1] == undefined || Number.isNaN(vec2[1]) || 'number' !== typeof vec2[1]) { throw new