yaqt
Version:
Yet another quad tree
100 lines (87 loc) • 2.74 kB
JavaScript
var Bounds = require('./bounds.js');
var MAX_ITEMS = 4;
module.exports = TreeNode;
function TreeNode(bounds) {
this.bounds = bounds;
this.nw = null;
this.ne = null;
this.sw = null;
this.se = null;
this.items = null;
}
TreeNode.prototype.subdivide = function subdivide() {
var bounds = this.bounds;
var quarter = bounds.half/2;
this.nw = new TreeNode(new Bounds(bounds.x - quarter, bounds.y - quarter, quarter));
this.ne = new TreeNode(new Bounds(bounds.x + quarter, bounds.y - quarter, quarter));
this.sw = new TreeNode(new Bounds(bounds.x - quarter, bounds.y + quarter, quarter));
this.se = new TreeNode(new Bounds(bounds.x + quarter, bounds.y + quarter, quarter));
};
TreeNode.prototype.insert = function insert(idx, array, depth) {
if (!depth) depth = 0;
if (depth > 24) return; // TODO: this probably needs better handling
var isLeaf = this.nw === null;
if (isLeaf) {
// todo: this memory could be recycled to avoid gc
if (this.items === null) {
this.items = [idx];
} else {
this.items.push(idx);
}
// TODO: This as well.. Why 0.1?
if (this.bounds.half > 0.1) {
if (this.items.length >= MAX_ITEMS ) {
this.subdivide();
for (var i = 0; i < this.items.length; ++i) {
this.insert(this.items[i], array, depth + 1);
}
this.items = null;
}
}
} else {
var x = array[idx], y = array[idx + 1];
var bounds = this.bounds;
var quadIdx = 0; // assume NW
if (x > bounds.x) {
quadIdx += 1; // nope, we are in E part
}
if (y > bounds.y) {
quadIdx += 2; // Somewhere south.
}
var child = getChild(this, quadIdx);
child.insert(idx, array, depth + 1);
}
};
TreeNode.prototype.visit = function visit(cb) {
if (cb(this) && this.nw) {
this.nw.visit(cb);
this.ne.visit(cb);
this.sw.visit(cb);
this.se.visit(cb);
}
}
TreeNode.prototype.query = function queryBounds(bounds, results, sourceArray, intersects) {
if (!intersects(this.bounds, bounds)) return;
var items = this.items;
if (items) {
for (var i = 0; i < items.length; ++i) {
var idx = items[i];
var x = sourceArray[idx];
var y = sourceArray[idx + 1];
if (bounds.contains(x, y)) {
results.push(idx);
}
}
}
if (!this.nw) return;
this.nw.query(bounds, results, sourceArray, intersects);
this.ne.query(bounds, results, sourceArray, intersects);
this.sw.query(bounds, results, sourceArray, intersects);
this.se.query(bounds, results, sourceArray, intersects);
};
function getChild(node, idx) {
if (idx === 0) return node.nw;
if (idx === 1) return node.ne;
if (idx === 2) return node.sw;
if (idx === 3) return node.se;
}