UNPKG

quadtree2

Version:

JavaScript implementation of quadtree datastructure for collision detection.

494 lines 23.2 kB
/** * @license * quadtree2 - v0.6.0 * Copyright (c) 2013-2014 p1100i * https://github.com/p1100i/quadtree2.js * * Compiled: 2015-08-31 * * quadtree2 is licensed under the MIT License. * http://www.opensource.org/licenses/mit-license.php */ !function a(b, c, d) { function e(g, h) { if (!c[g]) { if (!b[g]) { var i = "function" == typeof require && require; if (!h && i) return i(g, !0); if (f) return f(g, !0); var j = new Error("Cannot find module '" + g + "'"); throw j.code = "MODULE_NOT_FOUND", j; } var k = c[g] = { exports: {} }; b[g][0].call(k.exports, function(a) { var c = b[g][1][a]; return e(c ? c : a); }, k, k.exports, a, b, c, d); } return c[g].exports; } for (var f = "function" == typeof require && require, g = 0; g < d.length; g++) e(d[g]); return e; }({ 1: [ function(a, b, c) { Quadtree2 = a("./src/quadtree2"); }, { "./src/quadtree2": 3 } ], 2: [ function(a, b, c) { !function d(a, c, e) { function f(a, b) { return this instanceof f ? (g(a) ? (b = a[1], a = a[0]) : "object" == typeof a && a && (b = a.y, a = a.x), this.x = f.clean(a || 0), void (this.y = f.clean(b || 0))) : new f(a, b); } var g = function(a) { return "[object Array]" === Object.prototype.toString.call(a); }; f.prototype = { change: function(a) { if (a) this.observers ? this.observers.push(a) : this.observers = [ a ]; else if (this.observers) for (var b = this.observers.length - 1; b >= 0; b--) this.observers[b](this); return this; }, ignore: function(a) { if (this.observers) for (var b = this.observers, c = b.length; c--; ) b[c] === a && b.splice(c, 1); return this; }, set: function(a, b, c) { return "number" != typeof a && (c = b, b = a.y, a = a.x), this.x === a && this.y === b ? this : (this.x = f.clean(a), this.y = f.clean(b), c !== !1 ? this.change() : void 0); }, zero: function() { return this.set(0, 0); }, clone: function() { return new this.constructor(this.x, this.y); }, negate: function(a) { return a ? new this.constructor(-this.x, -this.y) : this.set(-this.x, -this.y); }, add: function(a, b) { return b ? new this.constructor(this.x + a.x, this.y + a.y) : (this.x += a.x, this.y += a.y, this.change()); }, subtract: function(a, b) { return b ? new this.constructor(this.x - a.x, this.y - a.y) : (this.x -= a.x, this.y -= a.y, this.change()); }, multiply: function(a, b) { var c, d; return "number" != typeof a ? (c = a.x, d = a.y) : c = d = a, b ? new this.constructor(this.x * c, this.y * d) : this.set(this.x * c, this.y * d); }, rotate: function(a, b, c) { var d, e, f = this.x, g = this.y, h = Math.cos(a), i = Math.sin(a); return b = b ? -1 : 1, d = h * f - b * i * g, e = b * i * f + h * g, c ? new this.constructor(d, e) : this.set(d, e); }, length: function() { var a = this.x, b = this.y; return Math.sqrt(a * a + b * b); }, lengthSquared: function() { var a = this.x, b = this.y; return a * a + b * b; }, distance: function(a) { var b = this.x - a.x, c = this.y - a.y; return Math.sqrt(b * b + c * c); }, normalize: function(a) { var b = this.length(), c = b < Number.MIN_VALUE ? 0 : 1 / b; return a ? new this.constructor(this.x * c, this.y * c) : this.set(this.x * c, this.y * c); }, equal: function(a, b) { return b === e && (b = a.y, a = a.x), f.clean(a) === this.x && f.clean(b) === this.y; }, abs: function(a) { var b = Math.abs(this.x), c = Math.abs(this.y); return a ? new this.constructor(b, c) : this.set(b, c); }, min: function(a, b) { var c = this.x, d = this.y, e = a.x, f = a.y, g = e > c ? c : e, h = f > d ? d : f; return b ? new this.constructor(g, h) : this.set(g, h); }, max: function(a, b) { var c = this.x, d = this.y, e = a.x, f = a.y, g = c > e ? c : e, h = d > f ? d : f; return b ? new this.constructor(g, h) : this.set(g, h); }, clamp: function(a, b, c) { var d = this.min(b, !0).max(a); return c ? d : this.set(d.x, d.y); }, lerp: function(a, b) { return this.add(a.subtract(this, !0).multiply(b), !0); }, skew: function() { return new this.constructor(-this.y, this.x); }, dot: function(a) { return f.clean(this.x * a.x + a.y * this.y); }, perpDot: function(a) { return f.clean(this.x * a.y - this.y * a.x); }, angleTo: function(a) { return Math.atan2(this.perpDot(a), this.dot(a)); }, divide: function(a, b) { var c, d; if ("number" != typeof a ? (c = a.x, d = a.y) : c = d = a, 0 === c || 0 === d) throw new Error("division by zero"); if (isNaN(c) || isNaN(d)) throw new Error("NaN detected"); return b ? new this.constructor(this.x / c, this.y / d) : this.set(this.x / c, this.y / d); }, isPointOnLine: function(a, b) { return (a.y - this.y) * (a.x - b.x) === (a.y - b.y) * (a.x - this.x); }, toArray: function() { return [ this.x, this.y ]; }, fromArray: function(a) { return this.set(a[0], a[1]); }, toJSON: function() { return { x: this.x, y: this.y }; }, toString: function() { return "(" + this.x + ", " + this.y + ")"; }, constructor: f }, f.fromArray = function(a, b) { return new (b || f)(a[0], a[1]); }, f.precision = c || 8; var h = Math.pow(10, f.precision); return f.clean = a || function(a) { if (isNaN(a)) throw new Error("NaN detected"); if (!isFinite(a)) throw new Error("Infinity detected"); return Math.round(a) === a ? a : Math.round(a * h) / h; }, f.inject = d, a || (f.fast = d(function(a) { return a; }), "undefined" != typeof b && "object" == typeof b.exports ? b.exports = f : window.Vec2 = window.Vec2 || f), f; }(); }, {} ], 3: [ function(a, b, c) { var d, e = a("vec2"), f = a("./quadtree2helper"), g = a("./quadtree2inspector"), h = a("./quadtree2validator"), i = a("./quadtree2quadrant"); d = function(a) { var b, c, d, j, k, l, m = this, n = "id", o = "pos", p = "rad", q = 1, r = 1, s = new h(), t = {}, u = {}, v = function() { var a = r; return r += 4, a; }, w = function R(a, b, c) { if (b.intersects(a[o], a[p])) { var d, e = b.getChildren(), f = e && e.length; if (f) for (d = 0; f > d; d++) R(a, e[d], c); else c[b.id_] = b; return c; } }, x = function(a, b) { b.removeObject(a[n]), delete u[a[n]][b.id_], b.parent_ && !b.hasChildren() && I(b.parent_); }, y = function(a, b) { var c; void 0 === b && (b = u[a[n]]); for (c in b) x(a, b[c]); }, z = function(a, b) { var c = a[n]; void 0 === u[c] && (u[c] = {}), u[c][b.id_] = b, b.addObject(c, a); }, A = function(a) { var b, c, d = a.removeObjects([], 1); for (b = 0; b < d.length; b++) c = d[b], delete u[c.object[n]][c.quadrant.id_]; return d; }, B = function S(a, b) { var d, e, f, g, h; if (b || (b = c), b.hasChildren()) { f = w(a, b, {}); for (e in f) S(a, f[e]); } else if (b.size_.x <= a[p] || b.getObjectCount() < k || b.size_.x < l.x) z(a, b); else for (b.makeChildren(v()), g = A(b), g.push({ object: a, quadrant: b }), d = 0; d < g.length; d++) h = g[d], S(h.object, h.quadrant); }, C = function(a) { var b = a[n]; if (q && !b && (b = a[n] = q++), t[b]) throw new Error("usedId"); return t[b] = a, B(a), a; }, D = function(a) { return a.forEach(C); }, E = function(a) { var b = a[n]; y(a), delete t[b]; }, F = function(a) { var b = t[a]; return E(b); }, G = function(a) { return a.forEach(E); }, H = function(a) { var b, c, d, e, f, g = u[a[n]], h = { objects: {}, quadrants: {} }; for (c in g) for (d = g[c], d.getObjectsUp(h), e = d.children_, f = e.length, b = 0; f > b; b++) e[b].getObjectsDown(h); return delete h.objects[a[n]], h.objects; }, I = function T(a) { var b, c, d, e, f; if (!a.refactoring_) { for (b = 0; b < a.children_.length; b++) if (e = a.children_[b], e.hasChildren()) return; if (d = a.getObjectCountForLimit(), !(d > k)) { for (a.refactoring_ = !0, b = 0; b < a.children_.length; b++) { e = a.children_[b]; for (c in e.objects_) f = e.objects_[c], x(f, e), z(f, a); } a.looseChildren(), a.refactoring_ = !1, a.parent_ && T(a.parent_); } } }, J = function(a) { var b, c, d = H(a); for (b in d) c = d[b], c[o].distance(a[o]) > c[p] + a[p] && delete d[b]; return d; }, K = function(a) { var b, d = u[a[n]], e = w(a, c, {}), g = f.getIdsOfObjects(d), h = f.getIdsOfObjects(e), i = f.arrayDiffs(g, h), j = i[0], k = i[1]; for (b = 0; b < k.length; b++) B(a, e[k[b]]); for (b = 0; b < j.length; b++) d[j[b]] && x(a, d[j[b]]); }, L = function(a) { return K(a); }, M = function(a) { var b = t[a]; return L(b); }, N = function(a) { return a.forEach(L); }, O = function() { var b = { root: c, idKey: n, config: a, objects: t, objectQuadrants: u }; return d || (b.qt = m, d = new g(b), delete b.qt), d; }, P = function(a, b) { "id" === a ? (q = 0, n = b) : "pos" === a ? o = b : "rad" === a && (p = b); }, Q = function(a) { b = a.size, k = a.objectLimit || 4, j = a.levelLimit || 6, s.isVec2(b, "size"), s.isNumber(k, "objectLimit"), s.isNumber(j, "levelLimit"), c = new i(new e(0, 0), b.clone(), 1), l = b.clone().divide(Math.pow(2, j)); }; return Q(a), this.addObject = C, this.addObjects = D, this.getCollidables = H, this.getCollidings = J, this.updateObject = L, this.updateObjectById = M, this.updateObjects = N, this.removeObject = E, this.removeObjectById = F, this.removeObjects = G, this.setKey = P, this.inspect = O, this; }, b.exports = d; }, { "./quadtree2helper": 4, "./quadtree2inspector": 5, "./quadtree2quadrant": 6, "./quadtree2validator": 7, vec2: 2 } ], 4: [ function(a, b, c) { var d = { fnName: function(a) { var b = a.toString(); return b = b.substr("function ".length), b = b.substr(0, b.indexOf("(")); }, thrower: function(a, b, c) { var d = a; throw c && (d += "_" + c), b && (d += " - "), b && c && (d += c + ": "), b && (d += b), new Error(d); }, getIdsOfObjects: function(a) { var b = []; for (var c in a) b.push(a[c].id_); return b; }, compare: function(a, b) { return a - b; }, arrayDiffs: function(a, b) { var c = 0, d = 0, e = [], f = []; for (a.sort(this.compare), b.sort(this.compare); c < a.length && d < b.length; ) a[c] !== b[d] ? a[c] < b[d] ? (e.push(a[c]), c++) : (f.push(b[d]), d++) : (c++, d++); return c < a.length ? e.push.apply(e, a.slice(c, a.length)) : f.push.apply(f, b.slice(d, b.length)), [ e, f ]; } }; b.exports = d; }, {} ], 5: [ function(a, b, c) { var d; a("vec2"); d = function(a) { var b, c, d, e, f, g, h = "", i = function(a) { return a ? Object.keys(g[a[d]]).length : 1 + c.getChildCount(!0); }, j = function() { return Object.keys(f).length; }, k = function(a, b) { return b ? b * a : a; }, l = function(a, b) { return "new Vec2(" + k(a.x, b) + ", " + k(a.y, b) + ")"; }, m = function(a, b) { var c = "", d = l(a.pos, b); return c += "o = {\n pos : " + d + ",\n rad : " + k(a.rad, b) + " \n};\n\n", c += "qt.addObject(o);\n", c += "os[o.id] = o;\n\n"; }, n = function(a) { return "qt.removeObjectById(" + a.id + ");\n\n"; }, o = function(a, b) { var c = ""; return c += "o = os[" + a.id + "];\n", c += "o.pos.x = " + b.x + ";\n", c += "o.pos.y = " + b.y + ";\n\n"; }, p = function(a) { return "qt.updateObjectById(" + a.id + ");\n\n"; }, q = function(a) { var b = "os = {};\n\n", c = l(e.size, a); return b += "qt = new Quadtree2({\n size : " + c + ",\n objectLimit : " + e.objectLimit + ",\n levelLimit : " + e.levelLimit + " \n});\n\n"; }, r = function(a) { var b, c, d = q(a); for (b in f) c = f[b], d += m(c, a); return d; }, s = function(a) { h += a; }, t = function() { return q() + h; }, u = function(a, c) { var d = b[a]; b[a] = function(a) { s(c(a)), d(a); }; }, v = function(a) { b = a.qt, c = a.root, d = a.idKey, e = a.config, f = a.objects, g = a.objectQuadrants, u("addObject", m), u("removeObject", n), u("updateObject", p); }; v(a), this.data = a, this.addLog = s, this.getLog = t, this.getObjectCount = j, this.getQuadrantCount = i, this.getRebuildingCommand = r, this.stringifyVec2ConstructorCall = l, this.stringifyAddObjectCall = m, this.stringifyMoveObjectCall = o, this.stringifyUpdateObjectCall = p, this.stringifyConstructorCall = q; }, b.exports = d; }, { vec2: 2 } ], 6: [ function(a, b, c) { var d = function(a, b, c, d) { this.leftTop_ = a.clone(), this.children_ = [], this.objects_ = {}, this.objectCount_ = 0, this.id_ = c || 0, this.parent_ = d, this.refactoring_ = !1, this.setSize(b); }; d.prototype = { setSize: function(a) { a && (this.size_ = a, this.rad_ = a.multiply(.5, !0), this.center_ = this.leftTop_.add(this.rad_, !0), this.leftBot_ = this.leftTop_.clone(), this.leftBot_.y += a.y, this.rightTop_ = this.leftTop_.clone(), this.rightTop_.x += a.x, this.rightBot_ = this.leftTop_.add(a, !0), this.leftMid_ = this.center_.clone(), this.leftMid_.x = this.leftTop_.x, this.topMid_ = this.center_.clone(), this.topMid_.y = this.leftTop_.y); }, makeChildren: function(a) { return this.children_.length > 0 ? !1 : (this.children_.push(new d(this.leftTop_, this.rad_, ++a, this), new d(this.topMid_, this.rad_, ++a, this), new d(this.leftMid_, this.rad_, ++a, this), new d(this.center_, this.rad_, ++a, this)), a); }, looseChildren: function() { this.children_ = []; }, addObjects: function(a) { var b; for (b in a) this.addObject(b, a[b]); }, addObject: function(a, b) { this.objectCount_++, this.objects_[a] = b; }, removeObjects: function(a, b) { var c; a || (a = []); for (c in this.objects_) a.push({ object: this.objects_[c], quadrant: this }), delete this.objects_[c]; return this.objectCount_ = 0, b && 1 !== b || this.parent_ && this.parent_.removeObjects(a, 1), b && -1 !== b || this.children_.forEach(function(b) { b.removeObjects(a, -1); }), a; }, removeObject: function(a) { var b = this.objects_[a]; return this.objectCount_--, delete this.objects_[a], b; }, getObjectCountForLimit: function() { var a, b, c = {}; for (b in this.objects_) c[b] = !0; for (a = 0; a < this.children_.length; a++) for (b in this.children_[a].objects_) c[b] = !0; return Object.keys(c).length; }, getObjectCount: function(a, b) { var c = this.objectCount_; return a && this.children_.forEach(function(d) { c += d.getObjectCount(!b && a); }), c; }, intersectingChildren: function(a, b) { return this.children_.filter(function(c) { return c.intersects(a, b); }); }, intersects: function(a, b) { var c = a.subtract(this.center_, !0).abs(); return c.x > this.rad_.x + b ? !1 : c.y > this.rad_.y + b ? !1 : c.x <= this.rad_.x ? !0 : c.y <= this.rad_.y ? !0 : (cornerDistSq = Math.pow(c.x - this.rad_.x, 2) + Math.pow(c.y - this.rad_.y, 2), cornerDistSq <= Math.pow(b, 2)); }, hasChildren: function() { return 0 !== this.getChildCount(); }, getChildCount: function(a) { var b = this.children_.length; return a && this.children_.forEach(function(c) { b += c.getChildCount(a); }), b; }, getChildren: function(a, b) { return b || (b = []), b.push.apply(b, this.children_), a && this.children_.forEach(function(c) { c.getChildren(a, b); }), b; }, getObjectsUp: function(a) { var b; if (!a.quadrants[this.id_]) { a.quadrants[this.id_] = !0; for (b in this.objects_) a.objects[b] = this.objects_[b]; this.parent_ && this.parent_.getObjectsUp(a); } }, getObjectsDown: function(a) { var b; if (!a.quadrants[this.id_]) { a.quadrants[this.id_] = !0; for (b in this.objects_) a.objects[b] = this.objects_[b]; for (b = 0; b < this.children_.length; b++) this.children_[b].getObjectsDown(a); return a; } } }, b.exports = d; }, {} ], 7: [ function(a, b, c) { var d = (a("vec2"), a("./quadtree2helper")), e = function() {}; e.prototype = { isNumber: function(a, b) { "number" != typeof a && d.thrower("NaN", "Not a Number", b); }, isString: function(a, b) { "string" == typeof a || a instanceof String || d.thrower("NaS", "Not a String", b); }, isVec2: function(a, b) { var c = !1; c = "object" != typeof a || void 0 === a.x || void 0 === a.y, c && d.thrower("NaV", "Not a Vec2", b); }, isDefined: function(a, b) { void 0 === a && d.thrower("ND", "Not defined", b); }, isObject: function(a, b) { "object" != typeof a && d.thrower("NaO", "Not an Object", b); }, hasKey: function(a, b, c) { this.isDefined(a, "obj"), -1 === Object.keys(a).indexOf(b.toString()) && d.thrower("OhnK", "Object has no key", c + b); }, hasNoKey: function(a, b, c) { this.isDefined(a, "obj"), -1 !== Object.keys(a).indexOf(b.toString()) && d.thrower("OhK", "Object has key", c + b); }, fnFalse: function(a) { a() && d.thrower("FarT", "function already returns true", d.fnName(a)); }, byCallbackObject: function(a, b, c) { var d; for (d in b) void 0 !== c ? b[d](a[c[d]], c[d]) : b[d](a[d], d); } }, b.exports = e; }, { "./quadtree2helper": 4, vec2: 2 } ] }, {}, [ 1 ]);