{"ScriptPreparationCode":"/*\r\n HashBounds - A hierarchical spacial hashing system\r\n Copyright (C) 2016 Andrew S\r\n\r\n This program is free software: you can redistribute it and/or modify\r\n it under the terms of the GNU Affero General Public License as published\r\n by the Free Software Foundation, either version 3 of the License, or\r\n (at your option) any later version.\r\n\r\n This program is distributed in the hope that it will be useful,\r\n but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r\n GNU Affero General Public License for more details.\r\n\r\n You should have received a copy of the GNU Affero General Public License\r\n along with this program. If not, see \u003Chttp://www.gnu.org/licenses/\u003E.\r\n*/\r\nfunction Holder(parent, i) {\r\n this.parent = parent;\r\n if (this.parent) this.parent.children.push(this)\r\n this.map = new Map();\r\n this.len = 0;\r\n this.skip = 1;\r\n this.id = ~~(Math.random() * 100)\r\n this.children = []\r\n this.i = i;\r\n this.start = this.i;\r\n}\r\nHolder.prototype.set = function (id, node) {\r\n\r\n this.map.set(id, node)\r\n this.add()\r\n}\r\nHolder.prototype.add = function () {\r\n \u002B\u002Bthis.len;\r\n\r\n this.skip = 0;\r\n\r\n if (this.parent) {\r\n this.parent.add();\r\n\r\n\r\n }\r\n}\r\nHolder.prototype.toArray = function () {\r\n var nodes = [];\r\n this.map.forEach(function (n) {\r\n nodes.push(n)\r\n })\r\n return nodes\r\n}\r\nHolder.prototype.sub = function () {\r\n --this.len;\r\n if (!this.len) {\r\n this.skip = 1;\r\n this.start = this.i;\r\n }\r\n if (this.parent) {\r\n this.parent.sub();\r\n if (this.parent.skip) {\r\n this.skip = this.parent.skip \u003C\u003C 1;\r\n this.start = this.parent.start \u003C\u003C 1;\r\n }\r\n\r\n }\r\n}\r\nHolder.prototype.delete = function (id) {\r\n this.map.delete(id)\r\n this.sub()\r\n}\r\nHolder.prototype.every = function (c) {\r\n var a = this.map.entries()\r\n var b;\r\n while (b = a.next().value) {\r\n if (!c(b[1], b[0])) return false;\r\n }\r\n return true;\r\n}\r\nHolder.prototype.forEach = function (c) {\r\n return this.map.forEach(c);\r\n}\r\n\r\nfunction Grid(g, p, size, minc, prev) {\r\n this.POWER = g;\r\n this.LEVEL = p;\r\n this.PREV = prev;\r\n this.SIZE = size;\r\n this.MIN = minc * -1;\r\n this.DATA = {};\r\n this.LENGTH = 0;\r\n this.init()\r\n}\r\nGrid.prototype.init = function () {\r\n if (this.SIZE \u003E= 65535) {\r\n throw \u0022Maximum amount of buckets are 65535^2\u0022\r\n } // Max limit is 65535 (16 bits) \r\n // console.log(this.SIZE)\r\n for (var j = this.MIN; j \u003C= this.SIZE; \u002B\u002Bj) {\r\n var x = j \u003C\u003C 16\r\n var bx = (j \u003E\u003E 1) \u003C\u003C 16;\r\n for (var i = this.MIN; i \u003C= this.SIZE; \u002B\u002Bi) {\r\n\r\n var by = i \u003E\u003E 1\r\n var key = this._getKey(x, i);\r\n\r\n\r\n if (this.PREV) var l = this.PREV.DATA[this._getKey(bx, by)];\r\n else var l = false;\r\n this.DATA[key] = new Holder(l, i);\r\n\r\n }\r\n }\r\n}\r\n\r\nGrid.prototype.getKey = function (x, y) {\r\n return {\r\n x: x \u003E\u003E this.POWER,\r\n y: y \u003E\u003E this.POWER\r\n }\r\n}\r\nGrid.prototype._getKey = function (x, y) {\r\n return x | y\r\n\r\n}\r\nGrid.prototype._get = function (bounds, call) {\r\n var x1 = bounds.x,\r\n y1 = bounds.y,\r\n x2 = bounds.x \u002B bounds.width,\r\n y2 = bounds.y \u002B bounds.height;\r\n\r\n var k1 = this.getKey(x1, y1)\r\n var k2 = this.getKey(x2, y2)\r\n\r\n for (var j = k1.x; j \u003C= k2.x; \u002B\u002Bj) {\r\n\r\n var x = j \u003C\u003C 16;\r\n\r\n for (var i = k1.y; i \u003C= k2.y; \u002B\u002Bi) {\r\n\r\n\r\n var key = this._getKey(x, i);\r\n if (this.DATA[key]) {\r\n\r\n if (this.DATA[key].skip \u003E 1) {\r\n\r\n i = (this.DATA[key].start \u002B this.DATA[key].skip - 1);\r\n\r\n //console.log(this.DATA[key].start, this.DATA[key].skip)\r\n } else {\r\n\r\n if (!call(this.DATA[key])) return false\r\n }\r\n }\r\n\r\n }\r\n }\r\n return true;\r\n}\r\n\r\nGrid.prototype.insert = function (node) {\r\n\r\n // var a = this.getKey(node.bounds.width, node.bounds.height);\r\n // if (a.x \u002B a.y \u003E= 2 \u0026\u0026 this.LEVEL != 0) return false;\r\n this.LENGTH\u002B\u002B;\r\n var x1 = node.bounds.x,\r\n y1 = node.bounds.y,\r\n x2 = node.bounds.x \u002B node.bounds.width,\r\n y2 = node.bounds.y \u002B node.bounds.height;\r\n\r\n var k1 = this.getKey(x1, y1)\r\n var k2 = this.getKey(x2, y2)\r\n node.hash.k1 = k1\r\n node.hash.k2 = k2\r\n node.hash.level = this.LEVEL\r\n var lenX = k2.x \u002B 1,\r\n lenY = k2.y \u002B 1;\r\n for (var j = k1.x; j \u003C lenX; \u002B\u002Bj) {\r\n var x = j \u003C\u003C 16;\r\n for (var i = k1.y; i \u003C lenY; \u002B\u002Bi) {\r\n\r\n var ke = this._getKey(x, i);\r\n // console.log(ke)\r\n this.DATA[ke].set(node._HashID, node)\r\n }\r\n\r\n }\r\n return true;\r\n}\r\nGrid.prototype.delete = function (node) {\r\n var k1 = node.hash.k1\r\n var k2 = node.hash.k2\r\n this.LENGTH--;\r\n var lenX = k2.x \u002B 1,\r\n lenY = k2.y \u002B 1;\r\n for (var j = k1.x; j \u003C lenX; \u002B\u002Bj) {\r\n var x = j \u003C\u003C 16;\r\n for (var i = k1.y; i \u003C lenY; \u002B\u002Bi) {\r\n\r\n\r\n var ke = this._getKey(x, i);\r\n\r\n this.DATA[ke].delete(node._HashID)\r\n }\r\n\r\n }\r\n}\r\nGrid.prototype.toArray = function (array, bounds) {\r\n if (this.LENGTH \u003C= 0) return;\r\n var hsh = {};\r\n\r\n this._get(bounds, function (cell) {\r\n\r\n cell.forEach(function (obj, i) {\r\n if (hsh[i]) return\r\n hsh[i] = true;\r\n array.push(obj);\r\n\r\n })\r\n return true;\r\n })\r\n}\r\nGrid.prototype.every = function (bounds, call) {\r\n if (this.LENGTH \u003C= 0) return;\r\n var hsh = {};\r\n\r\n this._get(bounds, function (cell) {\r\n\r\n return cell.every(function (obj, i) {\r\n if (hsh[i]) return true;\r\n hsh[i] = true;\r\n return call(obj);\r\n\r\n })\r\n })\r\n}\r\nGrid.prototype.forEach = function (bounds, call) {\r\n\r\n if (this.LENGTH \u003C= 0) return;\r\n var hsh = {};\r\n\r\n this._get(bounds, function (cell) {\r\n\r\n cell.forEach(function (obj, i) {\r\n if (hsh[i]) return;\r\n hsh[i] = true;\r\n call(obj);\r\n\r\n })\r\n return true;\r\n })\r\n}\r\n\r\nfunction HashBounds(power, lvl, max, minc) {\r\n\r\n this.INITIAL = power;\r\n this.LVL = lvl;\r\n this.MAX = max;\r\n this.MINC = minc || 0;\r\n this.MIN = power \u002B 1;\r\n this.LEVELS = []\r\n this.lastid = 0;\r\n this.createLevels()\r\n this.SQRT = [];\r\n this.setupSQRT()\r\n}\r\nHashBounds.prototype.setupSQRT = function () {\r\n for (var i = 0; i \u003C 255; \u002B\u002Bi) {\r\n this.SQRT.push(Math.floor(Math.sqrt(i)))\r\n }\r\n}\r\nHashBounds.prototype.createLevels = function () {\r\n this.LEVELS = [];\r\n\r\n var last = false\r\n for (var i = this.LVL - 1; i \u003E= 0; --i) {\r\n var a = this.INITIAL \u002B i;\r\n\r\n var grid = new Grid(a, i, this.MAX \u003E\u003E a, this.MINC \u003E\u003E a, last)\r\n this.LEVELS[i] = grid;\r\n last = grid;\r\n }\r\n\r\n}\r\nHashBounds.prototype.clear = function () {\r\n this.createLevels();\r\n}\r\nHashBounds.prototype.update = function (node) {\r\n this.delete(node)\r\n this.insert(node)\r\n}\r\nHashBounds.prototype.insert = function (node) {\r\n if (node.hash) throw \u0022ERR: A node cannot be already in a hash!\u0022\r\n var bounds = node.bounds;\r\n node.hash = {}\r\n if (!node._HashID) node._HashID = \u002B\u002Bthis.lastid;\r\n if (node._HashSize == node.bounds.width \u002B node.bounds.height) {\r\n this.LEVELS[node._HashIndex].insert(node);\r\n return;\r\n }\r\n\r\n var index = this.SQRT[(node.bounds.width \u002B node.bounds.height) \u003E\u003E this.MIN]\r\n if (index \u003E= this.LVL) index = this.LVL - 1;\r\n\r\n node._HashIndex = index;\r\n node._HashSize = node.bounds.width \u002B node.bounds.height;\r\n this.LEVELS[index].insert(node);\r\n //for (var i = 0; i \u003C len; \u002B\u002Bi) {\r\n // if (this.LEVELS[len - i - 1].insert(node)) break;\r\n //}\r\n}\r\n\r\n\r\nHashBounds.prototype.delete = function (node) {\r\n if (!node.hash) throw \u0022ERR: Node is not in a hash!\u0022\r\n this.LEVELS[node.hash.level].delete(node)\r\n node.hash = null;\r\n}\r\nHashBounds.prototype.toArray = function (bounds) {\r\n var array = [];\r\n for (var i = 0; i \u003C this.LEVELS.length; i\u002B\u002B) {\r\n this.LEVELS[i].toArray(array, bounds)\r\n }\r\n return array;\r\n}\r\nHashBounds.prototype.every = function (bounds, call) {\r\n for (var i = 0; i \u003C this.LEVELS.length; i\u002B\u002B) {\r\n if (!this.LEVELS[i].every(bounds, call)) return false;\r\n }\r\n return true;\r\n}\r\nHashBounds.prototype.forEach = function (bounds, call) {\r\n for (var i = 0; i \u003C this.LEVELS.length; i\u002B\u002B) {\r\n this.LEVELS[i].forEach(bounds, call)\r\n }\r\n}\r\nvar Hash = new HashBounds(4,4,150)\r\nvar obj = {\r\n bounds: {\r\n x: Math.floor(Math.random() * 100),\r\n y: Math.floor(Math.random() * 100),\r\n width: Math.floor(Math.random() * 49),\r\n height: Math.floor(Math.random() * 49)\r\n \r\n }\r\n \r\n}\r\nHash.insert(obj)\r\n\r\nobj.x = Math.floor(Math.random() * 100)\r\nobj.y = Math.floor(Math.random() * 100)\r\nvar obj2 = {\r\n bounds: {\r\n x: Math.floor(Math.random() * 100),\r\n y: Math.floor(Math.random() * 100),\r\n width: Math.floor(Math.random() * 49),\r\n height: Math.floor(Math.random() * 49)\r\n \r\n }\r\n \r\n}\r\nHash.insert(obj2)\r\n\r\nobj2.x = Math.floor(Math.random() * 100)\r\nobj2.y = Math.floor(Math.random() * 100)\r\nvar obj3 = {\r\n bounds: {\r\n x: Math.floor(Math.random() * 100),\r\n y: Math.floor(Math.random() * 100),\r\n width: Math.floor(Math.random() * 49),\r\n height: Math.floor(Math.random() * 49)\r\n \r\n }\r\n \r\n}\r\nHash.insert(obj3)\r\n","TestCases":[{"Name":"Insert","Code":"Hash.insert({\r\n bounds: {\r\n x: Math.floor(Math.random() * 100),\r\n y: Math.floor(Math.random() * 100),\r\n width: Math.floor(Math.random() * 49),\r\n height: Math.floor(Math.random() * 49)\r\n \r\n }\r\n \r\n})","IsDeferred":false},{"Name":"Update","Code":"Hash.update(obj)","IsDeferred":false},{"Name":"delete-insert","Code":"Hash.delete(obj2)\r\nHash.insert(obj2)\r\n","IsDeferred":false},{"Name":"forEach()","Code":"Hash.forEach(obj3,function(obj) {\r\n \r\n})","IsDeferred":false}]}