From 646474eaf189b79f25e85819ba3700cdcf38cd2c Mon Sep 17 00:00:00 2001 From: Julien Elbaz Date: Sun, 20 Aug 2017 17:39:15 +0200 Subject: [PATCH] 1.0.8 tag --- CHANGELOG.md | 9 +++++++++ bower.json | 2 +- build/js/quadtree.min.js | 2 +- build/js/quadtree.min.js.map | 2 +- docs/demo/quadtree.min.js | 2 +- docs/demo/quadtree.min.js.map | 2 +- docs/index.html | 2 +- docs/quadtree.html | 2 +- package-lock.json | 2 +- package.json | 2 +- 10 files changed, 18 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e06103..627c794 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Change log - quadtree-lib +## [1.0.8](https://github.com/elbywan/quadtree-lib/compare/1.0.7...1.0.8) + +##### Added + +- [Clear function](https://github.com/elbywan/quadtree-lib/commit/bff7a534185c3e4b127d7c5b9ad3d712f35e2e8c) +- [Javascript linter (Eslint)](https://github.com/elbywan/quadtree-lib/commit/c6ec2412926a218880e6bc8d3877a6d0fcc5a1cf) +- [Movement demo](https://github.com/elbywan/quadtree-lib/commit/a55695507a02597bcca059f35e354c5c87eb8d06) +- [Demo .js refactoring](https://github.com/elbywan/quadtree-lib/commit/2ef03608849ee0cc8cf09cad8fbe82a1b1ad3aac) + ## [1.0.7](https://github.com/elbywan/quadtree-lib/compare/1.0.6...1.0.7) ##### Added diff --git a/bower.json b/bower.json index 6ee6e5d..f428f88 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "quadtree-lib", - "version": "1.0.7", + "version": "1.0.8", "authors": [ "Julien Elbaz " ], diff --git a/build/js/quadtree.min.js b/build/js/quadtree.min.js index 376da09..b1590a2 100644 --- a/build/js/quadtree.min.js +++ b/build/js/quadtree.min.js @@ -1,2 +1,2 @@ -!function(e,t){"function"==typeof define&&define.amd?define([],t):"object"==typeof exports&&module.exports?module.exports=t():e.Quadtree=t()}(this,function(){return function(){function e(t){var n,i;if(this.x=t.x,this.y=t.y,this.width=t.width,this.height=t.height,this.maxElements=t.maxElements,null==this.width||null==this.height)throw new Error("Missing quadtree dimensions.");if(null==this.x&&(this.x=0),null==this.y&&(this.y=0),null==this.maxElements&&(this.maxElements=1),this.contents=[],this.oversized=[],this.size=0,this.width<1||this.height<1)throw new Error("Dimensions must be positive integers.");if(!Number.isInteger(this.x)||!Number.isInteger(this.y))throw new Error("Coordinates must be integers");if(this.maxElements<1)throw new Error("The maximum number of elements before a split must be a positive integer.");i=this,this.children={NW:{create:function(){return new e({x:i.x,y:i.y,width:Math.max(Math.floor(i.width/2),1),height:Math.max(Math.floor(i.height/2),1),maxElements:i.maxElements})},tree:null},NE:{create:function(){return new e({x:i.x+Math.max(Math.floor(i.width/2),1),y:i.y,width:Math.ceil(i.width/2),height:Math.max(Math.floor(i.height/2),1),maxElements:i.maxElements})},tree:null},SW:{create:function(){return new e({x:i.x,y:i.y+Math.max(Math.floor(i.height/2),1),width:Math.max(Math.floor(i.width/2),1),height:Math.ceil(i.height/2),maxElements:i.maxElements})},tree:null},SE:{create:function(){return new e({x:i.x+Math.max(Math.floor(i.width/2),1),y:i.y+Math.max(Math.floor(i.height/2),1),width:Math.ceil(i.width/2),height:Math.ceil(i.height/2),maxElements:i.maxElements})},tree:null}};for(n in this.children)this.children[n].get=function(){return null!=this.tree?this.tree:(this.tree=this.create(),this.tree)}}var t,n,i,r,h,l,o,s;return r=function(e){var t,n;return{x:Math.floor((null!=(t=e.width)?t:1)/2)+e.x,y:Math.floor((null!=(n=e.height)?n:1)/2)+e.y}},t=function(e,t){var n,i,r,h;return!(e.x>=t.x+(null!=(n=t.width)?n:1)||e.x+(null!=(i=e.width)?i:1)<=t.x||e.y>=t.y+(null!=(r=t.height)?r:1)||e.y+(null!=(h=e.height)?h:1)<=t.y)},n=function(e,t){var n;return n=r(t),e.x0;){for(E=c.shift(),b=E.tree,f=E.elements,d={NW:null,NE:null,SW:null,SE:null},m=0,v=f.length;m-1?(this.oversized.splice(i,1),this.size--,t||o(e),!0):(i=this.contents.indexOf(e))>-1?(this.contents.splice(i,1),this.size--,t||o(e),!0):(r=this.children[n(e,this)],!(null==r.tree||!r.tree.remove(e,t))&&(this.size--,0===r.tree.size&&(r.tree=null),!0))},e.prototype.colliding=function(e,n){var r,h,l,o,u,f,c,d,a,g,p,m,x,y;for(null==n&&(n=t),s(e),u=[],l=[this];l.length>0;){for(y=l.shift(),m=y.oversized,f=0,a=m.length;f=y.x+y.width&&o.push("NE"),e.y>=y.y+y.height&&o.push("SW"),o.length>0&&(1===o.length?o.push("SE"):o=["SE"])),d=0,p=o.length;d0;){for(y=o.shift(),m=y.oversized,f=0,a=m.length;f=y.x+y.width&&u.push("NE"),e.y>=y.y+y.height&&u.push("SW"),u.length>0&&(1===u.length?u.push("SE"):u=["SE"])),d=0,p=u.length;d0;){for(p=r.shift(),d=p.oversized,l=0,f=d.length;l0;){for(f=n.shift(),s=f.oversized,r=0,l=s.length;r0;){for(c=n.shift(),u=c.oversized,h=0,o=u.length;h0;){i=n.shift(),e.bind(i)();for(t in i.children)null!=i.children[t].tree&&n.push(i.children[t].tree)}return this},e.prototype.pretty=function(){var e,t,n,i,r,h,l;for(h="",n=function(e){var t,n,i;for(i="",t=n=e;n<=0?t<0:t>0;n<=0?++t:--t)i+=" ";return i},t=[{label:"ROOT",tree:this,level:0}];t.length>0;){l=t.shift(),i=n(l.level),h+=i+"| "+l.label+"\n"+i+"| ------------\n",l.tree.oversized.length>0&&(h+=i+"| * Oversized elements *\n"+i+"| "+l.tree.oversized+"\n"),l.tree.contents.length>0&&(h+=i+"| * Leaf content *\n"+i+"| "+l.tree.contents+"\n"),r=!1;for(e in l.tree.children)null!=l.tree.children[e].tree&&(r=!0,t.unshift({label:e,tree:l.tree.children[e].tree,level:l.level+1}));r&&(h+=i+"└──┐\n")}return h},e}()}); +!function(e,t){"function"==typeof define&&define.amd?define([],t):"object"==typeof exports&&module.exports?module.exports=t():e.Quadtree=t()}(this,function(){return function(){function e(t){var n,i;if(this.x=t.x,this.y=t.y,this.width=t.width,this.height=t.height,this.maxElements=t.maxElements,null==this.width||null==this.height)throw new Error("Missing quadtree dimensions.");if(null==this.x&&(this.x=0),null==this.y&&(this.y=0),null==this.maxElements&&(this.maxElements=1),this.contents=[],this.oversized=[],this.size=0,this.width<1||this.height<1)throw new Error("Dimensions must be positive integers.");if(!Number.isInteger(this.x)||!Number.isInteger(this.y))throw new Error("Coordinates must be integers");if(this.maxElements<1)throw new Error("The maximum number of elements before a split must be a positive integer.");i=this,this.children={NW:{create:function(){return new e({x:i.x,y:i.y,width:Math.max(Math.floor(i.width/2),1),height:Math.max(Math.floor(i.height/2),1),maxElements:i.maxElements})},tree:null},NE:{create:function(){return new e({x:i.x+Math.max(Math.floor(i.width/2),1),y:i.y,width:Math.ceil(i.width/2),height:Math.max(Math.floor(i.height/2),1),maxElements:i.maxElements})},tree:null},SW:{create:function(){return new e({x:i.x,y:i.y+Math.max(Math.floor(i.height/2),1),width:Math.max(Math.floor(i.width/2),1),height:Math.ceil(i.height/2),maxElements:i.maxElements})},tree:null},SE:{create:function(){return new e({x:i.x+Math.max(Math.floor(i.width/2),1),y:i.y+Math.max(Math.floor(i.height/2),1),width:Math.ceil(i.width/2),height:Math.ceil(i.height/2),maxElements:i.maxElements})},tree:null}};for(n in this.children)this.children[n].get=function(){return null!=this.tree?this.tree:(this.tree=this.create(),this.tree)}}var t,n,i,r,h,l,o,s;return r=function(e){var t,n;return{x:Math.floor((null!=(t=e.width)?t:1)/2)+e.x,y:Math.floor((null!=(n=e.height)?n:1)/2)+e.y}},t=function(e,t){var n,i,r,h;return!(e.x>=t.x+(null!=(n=t.width)?n:1)||e.x+(null!=(i=e.width)?i:1)<=t.x||e.y>=t.y+(null!=(r=t.height)?r:1)||e.y+(null!=(h=e.height)?h:1)<=t.y)},n=function(e,t){var n;return n=r(t),e.x0;){for(b=(E=c.shift()).tree,d={NW:null,NE:null,SW:null,SE:null},m=0,v=(f=E.elements).length;m-1?(this.oversized.splice(i,1),this.size--,t||o(e),!0):(i=this.contents.indexOf(e))>-1?(this.contents.splice(i,1),this.size--,t||o(e),!0):!(null==(r=this.children[n(e,this)]).tree||!r.tree.remove(e,t)||(this.size--,0===r.tree.size&&(r.tree=null),0))},e.prototype.colliding=function(e,n){var r,h,l,o,u,f,c,d,a,g,p,m,x,y;for(null==n&&(n=t),s(e),u=[],l=[this];l.length>0;){for(f=0,a=(m=(y=l.shift()).oversized).length;f=y.x+y.width&&o.push("NE"),e.y>=y.y+y.height&&o.push("SW"),o.length>0&&(1===o.length?o.push("SE"):o=["SE"])),d=0,p=o.length;d0;){for(f=0,a=(m=(y=o.shift()).oversized).length;f=y.x+y.width&&u.push("NE"),e.y>=y.y+y.height&&u.push("SW"),u.length>0&&(1===u.length?u.push("SE"):u=["SE"])),d=0,p=u.length;d0;){for(l=0,f=(d=(p=r.shift()).oversized).length;l0;){for(r=0,l=(s=(f=n.shift()).oversized).length;r0;){for(h=0,o=(u=(c=n.shift()).oversized).length;h0;){i=n.shift(),e.bind(i)();for(t in i.children)null!=i.children[t].tree&&n.push(i.children[t].tree)}return this},e.prototype.pretty=function(){var e,t,n,i,r,h,l;for(h="",n=function(e){var t,n,i;for(i="",t=n=e;n<=0?t<0:t>0;n<=0?++t:--t)i+=" ";return i},t=[{label:"ROOT",tree:this,level:0}];t.length>0;){h+=(i=n((l=t.shift()).level))+"| "+l.label+"\n"+i+"| ------------\n",l.tree.oversized.length>0&&(h+=i+"| * Oversized elements *\n"+i+"| "+l.tree.oversized+"\n"),l.tree.contents.length>0&&(h+=i+"| * Leaf content *\n"+i+"| "+l.tree.contents+"\n"),r=!1;for(e in l.tree.children)null!=l.tree.children[e].tree&&(r=!0,t.unshift({label:e,tree:l.tree.children[e].tree,level:l.level+1}));r&&(h+=i+"└──┐\n")}return h},e}()}); //# sourceMappingURL=quadtree.min.js.map diff --git a/build/js/quadtree.min.js.map b/build/js/quadtree.min.js.map index 4677d77..4d70253 100644 --- a/build/js/quadtree.min.js.map +++ b/build/js/quadtree.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["quadtree.coffee"],"names":["root","factory","define","amd","exports","module","this","Quadtree","arg","child","that","x","y","width","height","maxElements","Error","contents","oversized","size","Number","isInteger","children","NW","create","Math","max","floor","tree","NE","ceil","SW","SE","get","boundingBoxCollision","calculateDirection","fitting","getCenter","observe","splitTree","unobserve","validateElement","item","ref","ref1","elt1","elt2","ref2","ref3","element","quadCenter","bottomHeight","leftWidth","rightWidth","topHeight","coordinates","direction","where","push","writeAccessors","propName","Object","defineProperty","set","val","remove","configurable","unwriteAccessors","clear","results","doObserve","pushAll","items","candidate","content","contentDir","elements","fifo","fifoCandidates","fits","j","k","l","len","len1","len2","relatedChild","length","shift","stillObserve","index","indexOf","splice","colliding","collisionFunction","elt","top","onCollision","callback","query","check","key","find","each","action","i","predicate","filter","deepclone","target","copycat","reject","visit","bind","pretty","indent","indentation","isParent","str","level","res","label","unshift"],"mappings":"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","file":"quadtree.min.js","sourcesContent":["# quadtree-lib\n# ============\n#\n# **Quadtree-lib** is an easy to use, developer friendly quadtree library\n# which contains many helper methods to add, remove, iterate, filter, simulate\n# collisions over 2d elements and more.\n\n# #### UMD bundling related code\n((root, factory) ->\n if typeof define is 'function' and define.amd\n define [], factory\n else if typeof exports is 'object' and module.exports\n module.exports = factory()\n else\n root['Quadtree'] = factory()\n) @, (-> class Quadtree\n # The Quadtree class\n # -------------------\n\n # ### Constructor\n\n # The quadtree constructor accepts a single parameter object containing the following properties :\n # - width / length : dimensions of the quadtree. [ *mandatory* ]\n # - maxElements : the maximum number of elements before the leaf 'splits' into subtrees. [ *defaults to 1* ]\n # - x / y : these coordinates are used internally by the library to position subtrees. [ *internal use only* ]\n constructor: ({ @x, @y, @width, @height, @maxElements }) ->\n\n # An error is thrown when the width & length are not passed as constructor arguments.\n throw new Error 'Missing quadtree dimensions.' if not @width? or not @height?\n @x ?= 0\n @y ?= 0\n @maxElements ?= 1\n @contents = []\n @oversized = []\n @size = 0\n\n # Dimension & coordinates are checked, an error is thrown in case of bad input.\n throw new Error 'Dimensions must be positive integers.' if @width < 1 or @height < 1\n throw new Error 'Coordinates must be integers' if not Number.isInteger(@x) or not Number.isInteger(@y)\n throw new Error 'The maximum number of elements before a split must be a positive integer.' if @maxElements < 1\n\n that = @\n\n # The subtrees list, by position.\n @children = {\n # Northwest tree.\n NW:\n create: ->\n new Quadtree({\n x: that.x\n y: that.y\n width: Math.max (Math.floor that.width / 2), 1\n height: Math.max (Math.floor that.height / 2), 1\n maxElements: that.maxElements\n })\n tree: null\n # Northeast tree.\n NE:\n create: ->\n new Quadtree({\n x: that.x + Math.max (Math.floor that.width / 2), 1\n y: that.y\n width: Math.ceil that.width / 2\n height: Math.max (Math.floor that.height / 2), 1\n maxElements: that.maxElements\n })\n tree: null\n # Southwest tree.\n SW:\n create: ->\n new Quadtree({\n x: that.x\n y: that.y + Math.max (Math.floor that.height / 2), 1\n width: Math.max (Math.floor that.width / 2), 1\n height: Math.ceil that.height / 2\n maxElements: that.maxElements\n })\n tree: null\n # Southeast tree.\n SE:\n create: ->\n new Quadtree({\n x: that.x + Math.max (Math.floor that.width / 2), 1\n y: that.y + Math.max (Math.floor that.height / 2), 1\n width: Math.ceil that.width / 2\n height: Math.ceil that.height / 2\n maxElements: that.maxElements\n })\n tree: null\n }\n # Adding a getter which lazily creates the tree.\n for child of @children\n @children[child].get = ->\n if @tree? then @tree else @tree = @create(); @tree\n\n # ### Internal methods & vars\n\n # Retrieves the center coordinates of a rectangle.\n getCenter = (item) ->\n x: Math.floor((item.width ? 1) / 2) + item.x\n y: Math.floor((item.height ? 1) / 2) + item.y\n\n # Bounding box collision algorithm.\n boundingBoxCollision = (elt1, elt2) ->\n not(elt1.x >= elt2.x + (elt2.width ? 1) or\n elt1.x + (elt1.width ? 1) <= elt2.x or\n elt1.y >= elt2.y + (elt2.height ? 1) or\n elt1.y + (elt1.height ? 1) <= elt2.y)\n\n # Determines which subtree an element belongs to.\n calculateDirection = (element, tree) ->\n quadCenter = getCenter tree\n\n if element.x < quadCenter.x\n if element.y < quadCenter.y then 'NW'\n else 'SW'\n else\n if element.y < quadCenter.y then 'NE'\n else 'SE'\n\n # Validates a potential element of the tree.\n validateElement = (element) ->\n if not (typeof element is 'object')\n throw new Error 'Element must be an Object.'\n if not element.x? or not element.y?\n throw new Error 'Coordinates properties are missing.'\n if element?.width < 0 or element?.height < 0\n throw new Error 'Width and height must be positive integers.'\n\n # Returns splitted coordinates and dimensions.\n splitTree = (tree) ->\n leftWidth = Math.max (Math.floor tree.width / 2), 1\n rightWidth = Math.ceil tree.width / 2\n topHeight = Math.max (Math.floor tree.height / 2), 1\n bottomHeight = Math.ceil tree.height / 2\n NW:\n x: tree.x\n y: tree.y\n width: leftWidth\n height: topHeight\n NE:\n x: tree.x + leftWidth\n y: tree.y\n width: rightWidth\n height: topHeight\n SW:\n x: tree.x\n y: tree.y + topHeight\n width: leftWidth\n height: bottomHeight\n SE:\n x: tree.x + leftWidth\n y: tree.y + topHeight\n width: rightWidth\n height: bottomHeight\n\n # Determines wether an element fits into subtrees.\n fitting = (element, tree) ->\n where = []\n for direction, coordinates of splitTree tree when boundingBoxCollision element, coordinates\n where.push direction\n where\n\n # Add getters and setters for coordinates and dimensions properties in order to automatically reorganize the elements on change.\n observe = (item, tree) ->\n writeAccessors = (propName) ->\n item[\"_#{propName}\"] = item[propName]\n Object.defineProperty item, propName, {\n set: (val) ->\n tree.remove @, true\n @[\"_#{propName}\"] = val\n tree.push @\n get: ->\n @[\"_#{propName}\"]\n configurable: true\n }\n writeAccessors 'x'\n writeAccessors 'y'\n writeAccessors 'width'\n writeAccessors 'height'\n\n # Remove getters and setters and restore previous properties\n unobserve = (item) ->\n unwriteAccessors = (propName) ->\n if not item[\"_#{propName}\"]? then return\n delete item[propName]\n item[propName] = item[\"_#{propName}\"]\n delete item[\"_#{propName}\"]\n unwriteAccessors 'x'\n unwriteAccessors 'y'\n unwriteAccessors 'width'\n unwriteAccessors 'height'\n\n # ### Exposed methods\n\n # Removes all elements from the quadtree and restores it to pristine state.\n clear: ->\n @contents = []\n @oversized = []\n @size = 0\n for child of @children\n @children[child].tree = null\n\n # Add an element to the quadtree.\n # Elements can be observed to reorganize them into the quadtree automatically whenever their coordinates or dimensions are set (for ex. obj.x = ...).\n push: (item, doObserve) ->\n @pushAll([item], doObserve)\n\n # Push an array of elements.\n pushAll: (items, doObserve) ->\n for item in items\n validateElement item\n observe item, @ if doObserve\n\n fifo = [tree: @, elements: items]\n\n while fifo.length > 0\n { tree, elements } = fifo.shift()\n\n fifoCandidates = { NW: null, NE: null, SW: null, SE: null }\n\n for element in elements\n tree.size++\n\n fits = fitting element, tree\n\n if fits.length isnt 1 or tree.width is 1 or tree.height is 1\n tree.oversized.push element\n\n else if (tree.size - tree.oversized.length) <= tree.maxElements\n tree.contents.push element\n\n else\n direction = fits[0]\n relatedChild = tree.children[direction]\n fifoCandidates[direction] ?= { tree: relatedChild.get(), elements: [] }\n fifoCandidates[direction].elements.push(element)\n\n for content in tree.contents\n contentDir = (fitting content, tree)[0]\n fifoCandidates[contentDir] ?= { tree: tree.children[contentDir].get(), elements: [] }\n fifoCandidates[contentDir].elements.push(content)\n\n tree.contents = []\n\n for direction, candidate of fifoCandidates\n if candidate? then fifo.push candidate\n\n @\n\n # Removes an element from the quadtree.\n remove: (item, stillObserve) ->\n validateElement item\n\n index = @oversized.indexOf item\n if index > -1\n @oversized.splice index, 1\n @size--\n if not stillObserve then unobserve item\n return true\n\n index = @contents.indexOf item\n if index > -1\n @contents.splice index, 1\n @size--\n if not stillObserve then unobserve item\n return true\n\n relatedChild = @children[calculateDirection item, @]\n\n if relatedChild.tree? and relatedChild.tree.remove item, stillObserve\n @size--\n relatedChild.tree = null if relatedChild.tree.size is 0\n return true\n\n false\n\n # Returns an array of elements which collides with the `item` argument.\n # `item` being an object having x, y, width & height properties.\n\n # The default collision function is a basic bounding box algorithm.\n # You can change it by providing a function as a second argument.\n #```javascript\n #colliding({x: 10, y: 20}, function(element1, element2) {\n # return // Place predicate here //\n #})\n #```\n colliding: (item, collisionFunction = boundingBoxCollision) ->\n validateElement item\n\n items = []\n fifo = [@]\n\n while fifo.length > 0\n top = fifo.shift()\n\n for elt in top.oversized when elt isnt item and collisionFunction item, elt then items.push elt\n for elt in top.contents when elt isnt item and collisionFunction item, elt then items.push elt\n\n fits = fitting item, top\n\n # Special case for elements located outside of the quadtree on the right / bottom side\n if fits.length is 0\n fits = []\n if item.x >= top.x + top.width\n fits.push 'NE'\n if item.y >= top.y + top.height\n fits.push 'SW'\n if fits.length > 0\n if fits.length is 1 then fits.push 'SE' else fits = ['SE']\n\n for child in fits when top.children[child].tree?\n fifo.push top.children[child].tree\n\n items\n\n # Performs an action on elements which collides with the `item` argument.\n # `item` being an object having x, y, width & height properties.\n\n # The default collision function is a basic bounding box algorithm.\n # You can change it by providing a function as a third argument.\n #```javascript\n #onCollision(\n # {x: 10, y: 20},\n # function(item) { /* stuff */ },\n # function(element1, element2) {\n # return // Place predicate here //\n #})\n #```\n onCollision: (item, callback, collisionFunction = boundingBoxCollision) ->\n validateElement item\n\n fifo = [@]\n\n while fifo.length > 0\n top = fifo.shift()\n\n for elt in top.oversized when elt isnt item and collisionFunction item, elt then callback elt\n for elt in top.contents when elt isnt item and collisionFunction item, elt then callback elt\n\n fits = fitting item, top\n\n # Special case for elements located outside of the quadtree on the right / bottom side\n if fits.length is 0\n fits = []\n if item.x >= top.x + top.width\n fits.push 'NE'\n if item.y >= top.y + top.height\n fits.push 'SW'\n if fits.length > 0\n if fits.length is 1 then fits.push 'SE' else fits = ['SE']\n\n for child in fits when top.children[child].tree?\n fifo.push top.children[child].tree\n\n return null\n\n # Alias of `where`.\n get: (query) ->\n @where query\n # Returns an array of elements that match the `query` argument.\n where: (query) ->\n # Naïve parsing (missing coordinates)\n if typeof query is 'object' and (not query.x? or not query.y?)\n return @find (elt) ->\n check = true\n for key of query when query[key] isnt elt[key] then check = false\n check\n\n # Optimised parsing\n validateElement query\n\n items = []\n fifo = [@]\n\n while fifo.length > 0\n top = fifo.shift()\n\n for elt in top.oversized\n check = true\n for key of query when query[key] isnt elt[key] then check = false\n items.push elt if check\n for elt in top.contents\n check = true\n for key of query when query[key] isnt elt[key] then check = false\n items.push elt if check\n\n relatedChild = top.children[calculateDirection query, top]\n\n if relatedChild.tree?\n fifo.push relatedChild.tree\n\n items\n\n # For each element of the quadtree, performs the `action` function.\n #```javascript\n #quad.each(function(item) { console.log(item) })\n #```\n each: (action) ->\n fifo = [@]\n\n while fifo.length > 0\n top = fifo.shift()\n for i in top.oversized then action?(i)\n for i in top.contents then action?(i)\n\n for child of top.children when top.children[child].tree?\n fifo.push top.children[child].tree\n @\n\n # Returns an array of elements which validates the predicate.\n find: (predicate) ->\n fifo = [@]\n items = []\n\n while fifo.length > 0\n top = fifo.shift()\n for i in top.oversized when predicate?(i) then items.push i\n for i in top.contents when predicate?(i) then items.push i\n\n for child of top.children when top.children[child].tree?\n fifo.push top.children[child].tree\n items\n\n # Returns a **cloned** `Quadtree` object which contains only the elements that validate the predicate.\n filter: (predicate) ->\n deepclone = (target) ->\n copycat = new Quadtree x: target.x, y: target.y, width: target.width, height: target.height, maxElements: target.maxElements\n copycat.size = 0\n for child of target.children when target.children[child].tree?\n copycat.children[child].tree = deepclone target.children[child].tree\n copycat.size += copycat.children[child].tree?.size ? 0\n\n for item in target.oversized when not predicate? or predicate?(item)\n copycat.oversized.push item\n for item in target.contents when not predicate? or predicate?(item)\n copycat.contents.push item\n\n copycat.size += copycat.oversized.length + copycat.contents.length\n if copycat.size is 0 then null else copycat\n\n deepclone @\n\n # Opposite of filter.\n reject: (predicate) ->\n @filter (i) ->\n not predicate?(i)\n\n # Visits each tree & subtree contained in the `Quadtree` object.\n # For each node, performs the `action` function, inside which `this` is bound to the node tree object.\n visit: (action) ->\n fifo = [@]\n\n while fifo.length > 0\n that = fifo.shift()\n action.bind(that)()\n\n for child of that.children when that.children[child].tree?\n fifo.push that.children[child].tree\n @\n\n # Pretty printing function.\n pretty: ->\n str = ''\n\n indent = (level) ->\n res = ''\n res += ' ' for times in [level...0]\n res\n\n fifo = [{ label: 'ROOT', tree: @, level: 0 }]\n while fifo.length > 0\n top = fifo.shift()\n indentation = indent(top.level)\n str += \"\"\"\n #{indentation}| #{top.label}\n #{indentation}| ------------\\n\n \"\"\"\n\n if top.tree.oversized.length > 0\n str += \"\"\"\n #{indentation}| * Oversized elements *\n #{indentation}| #{top.tree.oversized}\\n\n \"\"\"\n\n if top.tree.contents.length > 0\n str += \"\"\"\n #{indentation}| * Leaf content *\n #{indentation}| #{top.tree.contents}\\n\n \"\"\"\n\n isParent = false\n for child of top.tree.children when top.tree.children[child].tree?\n isParent = true\n fifo.unshift { label: child, tree: top.tree.children[child].tree, level: top.level + 1 }\n\n if isParent then str += \"#{indentation}└──┐\\n\"\n\n str\n)\n"]} \ No newline at end of file +{"version":3,"sources":["quadtree.coffee"],"names":["root","factory","define","amd","exports","module","this","Quadtree","arg","child","that","x","y","width","height","maxElements","Error","contents","oversized","size","Number","isInteger","children","NW","create","Math","max","floor","tree","NE","ceil","SW","SE","get","boundingBoxCollision","calculateDirection","fitting","getCenter","observe","splitTree","unobserve","validateElement","item","ref","ref1","elt1","elt2","ref2","ref3","element","quadCenter","bottomHeight","leftWidth","rightWidth","topHeight","coordinates","direction","where","push","writeAccessors","propName","Object","defineProperty","set","val","remove","configurable","unwriteAccessors","clear","results","doObserve","pushAll","items","candidate","content","contentDir","elements","fifo","fifoCandidates","fits","j","k","l","len","len1","len2","relatedChild","length","shift","stillObserve","index","indexOf","splice","colliding","collisionFunction","elt","top","onCollision","callback","query","check","key","find","each","action","i","predicate","filter","deepclone","target","copycat","reject","visit","bind","pretty","indent","indentation","isParent","str","level","res","label","unshift"],"mappings":"CAQA,SAAEA,EAAMC,GACgB,mBAAVC,QAAyBA,OAAOC,IACtCD,UAAWD,GACW,iBAAXG,SAAwBC,OAAOD,QAC1CC,OAAOD,QAAUH,IAEjBD,EAAK,SAAcC,IAN3B,CAOEK,KAAG,kBAAU,WAUE,SAAAC,EAACC,GAGV,IAAAC,EAAAC,EAAA,GAHYJ,KAACK,EAAAH,EAAAG,EAAGL,KAACM,EAAAJ,EAAAI,EAAGN,KAACO,MAAAL,EAAAK,MAAOP,KAACQ,OAAAN,EAAAM,OAAQR,KAACS,YAAAP,EAAAO,YAGgB,MAAAT,KAAAO,OAAe,MAAAP,KAAAQ,OAArE,MAAM,IAAIE,MAAM,gCAShB,kBARAV,KAACK,EAAK,kBACNL,KAACM,EAAK,4BACNN,KAACS,YAAe,GAChBT,KAACW,YACDX,KAACY,aACDZ,KAACa,KAAO,EAGmDb,KAACO,MAAQ,GAAKP,KAACQ,OAAS,EAAnF,MAAM,IAAIE,MAAM,yCAChB,IAAsDI,OAAOC,UAAUf,KAACK,KAAUS,OAAOC,UAAUf,KAACM,GAApG,MAAM,IAAII,MAAM,gCAChB,GAA+FV,KAACS,YAAc,EAA9G,MAAM,IAAIC,MAAM,6EAEhBN,EAAOJ,KAGPA,KAACgB,UAEGC,IACIC,OAAQ,kBACJ,IAAIjB,GACAI,EAAGD,EAAKC,EACRC,EAAGF,EAAKE,EACRC,MAAOY,KAAKC,IAAKD,KAAKE,MAAMjB,EAAKG,MAAQ,GAAI,GAC7CC,OAAQW,KAAKC,IAAKD,KAAKE,MAAMjB,EAAKI,OAAS,GAAI,GAC/CC,YAAaL,EAAKK,eAE1Ba,KAAM,MAEVC,IACIL,OAAQ,kBACJ,IAAIjB,GACAI,EAAGD,EAAKC,EAAIc,KAAKC,IAAKD,KAAKE,MAAMjB,EAAKG,MAAQ,GAAI,GAClDD,EAAGF,EAAKE,EACRC,MAAOY,KAAKK,KAAKpB,EAAKG,MAAQ,GAC9BC,OAAQW,KAAKC,IAAKD,KAAKE,MAAMjB,EAAKI,OAAS,GAAI,GAC/CC,YAAaL,EAAKK,eAE1Ba,KAAM,MAEVG,IACIP,OAAQ,kBACJ,IAAIjB,GACAI,EAAGD,EAAKC,EACRC,EAAGF,EAAKE,EAAIa,KAAKC,IAAKD,KAAKE,MAAMjB,EAAKI,OAAS,GAAI,GACnDD,MAAOY,KAAKC,IAAKD,KAAKE,MAAMjB,EAAKG,MAAQ,GAAI,GAC7CC,OAAQW,KAAKK,KAAKpB,EAAKI,OAAS,GAChCC,YAAaL,EAAKK,eAE1Ba,KAAM,MAEVI,IACIR,OAAQ,kBACJ,IAAIjB,GACAI,EAAGD,EAAKC,EAAIc,KAAKC,IAAKD,KAAKE,MAAMjB,EAAKG,MAAQ,GAAI,GAClDD,EAAGF,EAAKE,EAAIa,KAAKC,IAAKD,KAAKE,MAAMjB,EAAKI,OAAS,GAAI,GACnDD,MAAOY,KAAKK,KAAKpB,EAAKG,MAAQ,GAC9BC,OAAQW,KAAKK,KAAKpB,EAAKI,OAAS,GAChCC,YAAaL,EAAKK,eAE1Ba,KAAM,OAGd,IAAAnB,KAAAH,KAAAgB,SACIhB,KAACgB,SAASb,GAAOwB,IAAM,WACnB,OAAG,MAAA3B,KAAAsB,KAAYtB,KAACsB,MAAUtB,KAACsB,KAAOtB,KAACkB,SAAUlB,KAACsB,OApE1D,IAAAM,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,SAyEAJ,EAAY,SAACK,GACT,IAAAC,EAAAC,SAAAjC,EAAGc,KAAKE,OAAM,OAAAgB,EAAAD,EAAA7B,OAAA8B,EAAe,GAAK,GAAKD,EAAK/B,EAC5CC,EAAGa,KAAKE,OAAM,OAAAiB,EAAAF,EAAA5B,QAAA8B,EAAe,GAAK,GAAKF,EAAK9B,IAGhDsB,EAAuB,SAACW,EAAMC,GAC1B,IAAAH,EAAAC,EAAAG,EAAAC,UAAIH,EAAKlC,GAAKmC,EAAKnC,GAAI,OAAAgC,EAAAG,EAAAjC,OAAA8B,EAAc,IACjCE,EAAKlC,GAAI,OAAAiC,EAAAC,EAAAhC,OAAA+B,EAAc,IAAME,EAAKnC,GAClCkC,EAAKjC,GAAKkC,EAAKlC,GAAI,OAAAmC,EAAAD,EAAAhC,QAAAiC,EAAe,IAClCF,EAAKjC,GAAI,OAAAoC,EAAAH,EAAA/B,QAAAkC,EAAe,IAAMF,EAAKlC,IAG3CuB,EAAqB,SAACc,EAASrB,GAC3B,IAAAsB,EAEA,OAFAA,EAAab,EAAUT,GAEpBqB,EAAQtC,EAAIuC,EAAWvC,EACnBsC,EAAQrC,EAAIsC,EAAWtC,EAAO,KAC5B,KAEFqC,EAAQrC,EAAIsC,EAAWtC,EAAO,KAC5B,MAGb6B,EAAkB,SAACQ,GACf,GAA0B,iBAAXA,EACX,MAAM,IAAIjC,MAAM,8BACpB,GAAO,MAAAiC,EAAAtC,GAAkB,MAAAsC,EAAArC,EACrB,MAAM,IAAII,MAAM,uCACpB,IAAA,MAAAiC,EAAGA,EAASpC,WAAA,GAAQ,IAAjB,MAAAoC,EAAsBA,EAASnC,YAAA,GAAS,EACvC,MAAM,IAAIE,MAAM,gDAGxBuB,EAAY,SAACX,GACT,IAAAuB,EAAAC,EAAAC,EAAAC,SAAAF,EAAe3B,KAAKC,IAAKD,KAAKE,MAAMC,EAAKf,MAAQ,GAAI,GACrDwC,EAAe5B,KAAKK,KAAKF,EAAKf,MAAQ,GACtCyC,EAAe7B,KAAKC,IAAKD,KAAKE,MAAMC,EAAKd,OAAS,GAAI,GACtDqC,EAAe1B,KAAKK,KAAKF,EAAKd,OAAS,IACvCS,IACIZ,EAAGiB,EAAKjB,EACRC,EAAGgB,EAAKhB,EACRC,MAAOuC,EACPtC,OAAQwC,GACZzB,IACIlB,EAAGiB,EAAKjB,EAAIyC,EACZxC,EAAGgB,EAAKhB,EACRC,MAAOwC,EACPvC,OAAQwC,GACZvB,IACIpB,EAAGiB,EAAKjB,EACRC,EAAGgB,EAAKhB,EAAI0C,EACZzC,MAAOuC,EACPtC,OAAQqC,GACZnB,IACIrB,EAAGiB,EAAKjB,EAAIyC,EACZxC,EAAGgB,EAAKhB,EAAI0C,EACZzC,MAAOwC,EACPvC,OAAQqC,KAGhBf,EAAU,SAACa,EAASrB,GAChB,IAAA2B,EAAAC,EAAAb,EAAAc,EAAAA,KACAd,EAAAJ,EAAAX,GAAA,IAAA4B,KAAAb,SAAkDT,EAAqBe,EAASM,IAC5EE,EAAMC,KAAKF,UACfC,GAGJnB,EAAU,SAACI,EAAMd,GACb,IAAA+B,SAAAA,EAAiB,SAACC,UACdlB,EAAK,IAAIkB,GAAclB,EAAKkB,GAC5BC,OAAOC,eAAepB,EAAMkB,GACxBG,IAAK,SAACC,UACFpC,EAAKqC,OAAO3D,MAAG,GACfA,KAAE,IAAIsD,GAAcI,EACpBpC,EAAK8B,KAAKpD,OACd2B,IAAK,kBACD3B,KAAE,IAAIsD,IACVM,cAAc,MAEP,KACfP,EAAe,KACfA,EAAe,SACfA,EAAe,WAGnBnB,EAAY,SAACE,GACT,IAAAyB,SAAAA,EAAmB,SAACP,GAChB,GAAO,MAAAlB,EAAA,IAAAkB,iBACAlB,EAAKkB,GACZlB,EAAKkB,GAAYlB,EAAK,IAAIkB,UACnBlB,EAAK,IAAIkB,KACH,KACjBO,EAAiB,KACjBA,EAAiB,SACjBA,EAAiB,uBAKrBC,MAAO,WACH,IAAA3D,EAAA4D,EAAA/D,KAACW,YACDX,KAACY,aACDZ,KAACa,KAAO,EACRkD,SAAA5D,KAAAH,KAAAgB,gBACIhB,KAACgB,SAASb,GAAOmB,KAAO,4BAIhC8B,KAAM,SAAChB,EAAM4B,UACThE,KAACiE,SAAS7B,GAAO4B,gBAGrBC,QAAS,SAACC,EAAOF,GACb,IAAAG,EAAAC,EAAAC,EAAAnB,EAAAP,EAAA2B,EAAAC,EAAAC,EAAAC,EAAArC,EAAAsC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAA1C,EAAAC,EAAA0C,EAAA1D,EAAA,IAAAoD,EAAA,EAAAG,EAAAX,EAAAe,OAAAP,EAAAG,EAAAH,WACIvC,EAAgBC,GACG4B,GAAnBhC,EAAQI,EAAMpC,MAIlB,IAFAuE,IAAQjD,KAAMtB,KAAGsE,SAAUJ,IAErBK,EAAKU,OAAS,GAApB,CAKI,IAJE3D,GAAFe,EAAqBkC,EAAKW,SAAxB5D,KAEFkD,GAAmBvD,GAAI,KAAMM,GAAI,KAAME,GAAI,KAAMC,GAAI,MAErDiD,EAAA,EAAAG,GAJQR,EAAAjC,EAAAiC,UAIRW,OAAAN,EAAAG,EAAAH,IAKI,UAJArD,EAAKT,OAIe,KAFpB4D,EAAO3C,EAAQa,EAASrB,IAEhB2D,QAA+B,IAAd3D,EAAKf,OAA6B,IAAfe,EAAKd,OAC7Cc,EAAKV,UAAUwC,KAAKT,QAEnB,GAAIrB,EAAKT,KAAOS,EAAKV,UAAUqE,QAAW3D,EAAKb,YAChDa,EAAKX,SAASyC,KAAKT,OADlB,CASD,IALAO,EAAYuB,EAAK,GACjBO,EAAe1D,EAAKN,SAASkC,gBAC7BsB,EAAetB,IAAgB5B,KAAM0D,EAAarD,MAAO2C,cACzDE,EAAetB,GAAWoB,SAASlB,KAAKT,GAExCiC,EAAA,EAAAG,GAAAzC,EAAAhB,EAAAX,UAAAsE,OAAAL,EAAAG,EAAAH,mBACIP,EAAcvC,EAAQsC,EAAS9C,GAAM,MACrCkD,EAAeH,IAAiB/C,KAAMA,EAAKN,SAASqD,GAAY1C,MAAO2C,cACvEE,EAAeH,GAAYC,SAASlB,KAAKgB,GAE7C9C,EAAKX,YAEb,IAAAuC,KAAAsB,EACO,gBAAgBD,EAAKnB,KAAKe,UAErCnE,kBAGJ2D,OAAQ,SAACvB,EAAM+C,GACX,IAAAC,EAAAJ,EAGA,OAHA7C,EAAgBC,IAEhBgD,EAAQpF,KAACY,UAAUyE,QAAQjD,KACf,GACRpC,KAACY,UAAU0E,OAAOF,EAAO,GACzBpF,KAACa,OACMsE,GAAkBjD,EAAUE,IAC5B,IAEXgD,EAAQpF,KAACW,SAAS0E,QAAQjD,KACd,GACRpC,KAACW,SAAS2E,OAAOF,EAAO,GACxBpF,KAACa,OACMsE,GAAkBjD,EAAUE,IAC5B,KAIR,OAFH4C,EAAehF,KAACgB,SAASa,EAAmBO,EAAMpC,QAE/CsB,OAAuB0D,EAAa1D,KAAKqC,OAAOvB,EAAM+C,KACrDnF,KAACa,OACqD,IAA1BmE,EAAa1D,KAAKT,OAA9CmE,EAAa1D,KAAO,MACb,iBAcfiE,UAAW,SAACnD,EAAMoD,GACd,IAAArF,EAAAsF,EAAAlB,EAAAE,EAAAP,EAAAQ,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAA1C,EAAAC,EAAAoD,EAKA,cANcF,EAAoB5D,GAClCO,EAAgBC,GAEhB8B,KACAK,GAASvE,MAEHuE,EAAKU,OAAS,GAApB,CAGI,IAAAP,EAAA,EAAAG,GAAAxC,GAFAqD,EAAMnB,EAAKW,SAEXtE,WAAAqE,OAAAP,EAAAG,EAAAH,eAAuCtC,GAASoD,EAAkBpD,EAAMqD,IAASvB,EAAMd,KAAKqC,GAC5F,IAAAd,EAAA,EAAAG,GAAAxC,EAAAoD,EAAA/E,UAAAsE,OAAAN,EAAAG,EAAAH,eAAuCvC,GAASoD,EAAkBpD,EAAMqD,IAASvB,EAAMd,KAAKqC,GAc5F,IATkB,KAHlBhB,EAAO3C,EAAQM,EAAMsD,IAGbT,SACJR,KACGrC,EAAK/B,GAAKqF,EAAIrF,EAAIqF,EAAInF,OACrBkE,EAAKrB,KAAK,MACXhB,EAAK9B,GAAKoF,EAAIpF,EAAIoF,EAAIlF,QACrBiE,EAAKrB,KAAK,MACXqB,EAAKQ,OAAS,IACK,IAAfR,EAAKQ,OAAiBR,EAAKrB,KAAK,MAAUqB,GAAQ,QAE7DG,EAAA,EAAAG,EAAAN,EAAAQ,OAAAL,EAAAG,EAAAH,WAAuB,MAAAc,EAAA1E,SAAAb,GAAAmB,MACnBiD,EAAKnB,KAAKsC,EAAI1E,SAASb,GAAOmB,aAEtC4C,eAeJyB,YAAa,SAACvD,EAAMwD,EAAUJ,GAC1B,IAAArF,EAAAsF,EAAAlB,EAAAE,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAA1C,EAAAC,EAAAoD,EAIA,cAL0BF,EAAoB5D,GAC9CO,EAAgBC,GAEhBmC,GAASvE,MAEHuE,EAAKU,OAAS,GAApB,CAGI,IAAAP,EAAA,EAAAG,GAAAxC,GAFAqD,EAAMnB,EAAKW,SAEXtE,WAAAqE,OAAAP,EAAAG,EAAAH,eAAuCtC,GAASoD,EAAkBpD,EAAMqD,IAASG,EAASH,GAC1F,IAAAd,EAAA,EAAAG,GAAAxC,EAAAoD,EAAA/E,UAAAsE,OAAAN,EAAAG,EAAAH,eAAuCvC,GAASoD,EAAkBpD,EAAMqD,IAASG,EAASH,GAc1F,IATkB,KAHlBhB,EAAO3C,EAAQM,EAAMsD,IAGbT,SACJR,KACGrC,EAAK/B,GAAKqF,EAAIrF,EAAIqF,EAAInF,OACrBkE,EAAKrB,KAAK,MACXhB,EAAK9B,GAAKoF,EAAIpF,EAAIoF,EAAIlF,QACrBiE,EAAKrB,KAAK,MACXqB,EAAKQ,OAAS,IACK,IAAfR,EAAKQ,OAAiBR,EAAKrB,KAAK,MAAUqB,GAAQ,QAE7DG,EAAA,EAAAG,EAAAN,EAAAQ,OAAAL,EAAAG,EAAAH,WAAuB,MAAAc,EAAA1E,SAAAb,GAAAmB,MACnBiD,EAAKnB,KAAKsC,EAAI1E,SAASb,GAAOmB,MAEtC,OAAO,kBAGXK,IAAK,SAACkE,UACF7F,KAACmD,MAAM0C,gBAEX1C,MAAO,SAAC0C,GAEJ,IAAAC,EAAAL,EAAAlB,EAAAL,EAAAQ,EAAAC,EAAAoB,EAAAlB,EAAAC,EAAAzC,EAAAC,EAAA0C,EAAAU,EAAA,GAAmB,iBAATG,IAA2B,MAAAA,EAAAxF,GAAgB,MAAAwF,EAAAvF,GACjD,OAAON,KAACgG,KAAK,SAACP,GACV,IAAAK,EAAAC,EAAAD,GAAQ,EACR,IAAAC,KAAAF,EAAsBA,EAAME,KAAUN,EAAIM,KAAUD,GAAQ,UAC5DA,IAQR,IALA3D,EAAgB0D,GAEhB3B,KACAK,GAAQvE,MAEFuE,EAAKU,OAAS,GAApB,CAGI,IAAAP,EAAA,EAAAG,GAAAxC,GAFAqD,EAAMnB,EAAKW,SAEXtE,WAAAqE,OAAAP,EAAAG,EAAAH,IAAA,QACIoB,GAAQ,EACR,IAAAC,KAAAF,EAAsBA,EAAME,KAAUN,EAAIM,KAAUD,GAAQ,GAC1CA,GAAlB5B,EAAMd,KAAKqC,GACf,IAAAd,EAAA,EAAAG,GAAAxC,EAAAoD,EAAA/E,UAAAsE,OAAAN,EAAAG,EAAAH,IAAA,QACImB,GAAQ,EACR,IAAAC,KAAAF,EAAsBA,EAAME,KAAUN,EAAIM,KAAUD,GAAQ,GAC1CA,GAAlB5B,EAAMd,KAAKqC,GAIZ,OAFHT,EAAeU,EAAI1E,SAASa,EAAmBgE,EAAOH,KAEnDpE,MACCiD,EAAKnB,KAAK4B,EAAa1D,aAE/B4C,eAMJ+B,KAAM,SAACC,GACH,IAAA/F,EAAAoE,EAAA4B,EAAAzB,EAAAC,EAAAE,EAAAC,EAAAzC,EAAAC,EAAAoD,EAEA,IAFAnB,GAAQvE,MAEFuE,EAAKU,OAAS,GAApB,CAEI,IAAAP,EAAA,EAAAG,GAAAxC,GADAqD,EAAMnB,EAAKW,SACXtE,WAAAqE,OAAAP,EAAAG,EAAAH,iCAA4BwB,EAAQC,GACpC,IAAAxB,EAAA,EAAAG,GAAAxC,EAAAoD,EAAA/E,UAAAsE,OAAAN,EAAAG,EAAAH,iCAA2BuB,EAAQC,GAEnC,IAAAhG,KAAAuF,EAAA1E,SAA+B,MAAA0E,EAAA1E,SAAAb,GAAAmB,MAC3BiD,EAAKnB,KAAKsC,EAAI1E,SAASb,GAAOmB,aACtCtB,kBAGJgG,KAAM,SAACI,GACH,IAAAjG,EAAAoE,EAAA4B,EAAAjC,EAAAQ,EAAAC,EAAAE,EAAAC,EAAAzC,EAAAC,EAAAoD,EAGA,IAHAnB,GAAQvE,MACRkE,KAEMK,EAAKU,OAAS,GAApB,CAEI,IAAAP,EAAA,EAAAG,GAAAxC,GADAqD,EAAMnB,EAAKW,SACXtE,WAAAqE,OAAAP,EAAAG,EAAAH,iCAA4B0B,EAAWD,QAAA,IAAQjC,EAAMd,KAAK+C,GAC1D,IAAAxB,EAAA,EAAAG,GAAAxC,EAAAoD,EAAA/E,UAAAsE,OAAAN,EAAAG,EAAAH,iCAA2ByB,EAAWD,QAAA,IAAQjC,EAAMd,KAAK+C,GAEzD,IAAAhG,KAAAuF,EAAA1E,SAA+B,MAAA0E,EAAA1E,SAAAb,GAAAmB,MAC3BiD,EAAKnB,KAAKsC,EAAI1E,SAASb,GAAOmB,aACtC4C,eAGJmC,OAAQ,SAACD,GACL,IAAAE,SAAAA,EAAY,SAACC,GACT,IAAApG,EAAAqG,EAAApE,EAAAsC,EAAAC,EAAAE,EAAAC,EAAAzC,EAAAC,EAAAG,EAAAC,GAAA8D,EAAU,IAAIvG,GAASI,EAAGkG,EAAOlG,EAAGC,EAAGiG,EAAOjG,EAAGC,MAAOgG,EAAOhG,MAAOC,OAAQ+F,EAAO/F,OAAQC,YAAa8F,EAAO9F,eACzGI,KAAO,EACf,IAAAV,KAAAoG,EAAAvF,SAAkC,MAAAuF,EAAAvF,SAAAb,GAAAmB,OAC9BkF,EAAQxF,SAASb,GAAOmB,KAAOgF,EAAUC,EAAOvF,SAASb,GAAOmB,MAChEkF,EAAQ3F,MAAR,OAAAwB,EAAA,OAAAC,EAAAkE,EAAAxF,SAAAb,GAAAmB,MAAAgB,EAAAzB,UAAA,GAAAwB,EAAqD,GAEzD,IAAAqC,EAAA,EAAAG,GAAApC,EAAA8D,EAAA3F,WAAAqE,OAAAP,EAAAG,EAAAH,YAAsC,MAAA0B,IAAJ,mBAAAA,EAAkBA,EAAWhE,QAAA,KAC3DoE,EAAQ5F,UAAUwC,KAAKhB,GAC3B,IAAAuC,EAAA,EAAAG,GAAApC,EAAA6D,EAAA5F,UAAAsE,OAAAN,EAAAG,EAAAH,YAAqC,MAAAyB,IAAJ,mBAAAA,EAAkBA,EAAWhE,QAAA,KAC1DoE,EAAQ7F,SAASyC,KAAKhB,GAG1B,OADAoE,EAAQ3F,MAAQ2F,EAAQ5F,UAAUqE,OAASuB,EAAQ7F,SAASsE,OACzC,IAAhBuB,EAAQ3F,KAAe,KAAU2F,IAE9BxG,mBAGdyG,OAAQ,SAACL,UACLpG,KAACqG,OAAO,SAACF,WACL,mBAAAC,EAAIA,EAAWD,QAAA,kBAIvBO,MAAO,SAACR,GACJ,IAAA/F,EAAAoE,EAAAnE,EAEA,IAFAmE,GAAQvE,MAEFuE,EAAKU,OAAS,GAApB,CACI7E,EAAOmE,EAAKW,QACZgB,EAAOS,KAAKvG,KAEZ,IAAAD,KAAAC,EAAAY,SAAgC,MAAAZ,EAAAY,SAAAb,GAAAmB,MAC5BiD,EAAKnB,KAAKhD,EAAKY,SAASb,GAAOmB,aACvCtB,kBAGJ4G,OAAQ,WACJ,IAAAzG,EAAAoE,EAAAsC,EAAAC,EAAAC,EAAAC,EAAAtB,EAQA,IARAsB,EAAM,GAENH,EAAS,SAACI,GACN,IAAAvC,EAAArC,EAAA6E,EACA,IADAA,EAAM,GACoBxC,EAAArC,EAAA4E,EAAA5E,GAAA,EAAAqC,EAAA,EAAAA,EAAA,EAAArC,GAAA,IAAAqC,IAAAA,EAA1BwC,GAAO,aACPA,GAEJ3C,IAAW4C,MAAO,OAAQ7F,KAAMtB,KAAGiH,MAAO,IACpC1C,EAAKU,OAAS,GAApB,CAGI+B,IADAF,EAAcD,GADdnB,EAAMnB,EAAKW,SACc+B,QAEJ,KAAIvB,EAAIyB,MAAM,KAC1BL,EAAY,mBAGlBpB,EAAIpE,KAAKV,UAAUqE,OAAS,IAC3B+B,GACSF,EAAY,6BACZA,EAAY,OAAMpB,EAAIpE,KAAKV,UAAU,MAG/C8E,EAAIpE,KAAKX,SAASsE,OAAS,IAC1B+B,GACSF,EAAY,uBACZA,EAAY,OAAMpB,EAAIpE,KAAKX,SAAS,MAGjDoG,GAAW,EACX,IAAA5G,KAAAuF,EAAApE,KAAAN,SAAoC,MAAA0E,EAAApE,KAAAN,SAAAb,GAAAmB,OAChCyF,GAAW,EACXxC,EAAK6C,SAAUD,MAAOhH,EAAOmB,KAAMoE,EAAIpE,KAAKN,SAASb,GAAOmB,KAAM2F,MAAOvB,EAAIuB,MAAQ,KAEtFF,IAAcC,GAAUF,EAAY,iBAE3CE,KAneO","file":"quadtree.min.js","sourcesContent":["# quadtree-lib\n# ============\n#\n# **Quadtree-lib** is an easy to use, developer friendly quadtree library\n# which contains many helper methods to add, remove, iterate, filter, simulate\n# collisions over 2d elements and more.\n\n# #### UMD bundling related code\n((root, factory) ->\n if typeof define is 'function' and define.amd\n define [], factory\n else if typeof exports is 'object' and module.exports\n module.exports = factory()\n else\n root['Quadtree'] = factory()\n) @, (-> class Quadtree\n # The Quadtree class\n # -------------------\n\n # ### Constructor\n\n # The quadtree constructor accepts a single parameter object containing the following properties :\n # - width / length : dimensions of the quadtree. [ *mandatory* ]\n # - maxElements : the maximum number of elements before the leaf 'splits' into subtrees. [ *defaults to 1* ]\n # - x / y : these coordinates are used internally by the library to position subtrees. [ *internal use only* ]\n constructor: ({ @x, @y, @width, @height, @maxElements }) ->\n\n # An error is thrown when the width & length are not passed as constructor arguments.\n throw new Error 'Missing quadtree dimensions.' if not @width? or not @height?\n @x ?= 0\n @y ?= 0\n @maxElements ?= 1\n @contents = []\n @oversized = []\n @size = 0\n\n # Dimension & coordinates are checked, an error is thrown in case of bad input.\n throw new Error 'Dimensions must be positive integers.' if @width < 1 or @height < 1\n throw new Error 'Coordinates must be integers' if not Number.isInteger(@x) or not Number.isInteger(@y)\n throw new Error 'The maximum number of elements before a split must be a positive integer.' if @maxElements < 1\n\n that = @\n\n # The subtrees list, by position.\n @children = {\n # Northwest tree.\n NW:\n create: ->\n new Quadtree({\n x: that.x\n y: that.y\n width: Math.max (Math.floor that.width / 2), 1\n height: Math.max (Math.floor that.height / 2), 1\n maxElements: that.maxElements\n })\n tree: null\n # Northeast tree.\n NE:\n create: ->\n new Quadtree({\n x: that.x + Math.max (Math.floor that.width / 2), 1\n y: that.y\n width: Math.ceil that.width / 2\n height: Math.max (Math.floor that.height / 2), 1\n maxElements: that.maxElements\n })\n tree: null\n # Southwest tree.\n SW:\n create: ->\n new Quadtree({\n x: that.x\n y: that.y + Math.max (Math.floor that.height / 2), 1\n width: Math.max (Math.floor that.width / 2), 1\n height: Math.ceil that.height / 2\n maxElements: that.maxElements\n })\n tree: null\n # Southeast tree.\n SE:\n create: ->\n new Quadtree({\n x: that.x + Math.max (Math.floor that.width / 2), 1\n y: that.y + Math.max (Math.floor that.height / 2), 1\n width: Math.ceil that.width / 2\n height: Math.ceil that.height / 2\n maxElements: that.maxElements\n })\n tree: null\n }\n # Adding a getter which lazily creates the tree.\n for child of @children\n @children[child].get = ->\n if @tree? then @tree else @tree = @create(); @tree\n\n # ### Internal methods & vars\n\n # Retrieves the center coordinates of a rectangle.\n getCenter = (item) ->\n x: Math.floor((item.width ? 1) / 2) + item.x\n y: Math.floor((item.height ? 1) / 2) + item.y\n\n # Bounding box collision algorithm.\n boundingBoxCollision = (elt1, elt2) ->\n not(elt1.x >= elt2.x + (elt2.width ? 1) or\n elt1.x + (elt1.width ? 1) <= elt2.x or\n elt1.y >= elt2.y + (elt2.height ? 1) or\n elt1.y + (elt1.height ? 1) <= elt2.y)\n\n # Determines which subtree an element belongs to.\n calculateDirection = (element, tree) ->\n quadCenter = getCenter tree\n\n if element.x < quadCenter.x\n if element.y < quadCenter.y then 'NW'\n else 'SW'\n else\n if element.y < quadCenter.y then 'NE'\n else 'SE'\n\n # Validates a potential element of the tree.\n validateElement = (element) ->\n if not (typeof element is 'object')\n throw new Error 'Element must be an Object.'\n if not element.x? or not element.y?\n throw new Error 'Coordinates properties are missing.'\n if element?.width < 0 or element?.height < 0\n throw new Error 'Width and height must be positive integers.'\n\n # Returns splitted coordinates and dimensions.\n splitTree = (tree) ->\n leftWidth = Math.max (Math.floor tree.width / 2), 1\n rightWidth = Math.ceil tree.width / 2\n topHeight = Math.max (Math.floor tree.height / 2), 1\n bottomHeight = Math.ceil tree.height / 2\n NW:\n x: tree.x\n y: tree.y\n width: leftWidth\n height: topHeight\n NE:\n x: tree.x + leftWidth\n y: tree.y\n width: rightWidth\n height: topHeight\n SW:\n x: tree.x\n y: tree.y + topHeight\n width: leftWidth\n height: bottomHeight\n SE:\n x: tree.x + leftWidth\n y: tree.y + topHeight\n width: rightWidth\n height: bottomHeight\n\n # Determines wether an element fits into subtrees.\n fitting = (element, tree) ->\n where = []\n for direction, coordinates of splitTree tree when boundingBoxCollision element, coordinates\n where.push direction\n where\n\n # Add getters and setters for coordinates and dimensions properties in order to automatically reorganize the elements on change.\n observe = (item, tree) ->\n writeAccessors = (propName) ->\n item[\"_#{propName}\"] = item[propName]\n Object.defineProperty item, propName, {\n set: (val) ->\n tree.remove @, true\n @[\"_#{propName}\"] = val\n tree.push @\n get: ->\n @[\"_#{propName}\"]\n configurable: true\n }\n writeAccessors 'x'\n writeAccessors 'y'\n writeAccessors 'width'\n writeAccessors 'height'\n\n # Remove getters and setters and restore previous properties\n unobserve = (item) ->\n unwriteAccessors = (propName) ->\n if not item[\"_#{propName}\"]? then return\n delete item[propName]\n item[propName] = item[\"_#{propName}\"]\n delete item[\"_#{propName}\"]\n unwriteAccessors 'x'\n unwriteAccessors 'y'\n unwriteAccessors 'width'\n unwriteAccessors 'height'\n\n # ### Exposed methods\n\n # Removes all elements from the quadtree and restores it to pristine state.\n clear: ->\n @contents = []\n @oversized = []\n @size = 0\n for child of @children\n @children[child].tree = null\n\n # Add an element to the quadtree.\n # Elements can be observed to reorganize them into the quadtree automatically whenever their coordinates or dimensions are set (for ex. obj.x = ...).\n push: (item, doObserve) ->\n @pushAll([item], doObserve)\n\n # Push an array of elements.\n pushAll: (items, doObserve) ->\n for item in items\n validateElement item\n observe item, @ if doObserve\n\n fifo = [tree: @, elements: items]\n\n while fifo.length > 0\n { tree, elements } = fifo.shift()\n\n fifoCandidates = { NW: null, NE: null, SW: null, SE: null }\n\n for element in elements\n tree.size++\n\n fits = fitting element, tree\n\n if fits.length isnt 1 or tree.width is 1 or tree.height is 1\n tree.oversized.push element\n\n else if (tree.size - tree.oversized.length) <= tree.maxElements\n tree.contents.push element\n\n else\n direction = fits[0]\n relatedChild = tree.children[direction]\n fifoCandidates[direction] ?= { tree: relatedChild.get(), elements: [] }\n fifoCandidates[direction].elements.push(element)\n\n for content in tree.contents\n contentDir = (fitting content, tree)[0]\n fifoCandidates[contentDir] ?= { tree: tree.children[contentDir].get(), elements: [] }\n fifoCandidates[contentDir].elements.push(content)\n\n tree.contents = []\n\n for direction, candidate of fifoCandidates\n if candidate? then fifo.push candidate\n\n @\n\n # Removes an element from the quadtree.\n remove: (item, stillObserve) ->\n validateElement item\n\n index = @oversized.indexOf item\n if index > -1\n @oversized.splice index, 1\n @size--\n if not stillObserve then unobserve item\n return true\n\n index = @contents.indexOf item\n if index > -1\n @contents.splice index, 1\n @size--\n if not stillObserve then unobserve item\n return true\n\n relatedChild = @children[calculateDirection item, @]\n\n if relatedChild.tree? and relatedChild.tree.remove item, stillObserve\n @size--\n relatedChild.tree = null if relatedChild.tree.size is 0\n return true\n\n false\n\n # Returns an array of elements which collides with the `item` argument.\n # `item` being an object having x, y, width & height properties.\n\n # The default collision function is a basic bounding box algorithm.\n # You can change it by providing a function as a second argument.\n #```javascript\n #colliding({x: 10, y: 20}, function(element1, element2) {\n # return // Place predicate here //\n #})\n #```\n colliding: (item, collisionFunction = boundingBoxCollision) ->\n validateElement item\n\n items = []\n fifo = [@]\n\n while fifo.length > 0\n top = fifo.shift()\n\n for elt in top.oversized when elt isnt item and collisionFunction item, elt then items.push elt\n for elt in top.contents when elt isnt item and collisionFunction item, elt then items.push elt\n\n fits = fitting item, top\n\n # Special case for elements located outside of the quadtree on the right / bottom side\n if fits.length is 0\n fits = []\n if item.x >= top.x + top.width\n fits.push 'NE'\n if item.y >= top.y + top.height\n fits.push 'SW'\n if fits.length > 0\n if fits.length is 1 then fits.push 'SE' else fits = ['SE']\n\n for child in fits when top.children[child].tree?\n fifo.push top.children[child].tree\n\n items\n\n # Performs an action on elements which collides with the `item` argument.\n # `item` being an object having x, y, width & height properties.\n\n # The default collision function is a basic bounding box algorithm.\n # You can change it by providing a function as a third argument.\n #```javascript\n #onCollision(\n # {x: 10, y: 20},\n # function(item) { /* stuff */ },\n # function(element1, element2) {\n # return // Place predicate here //\n #})\n #```\n onCollision: (item, callback, collisionFunction = boundingBoxCollision) ->\n validateElement item\n\n fifo = [@]\n\n while fifo.length > 0\n top = fifo.shift()\n\n for elt in top.oversized when elt isnt item and collisionFunction item, elt then callback elt\n for elt in top.contents when elt isnt item and collisionFunction item, elt then callback elt\n\n fits = fitting item, top\n\n # Special case for elements located outside of the quadtree on the right / bottom side\n if fits.length is 0\n fits = []\n if item.x >= top.x + top.width\n fits.push 'NE'\n if item.y >= top.y + top.height\n fits.push 'SW'\n if fits.length > 0\n if fits.length is 1 then fits.push 'SE' else fits = ['SE']\n\n for child in fits when top.children[child].tree?\n fifo.push top.children[child].tree\n\n return null\n\n # Alias of `where`.\n get: (query) ->\n @where query\n # Returns an array of elements that match the `query` argument.\n where: (query) ->\n # Naïve parsing (missing coordinates)\n if typeof query is 'object' and (not query.x? or not query.y?)\n return @find (elt) ->\n check = true\n for key of query when query[key] isnt elt[key] then check = false\n check\n\n # Optimised parsing\n validateElement query\n\n items = []\n fifo = [@]\n\n while fifo.length > 0\n top = fifo.shift()\n\n for elt in top.oversized\n check = true\n for key of query when query[key] isnt elt[key] then check = false\n items.push elt if check\n for elt in top.contents\n check = true\n for key of query when query[key] isnt elt[key] then check = false\n items.push elt if check\n\n relatedChild = top.children[calculateDirection query, top]\n\n if relatedChild.tree?\n fifo.push relatedChild.tree\n\n items\n\n # For each element of the quadtree, performs the `action` function.\n #```javascript\n #quad.each(function(item) { console.log(item) })\n #```\n each: (action) ->\n fifo = [@]\n\n while fifo.length > 0\n top = fifo.shift()\n for i in top.oversized then action?(i)\n for i in top.contents then action?(i)\n\n for child of top.children when top.children[child].tree?\n fifo.push top.children[child].tree\n @\n\n # Returns an array of elements which validates the predicate.\n find: (predicate) ->\n fifo = [@]\n items = []\n\n while fifo.length > 0\n top = fifo.shift()\n for i in top.oversized when predicate?(i) then items.push i\n for i in top.contents when predicate?(i) then items.push i\n\n for child of top.children when top.children[child].tree?\n fifo.push top.children[child].tree\n items\n\n # Returns a **cloned** `Quadtree` object which contains only the elements that validate the predicate.\n filter: (predicate) ->\n deepclone = (target) ->\n copycat = new Quadtree x: target.x, y: target.y, width: target.width, height: target.height, maxElements: target.maxElements\n copycat.size = 0\n for child of target.children when target.children[child].tree?\n copycat.children[child].tree = deepclone target.children[child].tree\n copycat.size += copycat.children[child].tree?.size ? 0\n\n for item in target.oversized when not predicate? or predicate?(item)\n copycat.oversized.push item\n for item in target.contents when not predicate? or predicate?(item)\n copycat.contents.push item\n\n copycat.size += copycat.oversized.length + copycat.contents.length\n if copycat.size is 0 then null else copycat\n\n deepclone @\n\n # Opposite of filter.\n reject: (predicate) ->\n @filter (i) ->\n not predicate?(i)\n\n # Visits each tree & subtree contained in the `Quadtree` object.\n # For each node, performs the `action` function, inside which `this` is bound to the node tree object.\n visit: (action) ->\n fifo = [@]\n\n while fifo.length > 0\n that = fifo.shift()\n action.bind(that)()\n\n for child of that.children when that.children[child].tree?\n fifo.push that.children[child].tree\n @\n\n # Pretty printing function.\n pretty: ->\n str = ''\n\n indent = (level) ->\n res = ''\n res += ' ' for times in [level...0]\n res\n\n fifo = [{ label: 'ROOT', tree: @, level: 0 }]\n while fifo.length > 0\n top = fifo.shift()\n indentation = indent(top.level)\n str += \"\"\"\n #{indentation}| #{top.label}\n #{indentation}| ------------\\n\n \"\"\"\n\n if top.tree.oversized.length > 0\n str += \"\"\"\n #{indentation}| * Oversized elements *\n #{indentation}| #{top.tree.oversized}\\n\n \"\"\"\n\n if top.tree.contents.length > 0\n str += \"\"\"\n #{indentation}| * Leaf content *\n #{indentation}| #{top.tree.contents}\\n\n \"\"\"\n\n isParent = false\n for child of top.tree.children when top.tree.children[child].tree?\n isParent = true\n fifo.unshift { label: child, tree: top.tree.children[child].tree, level: top.level + 1 }\n\n if isParent then str += \"#{indentation}└──┐\\n\"\n\n str\n)\n"]} \ No newline at end of file diff --git a/docs/demo/quadtree.min.js b/docs/demo/quadtree.min.js index 376da09..b1590a2 100644 --- a/docs/demo/quadtree.min.js +++ b/docs/demo/quadtree.min.js @@ -1,2 +1,2 @@ -!function(e,t){"function"==typeof define&&define.amd?define([],t):"object"==typeof exports&&module.exports?module.exports=t():e.Quadtree=t()}(this,function(){return function(){function e(t){var n,i;if(this.x=t.x,this.y=t.y,this.width=t.width,this.height=t.height,this.maxElements=t.maxElements,null==this.width||null==this.height)throw new Error("Missing quadtree dimensions.");if(null==this.x&&(this.x=0),null==this.y&&(this.y=0),null==this.maxElements&&(this.maxElements=1),this.contents=[],this.oversized=[],this.size=0,this.width<1||this.height<1)throw new Error("Dimensions must be positive integers.");if(!Number.isInteger(this.x)||!Number.isInteger(this.y))throw new Error("Coordinates must be integers");if(this.maxElements<1)throw new Error("The maximum number of elements before a split must be a positive integer.");i=this,this.children={NW:{create:function(){return new e({x:i.x,y:i.y,width:Math.max(Math.floor(i.width/2),1),height:Math.max(Math.floor(i.height/2),1),maxElements:i.maxElements})},tree:null},NE:{create:function(){return new e({x:i.x+Math.max(Math.floor(i.width/2),1),y:i.y,width:Math.ceil(i.width/2),height:Math.max(Math.floor(i.height/2),1),maxElements:i.maxElements})},tree:null},SW:{create:function(){return new e({x:i.x,y:i.y+Math.max(Math.floor(i.height/2),1),width:Math.max(Math.floor(i.width/2),1),height:Math.ceil(i.height/2),maxElements:i.maxElements})},tree:null},SE:{create:function(){return new e({x:i.x+Math.max(Math.floor(i.width/2),1),y:i.y+Math.max(Math.floor(i.height/2),1),width:Math.ceil(i.width/2),height:Math.ceil(i.height/2),maxElements:i.maxElements})},tree:null}};for(n in this.children)this.children[n].get=function(){return null!=this.tree?this.tree:(this.tree=this.create(),this.tree)}}var t,n,i,r,h,l,o,s;return r=function(e){var t,n;return{x:Math.floor((null!=(t=e.width)?t:1)/2)+e.x,y:Math.floor((null!=(n=e.height)?n:1)/2)+e.y}},t=function(e,t){var n,i,r,h;return!(e.x>=t.x+(null!=(n=t.width)?n:1)||e.x+(null!=(i=e.width)?i:1)<=t.x||e.y>=t.y+(null!=(r=t.height)?r:1)||e.y+(null!=(h=e.height)?h:1)<=t.y)},n=function(e,t){var n;return n=r(t),e.x0;){for(E=c.shift(),b=E.tree,f=E.elements,d={NW:null,NE:null,SW:null,SE:null},m=0,v=f.length;m-1?(this.oversized.splice(i,1),this.size--,t||o(e),!0):(i=this.contents.indexOf(e))>-1?(this.contents.splice(i,1),this.size--,t||o(e),!0):(r=this.children[n(e,this)],!(null==r.tree||!r.tree.remove(e,t))&&(this.size--,0===r.tree.size&&(r.tree=null),!0))},e.prototype.colliding=function(e,n){var r,h,l,o,u,f,c,d,a,g,p,m,x,y;for(null==n&&(n=t),s(e),u=[],l=[this];l.length>0;){for(y=l.shift(),m=y.oversized,f=0,a=m.length;f=y.x+y.width&&o.push("NE"),e.y>=y.y+y.height&&o.push("SW"),o.length>0&&(1===o.length?o.push("SE"):o=["SE"])),d=0,p=o.length;d0;){for(y=o.shift(),m=y.oversized,f=0,a=m.length;f=y.x+y.width&&u.push("NE"),e.y>=y.y+y.height&&u.push("SW"),u.length>0&&(1===u.length?u.push("SE"):u=["SE"])),d=0,p=u.length;d0;){for(p=r.shift(),d=p.oversized,l=0,f=d.length;l0;){for(f=n.shift(),s=f.oversized,r=0,l=s.length;r0;){for(c=n.shift(),u=c.oversized,h=0,o=u.length;h0;){i=n.shift(),e.bind(i)();for(t in i.children)null!=i.children[t].tree&&n.push(i.children[t].tree)}return this},e.prototype.pretty=function(){var e,t,n,i,r,h,l;for(h="",n=function(e){var t,n,i;for(i="",t=n=e;n<=0?t<0:t>0;n<=0?++t:--t)i+=" ";return i},t=[{label:"ROOT",tree:this,level:0}];t.length>0;){l=t.shift(),i=n(l.level),h+=i+"| "+l.label+"\n"+i+"| ------------\n",l.tree.oversized.length>0&&(h+=i+"| * Oversized elements *\n"+i+"| "+l.tree.oversized+"\n"),l.tree.contents.length>0&&(h+=i+"| * Leaf content *\n"+i+"| "+l.tree.contents+"\n"),r=!1;for(e in l.tree.children)null!=l.tree.children[e].tree&&(r=!0,t.unshift({label:e,tree:l.tree.children[e].tree,level:l.level+1}));r&&(h+=i+"└──┐\n")}return h},e}()}); +!function(e,t){"function"==typeof define&&define.amd?define([],t):"object"==typeof exports&&module.exports?module.exports=t():e.Quadtree=t()}(this,function(){return function(){function e(t){var n,i;if(this.x=t.x,this.y=t.y,this.width=t.width,this.height=t.height,this.maxElements=t.maxElements,null==this.width||null==this.height)throw new Error("Missing quadtree dimensions.");if(null==this.x&&(this.x=0),null==this.y&&(this.y=0),null==this.maxElements&&(this.maxElements=1),this.contents=[],this.oversized=[],this.size=0,this.width<1||this.height<1)throw new Error("Dimensions must be positive integers.");if(!Number.isInteger(this.x)||!Number.isInteger(this.y))throw new Error("Coordinates must be integers");if(this.maxElements<1)throw new Error("The maximum number of elements before a split must be a positive integer.");i=this,this.children={NW:{create:function(){return new e({x:i.x,y:i.y,width:Math.max(Math.floor(i.width/2),1),height:Math.max(Math.floor(i.height/2),1),maxElements:i.maxElements})},tree:null},NE:{create:function(){return new e({x:i.x+Math.max(Math.floor(i.width/2),1),y:i.y,width:Math.ceil(i.width/2),height:Math.max(Math.floor(i.height/2),1),maxElements:i.maxElements})},tree:null},SW:{create:function(){return new e({x:i.x,y:i.y+Math.max(Math.floor(i.height/2),1),width:Math.max(Math.floor(i.width/2),1),height:Math.ceil(i.height/2),maxElements:i.maxElements})},tree:null},SE:{create:function(){return new e({x:i.x+Math.max(Math.floor(i.width/2),1),y:i.y+Math.max(Math.floor(i.height/2),1),width:Math.ceil(i.width/2),height:Math.ceil(i.height/2),maxElements:i.maxElements})},tree:null}};for(n in this.children)this.children[n].get=function(){return null!=this.tree?this.tree:(this.tree=this.create(),this.tree)}}var t,n,i,r,h,l,o,s;return r=function(e){var t,n;return{x:Math.floor((null!=(t=e.width)?t:1)/2)+e.x,y:Math.floor((null!=(n=e.height)?n:1)/2)+e.y}},t=function(e,t){var n,i,r,h;return!(e.x>=t.x+(null!=(n=t.width)?n:1)||e.x+(null!=(i=e.width)?i:1)<=t.x||e.y>=t.y+(null!=(r=t.height)?r:1)||e.y+(null!=(h=e.height)?h:1)<=t.y)},n=function(e,t){var n;return n=r(t),e.x0;){for(b=(E=c.shift()).tree,d={NW:null,NE:null,SW:null,SE:null},m=0,v=(f=E.elements).length;m-1?(this.oversized.splice(i,1),this.size--,t||o(e),!0):(i=this.contents.indexOf(e))>-1?(this.contents.splice(i,1),this.size--,t||o(e),!0):!(null==(r=this.children[n(e,this)]).tree||!r.tree.remove(e,t)||(this.size--,0===r.tree.size&&(r.tree=null),0))},e.prototype.colliding=function(e,n){var r,h,l,o,u,f,c,d,a,g,p,m,x,y;for(null==n&&(n=t),s(e),u=[],l=[this];l.length>0;){for(f=0,a=(m=(y=l.shift()).oversized).length;f=y.x+y.width&&o.push("NE"),e.y>=y.y+y.height&&o.push("SW"),o.length>0&&(1===o.length?o.push("SE"):o=["SE"])),d=0,p=o.length;d0;){for(f=0,a=(m=(y=o.shift()).oversized).length;f=y.x+y.width&&u.push("NE"),e.y>=y.y+y.height&&u.push("SW"),u.length>0&&(1===u.length?u.push("SE"):u=["SE"])),d=0,p=u.length;d0;){for(l=0,f=(d=(p=r.shift()).oversized).length;l0;){for(r=0,l=(s=(f=n.shift()).oversized).length;r0;){for(h=0,o=(u=(c=n.shift()).oversized).length;h0;){i=n.shift(),e.bind(i)();for(t in i.children)null!=i.children[t].tree&&n.push(i.children[t].tree)}return this},e.prototype.pretty=function(){var e,t,n,i,r,h,l;for(h="",n=function(e){var t,n,i;for(i="",t=n=e;n<=0?t<0:t>0;n<=0?++t:--t)i+=" ";return i},t=[{label:"ROOT",tree:this,level:0}];t.length>0;){h+=(i=n((l=t.shift()).level))+"| "+l.label+"\n"+i+"| ------------\n",l.tree.oversized.length>0&&(h+=i+"| * Oversized elements *\n"+i+"| "+l.tree.oversized+"\n"),l.tree.contents.length>0&&(h+=i+"| * Leaf content *\n"+i+"| "+l.tree.contents+"\n"),r=!1;for(e in l.tree.children)null!=l.tree.children[e].tree&&(r=!0,t.unshift({label:e,tree:l.tree.children[e].tree,level:l.level+1}));r&&(h+=i+"└──┐\n")}return h},e}()}); //# sourceMappingURL=quadtree.min.js.map diff --git a/docs/demo/quadtree.min.js.map b/docs/demo/quadtree.min.js.map index 7c008ca..4d70253 100644 --- a/docs/demo/quadtree.min.js.map +++ b/docs/demo/quadtree.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["quadtree.coffee"],"names":["root","factory","define","amd","exports","module","this","Quadtree","arg","child","that","x","y","width","height","maxElements","Error","contents","oversized","size","Number","isInteger","children","NW","create","Math","max","floor","tree","NE","ceil","SW","SE","get","boundingBoxCollision","calculateDirection","fitting","getCenter","observe","splitTree","unobserve","validateElement","item","ref","ref1","elt1","elt2","ref2","ref3","element","quadCenter","bottomHeight","leftWidth","rightWidth","topHeight","coordinates","direction","where","push","writeAccessors","propName","Object","defineProperty","set","val","remove","configurable","unwriteAccessors","clear","results","doObserve","pushAll","items","candidate","content","contentDir","elements","fifo","fifoCandidates","fits","j","k","l","len","len1","len2","relatedChild","length","shift","stillObserve","index","indexOf","splice","colliding","collisionFunction","elt","top","onCollision","callback","query","check","key","find","each","action","i","predicate","filter","deepclone","target","copycat","reject","visit","bind","pretty","indent","indentation","isParent","str","level","res","label","unshift"],"mappings":"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","file":"quadtree.min.js","sourcesContent":["# quadtree-lib\n# ============\n#\n# **Quadtree-lib** is an easy to use, developer friendly quadtree library\n# which contains many helper methods to add, remove, iterate, filter, simulate\n# collisions over 2d elements and more.\n\n# #### UMD bundling related code\n((root, factory) ->\n if typeof define is 'function' and define.amd\n define [], factory\n else if typeof exports is 'object' and module.exports\n module.exports = factory()\n else\n root['Quadtree'] = factory()\n) @, (-> class Quadtree\n # The Quadtree class\n # -------------------\n\n # ### Constructor\n\n # The quadtree constructor accepts a single parameter object containing the following properties :\n # - width / length : dimensions of the quadtree. [ *mandatory* ]\n # - maxElements : the maximum number of elements before the leaf 'splits' into subtrees. [ *defaults to 1* ]\n # - x / y : these coordinates are used internally by the library to position subtrees. [ *internal use only* ]\n constructor: ({ @x, @y, @width, @height, @maxElements }) ->\n\n # An error is thrown when the width & length are not passed as constructor arguments.\n throw new Error 'Missing quadtree dimensions.' if not @width? or not @height?\n @x ?= 0\n @y ?= 0\n @maxElements ?= 1\n @contents = []\n @oversized = []\n @size = 0\n\n # Dimension & coordinates are checked, an error is thrown in case of bad input.\n throw new Error 'Dimensions must be positive integers.' if @width < 1 or @height < 1\n throw new Error 'Coordinates must be integers' if not Number.isInteger(@x) or not Number.isInteger(@y)\n throw new Error 'The maximum number of elements before a split must be a positive integer.' if @maxElements < 1\n\n that = @\n\n # The subtrees list, by position.\n @children = {\n # Northwest tree.\n NW:\n create: ->\n new Quadtree({\n x: that.x\n y: that.y\n width: Math.max (Math.floor that.width / 2), 1\n height: Math.max (Math.floor that.height / 2), 1\n maxElements: that.maxElements\n })\n tree: null\n # Northeast tree.\n NE:\n create: ->\n new Quadtree({\n x: that.x + Math.max (Math.floor that.width / 2), 1\n y: that.y\n width: Math.ceil that.width / 2\n height: Math.max (Math.floor that.height / 2), 1\n maxElements: that.maxElements\n })\n tree: null\n # Southwest tree.\n SW:\n create: ->\n new Quadtree({\n x: that.x\n y: that.y + Math.max (Math.floor that.height / 2), 1\n width: Math.max (Math.floor that.width / 2), 1\n height: Math.ceil that.height / 2\n maxElements: that.maxElements\n })\n tree: null\n # Southeast tree.\n SE:\n create: ->\n new Quadtree({\n x: that.x + Math.max (Math.floor that.width / 2), 1\n y: that.y + Math.max (Math.floor that.height / 2), 1\n width: Math.ceil that.width / 2\n height: Math.ceil that.height / 2\n maxElements: that.maxElements\n })\n tree: null\n }\n # Adding a getter which lazily creates the tree.\n for child of @children\n @children[child].get = ->\n if @tree? then @tree else @tree = @create(); @tree\n\n # ### Internal methods & vars\n\n # Retrieves the center coordinates of a rectangle.\n getCenter = (item) ->\n x: Math.floor((item.width ? 1) / 2) + item.x\n y: Math.floor((item.height ? 1) / 2) + item.y\n\n # Bounding box collision algorithm.\n boundingBoxCollision = (elt1, elt2) ->\n not(elt1.x >= elt2.x + (elt2.width ? 1) or\n elt1.x + (elt1.width ? 1) <= elt2.x or\n elt1.y >= elt2.y + (elt2.height ? 1) or\n elt1.y + (elt1.height ? 1) <= elt2.y)\n\n # Determines which subtree an element belongs to.\n calculateDirection = (element, tree) ->\n quadCenter = getCenter tree\n\n if element.x < quadCenter.x\n if element.y < quadCenter.y then 'NW'\n else 'SW'\n else\n if element.y < quadCenter.y then 'NE'\n else 'SE'\n\n # Validates a potential element of the tree.\n validateElement = (element) ->\n if not (typeof element is 'object')\n throw new Error 'Element must be an Object.'\n if not element.x? or not element.y?\n throw new Error 'Coordinates properties are missing.'\n if element?.width < 0 or element?.height < 0\n throw new Error 'Width and height must be positive integers.'\n\n # Returns splitted coordinates and dimensions.\n splitTree = (tree) ->\n leftWidth = Math.max (Math.floor tree.width / 2), 1\n rightWidth = Math.ceil tree.width / 2\n topHeight = Math.max (Math.floor tree.height / 2), 1\n bottomHeight = Math.ceil tree.height / 2\n NW:\n x: tree.x\n y: tree.y\n width: leftWidth\n height: topHeight\n NE:\n x: tree.x + leftWidth\n y: tree.y\n width: rightWidth\n height: topHeight\n SW:\n x: tree.x\n y: tree.y + topHeight\n width: leftWidth\n height: bottomHeight\n SE:\n x: tree.x + leftWidth\n y: tree.y + topHeight\n width: rightWidth\n height: bottomHeight\n\n # Determines wether an element fits into subtrees.\n fitting = (element, tree) ->\n where = []\n for direction, coordinates of splitTree tree when boundingBoxCollision element, coordinates\n where.push direction\n where\n\n # Add getters and setters for coordinates and dimensions properties in order to automatically reorganize the elements on change.\n observe = (item, tree) ->\n writeAccessors = (propName) ->\n item[\"_#{propName}\"] = item[propName]\n Object.defineProperty item, propName, {\n set: (val) ->\n tree.remove @, true\n @[\"_#{propName}\"] = val\n tree.push @\n get: ->\n @[\"_#{propName}\"]\n configurable: true\n }\n writeAccessors 'x'\n writeAccessors 'y'\n writeAccessors 'width'\n writeAccessors 'height'\n\n # Remove getters and setters and restore previous properties\n unobserve = (item) ->\n unwriteAccessors = (propName) ->\n if not item[\"_#{propName}\"]? then return\n delete item[propName]\n item[propName] = item[\"_#{propName}\"]\n delete item[\"_#{propName}\"]\n unwriteAccessors 'x'\n unwriteAccessors 'y'\n unwriteAccessors 'width'\n unwriteAccessors 'height'\n\n # ### Exposed methods\n\n # Removes all elements from the quadtree and restores pristine state.\n clear: ->\n @contents = []\n @oversized = []\n @size = 0\n for child of @children\n @children[child].tree = null\n\n # Add an element to the quadtree.\n # Elements can be observed to reorganize them into the quadtree automatically whenever their coordinates or dimensions are set (for ex. obj.x = ...).\n push: (item, doObserve) ->\n @pushAll([item], doObserve)\n\n # Push an array of elements.\n pushAll: (items, doObserve) ->\n for item in items\n validateElement item\n observe item, @ if doObserve\n\n fifo = [tree: @, elements: items]\n\n while fifo.length > 0\n { tree, elements } = fifo.shift()\n\n fifoCandidates = { NW: null, NE: null, SW: null, SE: null }\n\n for element in elements\n tree.size++\n\n fits = fitting element, tree\n\n if fits.length isnt 1 or tree.width is 1 or tree.height is 1\n tree.oversized.push element\n\n else if (tree.size - tree.oversized.length) <= tree.maxElements\n tree.contents.push element\n\n else\n direction = fits[0]\n relatedChild = tree.children[direction]\n fifoCandidates[direction] ?= { tree: relatedChild.get(), elements: [] }\n fifoCandidates[direction].elements.push(element)\n\n for content in tree.contents\n contentDir = (fitting content, tree)[0]\n fifoCandidates[contentDir] ?= { tree: tree.children[contentDir].get(), elements: [] }\n fifoCandidates[contentDir].elements.push(content)\n\n tree.contents = []\n\n for direction, candidate of fifoCandidates\n if candidate? then fifo.push candidate\n\n @\n\n # Removes an element from the quadtree.\n remove: (item, stillObserve) ->\n validateElement item\n\n index = @oversized.indexOf item\n if index > -1\n @oversized.splice index, 1\n @size--\n if not stillObserve then unobserve item\n return true\n\n index = @contents.indexOf item\n if index > -1\n @contents.splice index, 1\n @size--\n if not stillObserve then unobserve item\n return true\n\n relatedChild = @children[calculateDirection item, @]\n\n if relatedChild.tree? and relatedChild.tree.remove item, stillObserve\n @size--\n relatedChild.tree = null if relatedChild.tree.size is 0\n return true\n\n false\n\n # Returns an array of elements which collides with the `item` argument.\n # `item` being an object having x, y, width & height properties.\n\n # The default collision function is a basic bounding box algorithm.\n # You can change it by providing a function as a second argument.\n #```javascript\n #colliding({x: 10, y: 20}, function(element1, element2) {\n # return // Place predicate here //\n #})\n #```\n colliding: (item, collisionFunction = boundingBoxCollision) ->\n validateElement item\n\n items = []\n fifo = [@]\n\n while fifo.length > 0\n top = fifo.shift()\n\n for elt in top.oversized when elt isnt item and collisionFunction item, elt then items.push elt\n for elt in top.contents when elt isnt item and collisionFunction item, elt then items.push elt\n\n fits = fitting item, top\n\n # Special case for elements located outside of the quadtree on the right / bottom side\n if fits.length is 0\n fits = []\n if item.x >= top.x + top.width\n fits.push 'NE'\n if item.y >= top.y + top.height\n fits.push 'SW'\n if fits.length > 0\n if fits.length is 1 then fits.push 'SE' else fits = ['SE']\n\n for child in fits when top.children[child].tree?\n fifo.push top.children[child].tree\n\n items\n\n # Performs an action on elements which collides with the `item` argument.\n # `item` being an object having x, y, width & height properties.\n\n # The default collision function is a basic bounding box algorithm.\n # You can change it by providing a function as a third argument.\n #```javascript\n #onCollision(\n # {x: 10, y: 20},\n # function(item) { /* stuff */ },\n # function(element1, element2) {\n # return // Place predicate here //\n #})\n #```\n onCollision: (item, callback, collisionFunction = boundingBoxCollision) ->\n validateElement item\n\n fifo = [@]\n\n while fifo.length > 0\n top = fifo.shift()\n\n for elt in top.oversized when elt isnt item and collisionFunction item, elt then callback elt\n for elt in top.contents when elt isnt item and collisionFunction item, elt then callback elt\n\n fits = fitting item, top\n\n # Special case for elements located outside of the quadtree on the right / bottom side\n if fits.length is 0\n fits = []\n if item.x >= top.x + top.width\n fits.push 'NE'\n if item.y >= top.y + top.height\n fits.push 'SW'\n if fits.length > 0\n if fits.length is 1 then fits.push 'SE' else fits = ['SE']\n\n for child in fits when top.children[child].tree?\n fifo.push top.children[child].tree\n\n return null\n\n # Alias of `where`.\n get: (query) ->\n @where query\n # Returns an array of elements that match the `query` argument.\n where: (query) ->\n # Naïve parsing (missing coordinates)\n if typeof query is 'object' and (not query.x? or not query.y?)\n return @find (elt) ->\n check = true\n for key of query when query[key] isnt elt[key] then check = false\n check\n\n # Optimised parsing\n validateElement query\n\n items = []\n fifo = [@]\n\n while fifo.length > 0\n top = fifo.shift()\n\n for elt in top.oversized\n check = true\n for key of query when query[key] isnt elt[key] then check = false\n items.push elt if check\n for elt in top.contents\n check = true\n for key of query when query[key] isnt elt[key] then check = false\n items.push elt if check\n\n relatedChild = top.children[calculateDirection query, top]\n\n if relatedChild.tree?\n fifo.push relatedChild.tree\n\n items\n\n # For each element of the quadtree, performs the `action` function.\n #```javascript\n #quad.each(function(item) { console.log(item) })\n #```\n each: (action) ->\n fifo = [@]\n\n while fifo.length > 0\n top = fifo.shift()\n for i in top.oversized then action?(i)\n for i in top.contents then action?(i)\n\n for child of top.children when top.children[child].tree?\n fifo.push top.children[child].tree\n @\n\n # Returns an array of elements which validates the predicate.\n find: (predicate) ->\n fifo = [@]\n items = []\n\n while fifo.length > 0\n top = fifo.shift()\n for i in top.oversized when predicate?(i) then items.push i\n for i in top.contents when predicate?(i) then items.push i\n\n for child of top.children when top.children[child].tree?\n fifo.push top.children[child].tree\n items\n\n # Returns a **cloned** `Quadtree` object which contains only the elements that validate the predicate.\n filter: (predicate) ->\n deepclone = (target) ->\n copycat = new Quadtree x: target.x, y: target.y, width: target.width, height: target.height, maxElements: target.maxElements\n copycat.size = 0\n for child of target.children when target.children[child].tree?\n copycat.children[child].tree = deepclone target.children[child].tree\n copycat.size += copycat.children[child].tree?.size ? 0\n\n for item in target.oversized when not predicate? or predicate?(item)\n copycat.oversized.push item\n for item in target.contents when not predicate? or predicate?(item)\n copycat.contents.push item\n\n copycat.size += copycat.oversized.length + copycat.contents.length\n if copycat.size is 0 then null else copycat\n\n deepclone @\n\n # Opposite of filter.\n reject: (predicate) ->\n @filter (i) ->\n not predicate?(i)\n\n # Visits each tree & subtree contained in the `Quadtree` object.\n # For each node, performs the `action` function, inside which `this` is bound to the node tree object.\n visit: (action) ->\n fifo = [@]\n\n while fifo.length > 0\n that = fifo.shift()\n action.bind(that)()\n\n for child of that.children when that.children[child].tree?\n fifo.push that.children[child].tree\n @\n\n # Pretty printing function.\n pretty: ->\n str = ''\n\n indent = (level) ->\n res = ''\n res += ' ' for times in [level...0]\n res\n\n fifo = [{ label: 'ROOT', tree: @, level: 0 }]\n while fifo.length > 0\n top = fifo.shift()\n indentation = indent(top.level)\n str += \"\"\"\n #{indentation}| #{top.label}\n #{indentation}| ------------\\n\n \"\"\"\n\n if top.tree.oversized.length > 0\n str += \"\"\"\n #{indentation}| * Oversized elements *\n #{indentation}| #{top.tree.oversized}\\n\n \"\"\"\n\n if top.tree.contents.length > 0\n str += \"\"\"\n #{indentation}| * Leaf content *\n #{indentation}| #{top.tree.contents}\\n\n \"\"\"\n\n isParent = false\n for child of top.tree.children when top.tree.children[child].tree?\n isParent = true\n fifo.unshift { label: child, tree: top.tree.children[child].tree, level: top.level + 1 }\n\n if isParent then str += \"#{indentation}└──┐\\n\"\n\n str\n)\n"]} \ No newline at end of file +{"version":3,"sources":["quadtree.coffee"],"names":["root","factory","define","amd","exports","module","this","Quadtree","arg","child","that","x","y","width","height","maxElements","Error","contents","oversized","size","Number","isInteger","children","NW","create","Math","max","floor","tree","NE","ceil","SW","SE","get","boundingBoxCollision","calculateDirection","fitting","getCenter","observe","splitTree","unobserve","validateElement","item","ref","ref1","elt1","elt2","ref2","ref3","element","quadCenter","bottomHeight","leftWidth","rightWidth","topHeight","coordinates","direction","where","push","writeAccessors","propName","Object","defineProperty","set","val","remove","configurable","unwriteAccessors","clear","results","doObserve","pushAll","items","candidate","content","contentDir","elements","fifo","fifoCandidates","fits","j","k","l","len","len1","len2","relatedChild","length","shift","stillObserve","index","indexOf","splice","colliding","collisionFunction","elt","top","onCollision","callback","query","check","key","find","each","action","i","predicate","filter","deepclone","target","copycat","reject","visit","bind","pretty","indent","indentation","isParent","str","level","res","label","unshift"],"mappings":"CAQA,SAAEA,EAAMC,GACgB,mBAAVC,QAAyBA,OAAOC,IACtCD,UAAWD,GACW,iBAAXG,SAAwBC,OAAOD,QAC1CC,OAAOD,QAAUH,IAEjBD,EAAK,SAAcC,IAN3B,CAOEK,KAAG,kBAAU,WAUE,SAAAC,EAACC,GAGV,IAAAC,EAAAC,EAAA,GAHYJ,KAACK,EAAAH,EAAAG,EAAGL,KAACM,EAAAJ,EAAAI,EAAGN,KAACO,MAAAL,EAAAK,MAAOP,KAACQ,OAAAN,EAAAM,OAAQR,KAACS,YAAAP,EAAAO,YAGgB,MAAAT,KAAAO,OAAe,MAAAP,KAAAQ,OAArE,MAAM,IAAIE,MAAM,gCAShB,kBARAV,KAACK,EAAK,kBACNL,KAACM,EAAK,4BACNN,KAACS,YAAe,GAChBT,KAACW,YACDX,KAACY,aACDZ,KAACa,KAAO,EAGmDb,KAACO,MAAQ,GAAKP,KAACQ,OAAS,EAAnF,MAAM,IAAIE,MAAM,yCAChB,IAAsDI,OAAOC,UAAUf,KAACK,KAAUS,OAAOC,UAAUf,KAACM,GAApG,MAAM,IAAII,MAAM,gCAChB,GAA+FV,KAACS,YAAc,EAA9G,MAAM,IAAIC,MAAM,6EAEhBN,EAAOJ,KAGPA,KAACgB,UAEGC,IACIC,OAAQ,kBACJ,IAAIjB,GACAI,EAAGD,EAAKC,EACRC,EAAGF,EAAKE,EACRC,MAAOY,KAAKC,IAAKD,KAAKE,MAAMjB,EAAKG,MAAQ,GAAI,GAC7CC,OAAQW,KAAKC,IAAKD,KAAKE,MAAMjB,EAAKI,OAAS,GAAI,GAC/CC,YAAaL,EAAKK,eAE1Ba,KAAM,MAEVC,IACIL,OAAQ,kBACJ,IAAIjB,GACAI,EAAGD,EAAKC,EAAIc,KAAKC,IAAKD,KAAKE,MAAMjB,EAAKG,MAAQ,GAAI,GAClDD,EAAGF,EAAKE,EACRC,MAAOY,KAAKK,KAAKpB,EAAKG,MAAQ,GAC9BC,OAAQW,KAAKC,IAAKD,KAAKE,MAAMjB,EAAKI,OAAS,GAAI,GAC/CC,YAAaL,EAAKK,eAE1Ba,KAAM,MAEVG,IACIP,OAAQ,kBACJ,IAAIjB,GACAI,EAAGD,EAAKC,EACRC,EAAGF,EAAKE,EAAIa,KAAKC,IAAKD,KAAKE,MAAMjB,EAAKI,OAAS,GAAI,GACnDD,MAAOY,KAAKC,IAAKD,KAAKE,MAAMjB,EAAKG,MAAQ,GAAI,GAC7CC,OAAQW,KAAKK,KAAKpB,EAAKI,OAAS,GAChCC,YAAaL,EAAKK,eAE1Ba,KAAM,MAEVI,IACIR,OAAQ,kBACJ,IAAIjB,GACAI,EAAGD,EAAKC,EAAIc,KAAKC,IAAKD,KAAKE,MAAMjB,EAAKG,MAAQ,GAAI,GAClDD,EAAGF,EAAKE,EAAIa,KAAKC,IAAKD,KAAKE,MAAMjB,EAAKI,OAAS,GAAI,GACnDD,MAAOY,KAAKK,KAAKpB,EAAKG,MAAQ,GAC9BC,OAAQW,KAAKK,KAAKpB,EAAKI,OAAS,GAChCC,YAAaL,EAAKK,eAE1Ba,KAAM,OAGd,IAAAnB,KAAAH,KAAAgB,SACIhB,KAACgB,SAASb,GAAOwB,IAAM,WACnB,OAAG,MAAA3B,KAAAsB,KAAYtB,KAACsB,MAAUtB,KAACsB,KAAOtB,KAACkB,SAAUlB,KAACsB,OApE1D,IAAAM,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,SAyEAJ,EAAY,SAACK,GACT,IAAAC,EAAAC,SAAAjC,EAAGc,KAAKE,OAAM,OAAAgB,EAAAD,EAAA7B,OAAA8B,EAAe,GAAK,GAAKD,EAAK/B,EAC5CC,EAAGa,KAAKE,OAAM,OAAAiB,EAAAF,EAAA5B,QAAA8B,EAAe,GAAK,GAAKF,EAAK9B,IAGhDsB,EAAuB,SAACW,EAAMC,GAC1B,IAAAH,EAAAC,EAAAG,EAAAC,UAAIH,EAAKlC,GAAKmC,EAAKnC,GAAI,OAAAgC,EAAAG,EAAAjC,OAAA8B,EAAc,IACjCE,EAAKlC,GAAI,OAAAiC,EAAAC,EAAAhC,OAAA+B,EAAc,IAAME,EAAKnC,GAClCkC,EAAKjC,GAAKkC,EAAKlC,GAAI,OAAAmC,EAAAD,EAAAhC,QAAAiC,EAAe,IAClCF,EAAKjC,GAAI,OAAAoC,EAAAH,EAAA/B,QAAAkC,EAAe,IAAMF,EAAKlC,IAG3CuB,EAAqB,SAACc,EAASrB,GAC3B,IAAAsB,EAEA,OAFAA,EAAab,EAAUT,GAEpBqB,EAAQtC,EAAIuC,EAAWvC,EACnBsC,EAAQrC,EAAIsC,EAAWtC,EAAO,KAC5B,KAEFqC,EAAQrC,EAAIsC,EAAWtC,EAAO,KAC5B,MAGb6B,EAAkB,SAACQ,GACf,GAA0B,iBAAXA,EACX,MAAM,IAAIjC,MAAM,8BACpB,GAAO,MAAAiC,EAAAtC,GAAkB,MAAAsC,EAAArC,EACrB,MAAM,IAAII,MAAM,uCACpB,IAAA,MAAAiC,EAAGA,EAASpC,WAAA,GAAQ,IAAjB,MAAAoC,EAAsBA,EAASnC,YAAA,GAAS,EACvC,MAAM,IAAIE,MAAM,gDAGxBuB,EAAY,SAACX,GACT,IAAAuB,EAAAC,EAAAC,EAAAC,SAAAF,EAAe3B,KAAKC,IAAKD,KAAKE,MAAMC,EAAKf,MAAQ,GAAI,GACrDwC,EAAe5B,KAAKK,KAAKF,EAAKf,MAAQ,GACtCyC,EAAe7B,KAAKC,IAAKD,KAAKE,MAAMC,EAAKd,OAAS,GAAI,GACtDqC,EAAe1B,KAAKK,KAAKF,EAAKd,OAAS,IACvCS,IACIZ,EAAGiB,EAAKjB,EACRC,EAAGgB,EAAKhB,EACRC,MAAOuC,EACPtC,OAAQwC,GACZzB,IACIlB,EAAGiB,EAAKjB,EAAIyC,EACZxC,EAAGgB,EAAKhB,EACRC,MAAOwC,EACPvC,OAAQwC,GACZvB,IACIpB,EAAGiB,EAAKjB,EACRC,EAAGgB,EAAKhB,EAAI0C,EACZzC,MAAOuC,EACPtC,OAAQqC,GACZnB,IACIrB,EAAGiB,EAAKjB,EAAIyC,EACZxC,EAAGgB,EAAKhB,EAAI0C,EACZzC,MAAOwC,EACPvC,OAAQqC,KAGhBf,EAAU,SAACa,EAASrB,GAChB,IAAA2B,EAAAC,EAAAb,EAAAc,EAAAA,KACAd,EAAAJ,EAAAX,GAAA,IAAA4B,KAAAb,SAAkDT,EAAqBe,EAASM,IAC5EE,EAAMC,KAAKF,UACfC,GAGJnB,EAAU,SAACI,EAAMd,GACb,IAAA+B,SAAAA,EAAiB,SAACC,UACdlB,EAAK,IAAIkB,GAAclB,EAAKkB,GAC5BC,OAAOC,eAAepB,EAAMkB,GACxBG,IAAK,SAACC,UACFpC,EAAKqC,OAAO3D,MAAG,GACfA,KAAE,IAAIsD,GAAcI,EACpBpC,EAAK8B,KAAKpD,OACd2B,IAAK,kBACD3B,KAAE,IAAIsD,IACVM,cAAc,MAEP,KACfP,EAAe,KACfA,EAAe,SACfA,EAAe,WAGnBnB,EAAY,SAACE,GACT,IAAAyB,SAAAA,EAAmB,SAACP,GAChB,GAAO,MAAAlB,EAAA,IAAAkB,iBACAlB,EAAKkB,GACZlB,EAAKkB,GAAYlB,EAAK,IAAIkB,UACnBlB,EAAK,IAAIkB,KACH,KACjBO,EAAiB,KACjBA,EAAiB,SACjBA,EAAiB,uBAKrBC,MAAO,WACH,IAAA3D,EAAA4D,EAAA/D,KAACW,YACDX,KAACY,aACDZ,KAACa,KAAO,EACRkD,SAAA5D,KAAAH,KAAAgB,gBACIhB,KAACgB,SAASb,GAAOmB,KAAO,4BAIhC8B,KAAM,SAAChB,EAAM4B,UACThE,KAACiE,SAAS7B,GAAO4B,gBAGrBC,QAAS,SAACC,EAAOF,GACb,IAAAG,EAAAC,EAAAC,EAAAnB,EAAAP,EAAA2B,EAAAC,EAAAC,EAAAC,EAAArC,EAAAsC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAA1C,EAAAC,EAAA0C,EAAA1D,EAAA,IAAAoD,EAAA,EAAAG,EAAAX,EAAAe,OAAAP,EAAAG,EAAAH,WACIvC,EAAgBC,GACG4B,GAAnBhC,EAAQI,EAAMpC,MAIlB,IAFAuE,IAAQjD,KAAMtB,KAAGsE,SAAUJ,IAErBK,EAAKU,OAAS,GAApB,CAKI,IAJE3D,GAAFe,EAAqBkC,EAAKW,SAAxB5D,KAEFkD,GAAmBvD,GAAI,KAAMM,GAAI,KAAME,GAAI,KAAMC,GAAI,MAErDiD,EAAA,EAAAG,GAJQR,EAAAjC,EAAAiC,UAIRW,OAAAN,EAAAG,EAAAH,IAKI,UAJArD,EAAKT,OAIe,KAFpB4D,EAAO3C,EAAQa,EAASrB,IAEhB2D,QAA+B,IAAd3D,EAAKf,OAA6B,IAAfe,EAAKd,OAC7Cc,EAAKV,UAAUwC,KAAKT,QAEnB,GAAIrB,EAAKT,KAAOS,EAAKV,UAAUqE,QAAW3D,EAAKb,YAChDa,EAAKX,SAASyC,KAAKT,OADlB,CASD,IALAO,EAAYuB,EAAK,GACjBO,EAAe1D,EAAKN,SAASkC,gBAC7BsB,EAAetB,IAAgB5B,KAAM0D,EAAarD,MAAO2C,cACzDE,EAAetB,GAAWoB,SAASlB,KAAKT,GAExCiC,EAAA,EAAAG,GAAAzC,EAAAhB,EAAAX,UAAAsE,OAAAL,EAAAG,EAAAH,mBACIP,EAAcvC,EAAQsC,EAAS9C,GAAM,MACrCkD,EAAeH,IAAiB/C,KAAMA,EAAKN,SAASqD,GAAY1C,MAAO2C,cACvEE,EAAeH,GAAYC,SAASlB,KAAKgB,GAE7C9C,EAAKX,YAEb,IAAAuC,KAAAsB,EACO,gBAAgBD,EAAKnB,KAAKe,UAErCnE,kBAGJ2D,OAAQ,SAACvB,EAAM+C,GACX,IAAAC,EAAAJ,EAGA,OAHA7C,EAAgBC,IAEhBgD,EAAQpF,KAACY,UAAUyE,QAAQjD,KACf,GACRpC,KAACY,UAAU0E,OAAOF,EAAO,GACzBpF,KAACa,OACMsE,GAAkBjD,EAAUE,IAC5B,IAEXgD,EAAQpF,KAACW,SAAS0E,QAAQjD,KACd,GACRpC,KAACW,SAAS2E,OAAOF,EAAO,GACxBpF,KAACa,OACMsE,GAAkBjD,EAAUE,IAC5B,KAIR,OAFH4C,EAAehF,KAACgB,SAASa,EAAmBO,EAAMpC,QAE/CsB,OAAuB0D,EAAa1D,KAAKqC,OAAOvB,EAAM+C,KACrDnF,KAACa,OACqD,IAA1BmE,EAAa1D,KAAKT,OAA9CmE,EAAa1D,KAAO,MACb,iBAcfiE,UAAW,SAACnD,EAAMoD,GACd,IAAArF,EAAAsF,EAAAlB,EAAAE,EAAAP,EAAAQ,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAA1C,EAAAC,EAAAoD,EAKA,cANcF,EAAoB5D,GAClCO,EAAgBC,GAEhB8B,KACAK,GAASvE,MAEHuE,EAAKU,OAAS,GAApB,CAGI,IAAAP,EAAA,EAAAG,GAAAxC,GAFAqD,EAAMnB,EAAKW,SAEXtE,WAAAqE,OAAAP,EAAAG,EAAAH,eAAuCtC,GAASoD,EAAkBpD,EAAMqD,IAASvB,EAAMd,KAAKqC,GAC5F,IAAAd,EAAA,EAAAG,GAAAxC,EAAAoD,EAAA/E,UAAAsE,OAAAN,EAAAG,EAAAH,eAAuCvC,GAASoD,EAAkBpD,EAAMqD,IAASvB,EAAMd,KAAKqC,GAc5F,IATkB,KAHlBhB,EAAO3C,EAAQM,EAAMsD,IAGbT,SACJR,KACGrC,EAAK/B,GAAKqF,EAAIrF,EAAIqF,EAAInF,OACrBkE,EAAKrB,KAAK,MACXhB,EAAK9B,GAAKoF,EAAIpF,EAAIoF,EAAIlF,QACrBiE,EAAKrB,KAAK,MACXqB,EAAKQ,OAAS,IACK,IAAfR,EAAKQ,OAAiBR,EAAKrB,KAAK,MAAUqB,GAAQ,QAE7DG,EAAA,EAAAG,EAAAN,EAAAQ,OAAAL,EAAAG,EAAAH,WAAuB,MAAAc,EAAA1E,SAAAb,GAAAmB,MACnBiD,EAAKnB,KAAKsC,EAAI1E,SAASb,GAAOmB,aAEtC4C,eAeJyB,YAAa,SAACvD,EAAMwD,EAAUJ,GAC1B,IAAArF,EAAAsF,EAAAlB,EAAAE,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAA1C,EAAAC,EAAAoD,EAIA,cAL0BF,EAAoB5D,GAC9CO,EAAgBC,GAEhBmC,GAASvE,MAEHuE,EAAKU,OAAS,GAApB,CAGI,IAAAP,EAAA,EAAAG,GAAAxC,GAFAqD,EAAMnB,EAAKW,SAEXtE,WAAAqE,OAAAP,EAAAG,EAAAH,eAAuCtC,GAASoD,EAAkBpD,EAAMqD,IAASG,EAASH,GAC1F,IAAAd,EAAA,EAAAG,GAAAxC,EAAAoD,EAAA/E,UAAAsE,OAAAN,EAAAG,EAAAH,eAAuCvC,GAASoD,EAAkBpD,EAAMqD,IAASG,EAASH,GAc1F,IATkB,KAHlBhB,EAAO3C,EAAQM,EAAMsD,IAGbT,SACJR,KACGrC,EAAK/B,GAAKqF,EAAIrF,EAAIqF,EAAInF,OACrBkE,EAAKrB,KAAK,MACXhB,EAAK9B,GAAKoF,EAAIpF,EAAIoF,EAAIlF,QACrBiE,EAAKrB,KAAK,MACXqB,EAAKQ,OAAS,IACK,IAAfR,EAAKQ,OAAiBR,EAAKrB,KAAK,MAAUqB,GAAQ,QAE7DG,EAAA,EAAAG,EAAAN,EAAAQ,OAAAL,EAAAG,EAAAH,WAAuB,MAAAc,EAAA1E,SAAAb,GAAAmB,MACnBiD,EAAKnB,KAAKsC,EAAI1E,SAASb,GAAOmB,MAEtC,OAAO,kBAGXK,IAAK,SAACkE,UACF7F,KAACmD,MAAM0C,gBAEX1C,MAAO,SAAC0C,GAEJ,IAAAC,EAAAL,EAAAlB,EAAAL,EAAAQ,EAAAC,EAAAoB,EAAAlB,EAAAC,EAAAzC,EAAAC,EAAA0C,EAAAU,EAAA,GAAmB,iBAATG,IAA2B,MAAAA,EAAAxF,GAAgB,MAAAwF,EAAAvF,GACjD,OAAON,KAACgG,KAAK,SAACP,GACV,IAAAK,EAAAC,EAAAD,GAAQ,EACR,IAAAC,KAAAF,EAAsBA,EAAME,KAAUN,EAAIM,KAAUD,GAAQ,UAC5DA,IAQR,IALA3D,EAAgB0D,GAEhB3B,KACAK,GAAQvE,MAEFuE,EAAKU,OAAS,GAApB,CAGI,IAAAP,EAAA,EAAAG,GAAAxC,GAFAqD,EAAMnB,EAAKW,SAEXtE,WAAAqE,OAAAP,EAAAG,EAAAH,IAAA,QACIoB,GAAQ,EACR,IAAAC,KAAAF,EAAsBA,EAAME,KAAUN,EAAIM,KAAUD,GAAQ,GAC1CA,GAAlB5B,EAAMd,KAAKqC,GACf,IAAAd,EAAA,EAAAG,GAAAxC,EAAAoD,EAAA/E,UAAAsE,OAAAN,EAAAG,EAAAH,IAAA,QACImB,GAAQ,EACR,IAAAC,KAAAF,EAAsBA,EAAME,KAAUN,EAAIM,KAAUD,GAAQ,GAC1CA,GAAlB5B,EAAMd,KAAKqC,GAIZ,OAFHT,EAAeU,EAAI1E,SAASa,EAAmBgE,EAAOH,KAEnDpE,MACCiD,EAAKnB,KAAK4B,EAAa1D,aAE/B4C,eAMJ+B,KAAM,SAACC,GACH,IAAA/F,EAAAoE,EAAA4B,EAAAzB,EAAAC,EAAAE,EAAAC,EAAAzC,EAAAC,EAAAoD,EAEA,IAFAnB,GAAQvE,MAEFuE,EAAKU,OAAS,GAApB,CAEI,IAAAP,EAAA,EAAAG,GAAAxC,GADAqD,EAAMnB,EAAKW,SACXtE,WAAAqE,OAAAP,EAAAG,EAAAH,iCAA4BwB,EAAQC,GACpC,IAAAxB,EAAA,EAAAG,GAAAxC,EAAAoD,EAAA/E,UAAAsE,OAAAN,EAAAG,EAAAH,iCAA2BuB,EAAQC,GAEnC,IAAAhG,KAAAuF,EAAA1E,SAA+B,MAAA0E,EAAA1E,SAAAb,GAAAmB,MAC3BiD,EAAKnB,KAAKsC,EAAI1E,SAASb,GAAOmB,aACtCtB,kBAGJgG,KAAM,SAACI,GACH,IAAAjG,EAAAoE,EAAA4B,EAAAjC,EAAAQ,EAAAC,EAAAE,EAAAC,EAAAzC,EAAAC,EAAAoD,EAGA,IAHAnB,GAAQvE,MACRkE,KAEMK,EAAKU,OAAS,GAApB,CAEI,IAAAP,EAAA,EAAAG,GAAAxC,GADAqD,EAAMnB,EAAKW,SACXtE,WAAAqE,OAAAP,EAAAG,EAAAH,iCAA4B0B,EAAWD,QAAA,IAAQjC,EAAMd,KAAK+C,GAC1D,IAAAxB,EAAA,EAAAG,GAAAxC,EAAAoD,EAAA/E,UAAAsE,OAAAN,EAAAG,EAAAH,iCAA2ByB,EAAWD,QAAA,IAAQjC,EAAMd,KAAK+C,GAEzD,IAAAhG,KAAAuF,EAAA1E,SAA+B,MAAA0E,EAAA1E,SAAAb,GAAAmB,MAC3BiD,EAAKnB,KAAKsC,EAAI1E,SAASb,GAAOmB,aACtC4C,eAGJmC,OAAQ,SAACD,GACL,IAAAE,SAAAA,EAAY,SAACC,GACT,IAAApG,EAAAqG,EAAApE,EAAAsC,EAAAC,EAAAE,EAAAC,EAAAzC,EAAAC,EAAAG,EAAAC,GAAA8D,EAAU,IAAIvG,GAASI,EAAGkG,EAAOlG,EAAGC,EAAGiG,EAAOjG,EAAGC,MAAOgG,EAAOhG,MAAOC,OAAQ+F,EAAO/F,OAAQC,YAAa8F,EAAO9F,eACzGI,KAAO,EACf,IAAAV,KAAAoG,EAAAvF,SAAkC,MAAAuF,EAAAvF,SAAAb,GAAAmB,OAC9BkF,EAAQxF,SAASb,GAAOmB,KAAOgF,EAAUC,EAAOvF,SAASb,GAAOmB,MAChEkF,EAAQ3F,MAAR,OAAAwB,EAAA,OAAAC,EAAAkE,EAAAxF,SAAAb,GAAAmB,MAAAgB,EAAAzB,UAAA,GAAAwB,EAAqD,GAEzD,IAAAqC,EAAA,EAAAG,GAAApC,EAAA8D,EAAA3F,WAAAqE,OAAAP,EAAAG,EAAAH,YAAsC,MAAA0B,IAAJ,mBAAAA,EAAkBA,EAAWhE,QAAA,KAC3DoE,EAAQ5F,UAAUwC,KAAKhB,GAC3B,IAAAuC,EAAA,EAAAG,GAAApC,EAAA6D,EAAA5F,UAAAsE,OAAAN,EAAAG,EAAAH,YAAqC,MAAAyB,IAAJ,mBAAAA,EAAkBA,EAAWhE,QAAA,KAC1DoE,EAAQ7F,SAASyC,KAAKhB,GAG1B,OADAoE,EAAQ3F,MAAQ2F,EAAQ5F,UAAUqE,OAASuB,EAAQ7F,SAASsE,OACzC,IAAhBuB,EAAQ3F,KAAe,KAAU2F,IAE9BxG,mBAGdyG,OAAQ,SAACL,UACLpG,KAACqG,OAAO,SAACF,WACL,mBAAAC,EAAIA,EAAWD,QAAA,kBAIvBO,MAAO,SAACR,GACJ,IAAA/F,EAAAoE,EAAAnE,EAEA,IAFAmE,GAAQvE,MAEFuE,EAAKU,OAAS,GAApB,CACI7E,EAAOmE,EAAKW,QACZgB,EAAOS,KAAKvG,KAEZ,IAAAD,KAAAC,EAAAY,SAAgC,MAAAZ,EAAAY,SAAAb,GAAAmB,MAC5BiD,EAAKnB,KAAKhD,EAAKY,SAASb,GAAOmB,aACvCtB,kBAGJ4G,OAAQ,WACJ,IAAAzG,EAAAoE,EAAAsC,EAAAC,EAAAC,EAAAC,EAAAtB,EAQA,IARAsB,EAAM,GAENH,EAAS,SAACI,GACN,IAAAvC,EAAArC,EAAA6E,EACA,IADAA,EAAM,GACoBxC,EAAArC,EAAA4E,EAAA5E,GAAA,EAAAqC,EAAA,EAAAA,EAAA,EAAArC,GAAA,IAAAqC,IAAAA,EAA1BwC,GAAO,aACPA,GAEJ3C,IAAW4C,MAAO,OAAQ7F,KAAMtB,KAAGiH,MAAO,IACpC1C,EAAKU,OAAS,GAApB,CAGI+B,IADAF,EAAcD,GADdnB,EAAMnB,EAAKW,SACc+B,QAEJ,KAAIvB,EAAIyB,MAAM,KAC1BL,EAAY,mBAGlBpB,EAAIpE,KAAKV,UAAUqE,OAAS,IAC3B+B,GACSF,EAAY,6BACZA,EAAY,OAAMpB,EAAIpE,KAAKV,UAAU,MAG/C8E,EAAIpE,KAAKX,SAASsE,OAAS,IAC1B+B,GACSF,EAAY,uBACZA,EAAY,OAAMpB,EAAIpE,KAAKX,SAAS,MAGjDoG,GAAW,EACX,IAAA5G,KAAAuF,EAAApE,KAAAN,SAAoC,MAAA0E,EAAApE,KAAAN,SAAAb,GAAAmB,OAChCyF,GAAW,EACXxC,EAAK6C,SAAUD,MAAOhH,EAAOmB,KAAMoE,EAAIpE,KAAKN,SAASb,GAAOmB,KAAM2F,MAAOvB,EAAIuB,MAAQ,KAEtFF,IAAcC,GAAUF,EAAY,iBAE3CE,KAneO","file":"quadtree.min.js","sourcesContent":["# quadtree-lib\n# ============\n#\n# **Quadtree-lib** is an easy to use, developer friendly quadtree library\n# which contains many helper methods to add, remove, iterate, filter, simulate\n# collisions over 2d elements and more.\n\n# #### UMD bundling related code\n((root, factory) ->\n if typeof define is 'function' and define.amd\n define [], factory\n else if typeof exports is 'object' and module.exports\n module.exports = factory()\n else\n root['Quadtree'] = factory()\n) @, (-> class Quadtree\n # The Quadtree class\n # -------------------\n\n # ### Constructor\n\n # The quadtree constructor accepts a single parameter object containing the following properties :\n # - width / length : dimensions of the quadtree. [ *mandatory* ]\n # - maxElements : the maximum number of elements before the leaf 'splits' into subtrees. [ *defaults to 1* ]\n # - x / y : these coordinates are used internally by the library to position subtrees. [ *internal use only* ]\n constructor: ({ @x, @y, @width, @height, @maxElements }) ->\n\n # An error is thrown when the width & length are not passed as constructor arguments.\n throw new Error 'Missing quadtree dimensions.' if not @width? or not @height?\n @x ?= 0\n @y ?= 0\n @maxElements ?= 1\n @contents = []\n @oversized = []\n @size = 0\n\n # Dimension & coordinates are checked, an error is thrown in case of bad input.\n throw new Error 'Dimensions must be positive integers.' if @width < 1 or @height < 1\n throw new Error 'Coordinates must be integers' if not Number.isInteger(@x) or not Number.isInteger(@y)\n throw new Error 'The maximum number of elements before a split must be a positive integer.' if @maxElements < 1\n\n that = @\n\n # The subtrees list, by position.\n @children = {\n # Northwest tree.\n NW:\n create: ->\n new Quadtree({\n x: that.x\n y: that.y\n width: Math.max (Math.floor that.width / 2), 1\n height: Math.max (Math.floor that.height / 2), 1\n maxElements: that.maxElements\n })\n tree: null\n # Northeast tree.\n NE:\n create: ->\n new Quadtree({\n x: that.x + Math.max (Math.floor that.width / 2), 1\n y: that.y\n width: Math.ceil that.width / 2\n height: Math.max (Math.floor that.height / 2), 1\n maxElements: that.maxElements\n })\n tree: null\n # Southwest tree.\n SW:\n create: ->\n new Quadtree({\n x: that.x\n y: that.y + Math.max (Math.floor that.height / 2), 1\n width: Math.max (Math.floor that.width / 2), 1\n height: Math.ceil that.height / 2\n maxElements: that.maxElements\n })\n tree: null\n # Southeast tree.\n SE:\n create: ->\n new Quadtree({\n x: that.x + Math.max (Math.floor that.width / 2), 1\n y: that.y + Math.max (Math.floor that.height / 2), 1\n width: Math.ceil that.width / 2\n height: Math.ceil that.height / 2\n maxElements: that.maxElements\n })\n tree: null\n }\n # Adding a getter which lazily creates the tree.\n for child of @children\n @children[child].get = ->\n if @tree? then @tree else @tree = @create(); @tree\n\n # ### Internal methods & vars\n\n # Retrieves the center coordinates of a rectangle.\n getCenter = (item) ->\n x: Math.floor((item.width ? 1) / 2) + item.x\n y: Math.floor((item.height ? 1) / 2) + item.y\n\n # Bounding box collision algorithm.\n boundingBoxCollision = (elt1, elt2) ->\n not(elt1.x >= elt2.x + (elt2.width ? 1) or\n elt1.x + (elt1.width ? 1) <= elt2.x or\n elt1.y >= elt2.y + (elt2.height ? 1) or\n elt1.y + (elt1.height ? 1) <= elt2.y)\n\n # Determines which subtree an element belongs to.\n calculateDirection = (element, tree) ->\n quadCenter = getCenter tree\n\n if element.x < quadCenter.x\n if element.y < quadCenter.y then 'NW'\n else 'SW'\n else\n if element.y < quadCenter.y then 'NE'\n else 'SE'\n\n # Validates a potential element of the tree.\n validateElement = (element) ->\n if not (typeof element is 'object')\n throw new Error 'Element must be an Object.'\n if not element.x? or not element.y?\n throw new Error 'Coordinates properties are missing.'\n if element?.width < 0 or element?.height < 0\n throw new Error 'Width and height must be positive integers.'\n\n # Returns splitted coordinates and dimensions.\n splitTree = (tree) ->\n leftWidth = Math.max (Math.floor tree.width / 2), 1\n rightWidth = Math.ceil tree.width / 2\n topHeight = Math.max (Math.floor tree.height / 2), 1\n bottomHeight = Math.ceil tree.height / 2\n NW:\n x: tree.x\n y: tree.y\n width: leftWidth\n height: topHeight\n NE:\n x: tree.x + leftWidth\n y: tree.y\n width: rightWidth\n height: topHeight\n SW:\n x: tree.x\n y: tree.y + topHeight\n width: leftWidth\n height: bottomHeight\n SE:\n x: tree.x + leftWidth\n y: tree.y + topHeight\n width: rightWidth\n height: bottomHeight\n\n # Determines wether an element fits into subtrees.\n fitting = (element, tree) ->\n where = []\n for direction, coordinates of splitTree tree when boundingBoxCollision element, coordinates\n where.push direction\n where\n\n # Add getters and setters for coordinates and dimensions properties in order to automatically reorganize the elements on change.\n observe = (item, tree) ->\n writeAccessors = (propName) ->\n item[\"_#{propName}\"] = item[propName]\n Object.defineProperty item, propName, {\n set: (val) ->\n tree.remove @, true\n @[\"_#{propName}\"] = val\n tree.push @\n get: ->\n @[\"_#{propName}\"]\n configurable: true\n }\n writeAccessors 'x'\n writeAccessors 'y'\n writeAccessors 'width'\n writeAccessors 'height'\n\n # Remove getters and setters and restore previous properties\n unobserve = (item) ->\n unwriteAccessors = (propName) ->\n if not item[\"_#{propName}\"]? then return\n delete item[propName]\n item[propName] = item[\"_#{propName}\"]\n delete item[\"_#{propName}\"]\n unwriteAccessors 'x'\n unwriteAccessors 'y'\n unwriteAccessors 'width'\n unwriteAccessors 'height'\n\n # ### Exposed methods\n\n # Removes all elements from the quadtree and restores it to pristine state.\n clear: ->\n @contents = []\n @oversized = []\n @size = 0\n for child of @children\n @children[child].tree = null\n\n # Add an element to the quadtree.\n # Elements can be observed to reorganize them into the quadtree automatically whenever their coordinates or dimensions are set (for ex. obj.x = ...).\n push: (item, doObserve) ->\n @pushAll([item], doObserve)\n\n # Push an array of elements.\n pushAll: (items, doObserve) ->\n for item in items\n validateElement item\n observe item, @ if doObserve\n\n fifo = [tree: @, elements: items]\n\n while fifo.length > 0\n { tree, elements } = fifo.shift()\n\n fifoCandidates = { NW: null, NE: null, SW: null, SE: null }\n\n for element in elements\n tree.size++\n\n fits = fitting element, tree\n\n if fits.length isnt 1 or tree.width is 1 or tree.height is 1\n tree.oversized.push element\n\n else if (tree.size - tree.oversized.length) <= tree.maxElements\n tree.contents.push element\n\n else\n direction = fits[0]\n relatedChild = tree.children[direction]\n fifoCandidates[direction] ?= { tree: relatedChild.get(), elements: [] }\n fifoCandidates[direction].elements.push(element)\n\n for content in tree.contents\n contentDir = (fitting content, tree)[0]\n fifoCandidates[contentDir] ?= { tree: tree.children[contentDir].get(), elements: [] }\n fifoCandidates[contentDir].elements.push(content)\n\n tree.contents = []\n\n for direction, candidate of fifoCandidates\n if candidate? then fifo.push candidate\n\n @\n\n # Removes an element from the quadtree.\n remove: (item, stillObserve) ->\n validateElement item\n\n index = @oversized.indexOf item\n if index > -1\n @oversized.splice index, 1\n @size--\n if not stillObserve then unobserve item\n return true\n\n index = @contents.indexOf item\n if index > -1\n @contents.splice index, 1\n @size--\n if not stillObserve then unobserve item\n return true\n\n relatedChild = @children[calculateDirection item, @]\n\n if relatedChild.tree? and relatedChild.tree.remove item, stillObserve\n @size--\n relatedChild.tree = null if relatedChild.tree.size is 0\n return true\n\n false\n\n # Returns an array of elements which collides with the `item` argument.\n # `item` being an object having x, y, width & height properties.\n\n # The default collision function is a basic bounding box algorithm.\n # You can change it by providing a function as a second argument.\n #```javascript\n #colliding({x: 10, y: 20}, function(element1, element2) {\n # return // Place predicate here //\n #})\n #```\n colliding: (item, collisionFunction = boundingBoxCollision) ->\n validateElement item\n\n items = []\n fifo = [@]\n\n while fifo.length > 0\n top = fifo.shift()\n\n for elt in top.oversized when elt isnt item and collisionFunction item, elt then items.push elt\n for elt in top.contents when elt isnt item and collisionFunction item, elt then items.push elt\n\n fits = fitting item, top\n\n # Special case for elements located outside of the quadtree on the right / bottom side\n if fits.length is 0\n fits = []\n if item.x >= top.x + top.width\n fits.push 'NE'\n if item.y >= top.y + top.height\n fits.push 'SW'\n if fits.length > 0\n if fits.length is 1 then fits.push 'SE' else fits = ['SE']\n\n for child in fits when top.children[child].tree?\n fifo.push top.children[child].tree\n\n items\n\n # Performs an action on elements which collides with the `item` argument.\n # `item` being an object having x, y, width & height properties.\n\n # The default collision function is a basic bounding box algorithm.\n # You can change it by providing a function as a third argument.\n #```javascript\n #onCollision(\n # {x: 10, y: 20},\n # function(item) { /* stuff */ },\n # function(element1, element2) {\n # return // Place predicate here //\n #})\n #```\n onCollision: (item, callback, collisionFunction = boundingBoxCollision) ->\n validateElement item\n\n fifo = [@]\n\n while fifo.length > 0\n top = fifo.shift()\n\n for elt in top.oversized when elt isnt item and collisionFunction item, elt then callback elt\n for elt in top.contents when elt isnt item and collisionFunction item, elt then callback elt\n\n fits = fitting item, top\n\n # Special case for elements located outside of the quadtree on the right / bottom side\n if fits.length is 0\n fits = []\n if item.x >= top.x + top.width\n fits.push 'NE'\n if item.y >= top.y + top.height\n fits.push 'SW'\n if fits.length > 0\n if fits.length is 1 then fits.push 'SE' else fits = ['SE']\n\n for child in fits when top.children[child].tree?\n fifo.push top.children[child].tree\n\n return null\n\n # Alias of `where`.\n get: (query) ->\n @where query\n # Returns an array of elements that match the `query` argument.\n where: (query) ->\n # Naïve parsing (missing coordinates)\n if typeof query is 'object' and (not query.x? or not query.y?)\n return @find (elt) ->\n check = true\n for key of query when query[key] isnt elt[key] then check = false\n check\n\n # Optimised parsing\n validateElement query\n\n items = []\n fifo = [@]\n\n while fifo.length > 0\n top = fifo.shift()\n\n for elt in top.oversized\n check = true\n for key of query when query[key] isnt elt[key] then check = false\n items.push elt if check\n for elt in top.contents\n check = true\n for key of query when query[key] isnt elt[key] then check = false\n items.push elt if check\n\n relatedChild = top.children[calculateDirection query, top]\n\n if relatedChild.tree?\n fifo.push relatedChild.tree\n\n items\n\n # For each element of the quadtree, performs the `action` function.\n #```javascript\n #quad.each(function(item) { console.log(item) })\n #```\n each: (action) ->\n fifo = [@]\n\n while fifo.length > 0\n top = fifo.shift()\n for i in top.oversized then action?(i)\n for i in top.contents then action?(i)\n\n for child of top.children when top.children[child].tree?\n fifo.push top.children[child].tree\n @\n\n # Returns an array of elements which validates the predicate.\n find: (predicate) ->\n fifo = [@]\n items = []\n\n while fifo.length > 0\n top = fifo.shift()\n for i in top.oversized when predicate?(i) then items.push i\n for i in top.contents when predicate?(i) then items.push i\n\n for child of top.children when top.children[child].tree?\n fifo.push top.children[child].tree\n items\n\n # Returns a **cloned** `Quadtree` object which contains only the elements that validate the predicate.\n filter: (predicate) ->\n deepclone = (target) ->\n copycat = new Quadtree x: target.x, y: target.y, width: target.width, height: target.height, maxElements: target.maxElements\n copycat.size = 0\n for child of target.children when target.children[child].tree?\n copycat.children[child].tree = deepclone target.children[child].tree\n copycat.size += copycat.children[child].tree?.size ? 0\n\n for item in target.oversized when not predicate? or predicate?(item)\n copycat.oversized.push item\n for item in target.contents when not predicate? or predicate?(item)\n copycat.contents.push item\n\n copycat.size += copycat.oversized.length + copycat.contents.length\n if copycat.size is 0 then null else copycat\n\n deepclone @\n\n # Opposite of filter.\n reject: (predicate) ->\n @filter (i) ->\n not predicate?(i)\n\n # Visits each tree & subtree contained in the `Quadtree` object.\n # For each node, performs the `action` function, inside which `this` is bound to the node tree object.\n visit: (action) ->\n fifo = [@]\n\n while fifo.length > 0\n that = fifo.shift()\n action.bind(that)()\n\n for child of that.children when that.children[child].tree?\n fifo.push that.children[child].tree\n @\n\n # Pretty printing function.\n pretty: ->\n str = ''\n\n indent = (level) ->\n res = ''\n res += ' ' for times in [level...0]\n res\n\n fifo = [{ label: 'ROOT', tree: @, level: 0 }]\n while fifo.length > 0\n top = fifo.shift()\n indentation = indent(top.level)\n str += \"\"\"\n #{indentation}| #{top.label}\n #{indentation}| ------------\\n\n \"\"\"\n\n if top.tree.oversized.length > 0\n str += \"\"\"\n #{indentation}| * Oversized elements *\n #{indentation}| #{top.tree.oversized}\\n\n \"\"\"\n\n if top.tree.contents.length > 0\n str += \"\"\"\n #{indentation}| * Leaf content *\n #{indentation}| #{top.tree.contents}\\n\n \"\"\"\n\n isParent = false\n for child of top.tree.children when top.tree.children[child].tree?\n isParent = true\n fifo.unshift { label: child, tree: top.tree.children[child].tree, level: top.level + 1 }\n\n if isParent then str += \"#{indentation}└──┐\\n\"\n\n str\n)\n"]} \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 2c0e992..d57feee 100644 --- a/docs/index.html +++ b/docs/index.html @@ -314,7 +314,7 @@

Exposed methods

-

Clears the quadtree and removes all elements.

+

Removes all elements from the quadtree and restores it to pristine state.

    clear: ->
diff --git a/docs/quadtree.html b/docs/quadtree.html
index 2c0e992..d57feee 100644
--- a/docs/quadtree.html
+++ b/docs/quadtree.html
@@ -314,7 +314,7 @@ 

Exposed methods

-

Clears the quadtree and removes all elements.

+

Removes all elements from the quadtree and restores it to pristine state.

    clear: ->
diff --git a/package-lock.json b/package-lock.json
index e61fadc..99390f1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
     "name": "quadtree-lib",
-    "version": "1.0.7",
+    "version": "1.0.8",
     "lockfileVersion": 1,
     "requires": true,
     "dependencies": {
diff --git a/package.json b/package.json
index 45325c0..a57f613 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
     "name": "quadtree-lib",
-    "version": "1.0.7",
+    "version": "1.0.8",
     "description": "Efficient quadtrees library written in CoffeeScript.",
     "author": "Julien Elbaz",
     "license": "MIT",