var vows = require("vows"), load = require("../load"), assert = require("../assert"); var suite = vows.describe("d3.geom.quadtree"); suite.addBatch({ "quadtree": { topic: load("geom/quadtree").expression("d3.geom.quadtree"), "the default quadtree layout": { topic: function(quadtree) { return quadtree(); }, "has no defined size": function(q) { assert.isNull(q.size()); }, "has no defined extent": function(q) { assert.isNull(q.extent()); }, "has the default x-accessor, d[0]": function(q) { assert.strictEqual(q.x()([42, 43]), 42); }, "has the default y-accessor, d[1]": function(q) { assert.strictEqual(q.y()([42, 43]), 43); }, "can create a single-node quadtree with no bounds": function(q) { var point = [0, 0], q = q([point]), n = 0; q.visit(function(node, x1, y1, x2, y2) { assert.deepEqual(node.point, point); assert.isUndefined(node[0]); assert.isUndefined(node[1]); assert.isUndefined(node[2]); assert.isUndefined(node[3]); assert.isTrue(node.leaf); ++n; }); assert.strictEqual(n, 1, "number of visits"); } }, "the quadtree applied directly": { "can create a single-node quadtree with no bounds": function(quadtree) { var point = {x: 0, y: 0}, q = quadtree([point]), n = 0; q.visit(function(node, x1, y1, x2, y2) { assert.deepEqual(node.point, point); assert.isUndefined(node[0]); assert.isUndefined(node[1]); assert.isUndefined(node[2]); assert.isUndefined(node[3]); assert.isTrue(node.leaf); ++n; }); assert.strictEqual(n, 1, "number of visits"); }, "can create an empty quadtree": function(quadtree) { var q = quadtree([], 8, 10, 56, 47), n = 0; q.visit(function(node, x1, y1, x2, y2) { assert.isNull(node.point); assert.isUndefined(node[0]); assert.isUndefined(node[1]); assert.isUndefined(node[2]); assert.isUndefined(node[3]); assert.isTrue(node.leaf); ++n; }); assert.strictEqual(n, 1, "number of visits"); }, "squarifies the input dimensions": function(quadtree) { var ox1 = 8, oy1 = 10, ox2 = 56, oy2 = 47, q = quadtree([], ox1, oy1, ox2, oy2), n = 0; q.visit(function(node, x1, y1, x2, y2) { assert.strictEqual(x1, ox1); assert.strictEqual(y1, oy1); assert.strictEqual(x2, Math.max(ox2 - ox1, oy2 - oy1) + x1); assert.strictEqual(y2, Math.max(ox2 - ox1, oy2 - oy1) + y1); ++n; }); assert.strictEqual(n, 1, "number of visits"); }, "with three arguments, x1 and y1 are 0,0": function(quadtree) { var dx = 56, dy = 47, q = quadtree([], dx, dy), n = 0; q.visit(function(node, x1, y1, x2, y2) { assert.strictEqual(x1, 0); assert.strictEqual(y1, 0); assert.strictEqual(x2, Math.max(dx, dy)); assert.strictEqual(y2, Math.max(dx, dy)); ++n; }); assert.strictEqual(n, 1, "number of visits"); }, "visit": { "uses pre-order traversal": function(quadtree) { var a = {x: 100, y: 100}, b = {x: 200, y: 200}, c = {x: 300, y: 300}, q = quadtree([a, b, c], 960, 500), expected = [ {point: null, x1: 0, y1: 0, x2: 960, y2: 960}, {point: null, x1: 0, y1: 0, x2: 480, y2: 480}, {point: null, x1: 0, y1: 0, x2: 240, y2: 240}, {point: a, x1: 0, y1: 0, x2: 120, y2: 120}, {point: b, x1: 120, y1: 120, x2: 240, y2: 240}, {point: c, x1: 240, y1: 240, x2: 480, y2: 480} ]; q.visit(function(node, x1, y1, x2, y2) { assert.deepEqual({point: node.point, x1: x1, y1: y1, x2: x2, y2: y2}, expected.shift()); assert.equal(!!node.point, node.leaf); }); assert.isEmpty(expected); }, "does not recurse if the callback returns truthy": function(quadtree) { var a = {x: 100, y: 100}, b = {x: 700, y: 700}, c = {x: 800, y: 800}, q = quadtree([a, b, c], 960, 500), n = 0; q.visit(function(node, x1, y1, x2, y2) { ++n; return x1 > 0; }); assert.equal(n, 3); } } } } }); suite.export(module);