Skip to content

Commit 35fb91d

Browse files
committed
Allow quadtree to be built dynamically.
You can now specify the domain of the quadtree upon construction, such that you can add points to the quadtree dynamically later. The quadtree example now also shows how to do a quick rectangular search using the quadtree.
1 parent f74ccb9 commit 35fb91d

7 files changed

Lines changed: 167 additions & 133 deletions

File tree

d3.geom.js

Lines changed: 50 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -693,59 +693,58 @@ d3.geom.delaunay = function(vertices) {
693693

694694
return triangles;
695695
};
696-
/**
697-
* Constructs a new quadtree for the specified array of points. A quadtree is a
698-
* two-dimensional recursive spatial subdivision. This implementation uses
699-
* square partitions, dividing each square into four equally-sized squares. Each
700-
* point exists in a unique node; if multiple points are in the same position,
701-
* some points may be stored on internal nodes rather than leaf nodes. Quadtrees
702-
* can be used to accelerate various spatial operations, such as the Barnes-Hut
703-
* approximation for computing n-body forces, or collision detection.
704-
*
705-
* @param points [{x: x1, y: y1}, {x: x2, y: y2}, …]
706-
* @return quadtree root {left: boolean, nodes: […], point: {x: x, y: y}}
707-
*/
708-
d3.geom.quadtree = function(points) {
696+
// Constructs a new quadtree for the specified array of points. A quadtree is a
697+
// two-dimensional recursive spatial subdivision. This implementation uses
698+
// square partitions, dividing each square into four equally-sized squares. Each
699+
// point exists in a unique node; if multiple points are in the same position,
700+
// some points may be stored on internal nodes rather than leaf nodes. Quadtrees
701+
// can be used to accelerate various spatial operations, such as the Barnes-Hut
702+
// approximation for computing n-body forces, or collision detection.
703+
d3.geom.quadtree = function(points, x1, y1, x2, y2) {
709704
var p,
710705
i = -1,
711706
n = points.length;
712707

713-
/* Type conversion for deprecated API. */
708+
// Type conversion for deprecated API.
714709
if (n && isNaN(points[0].x)) points = points.map(d3_geom_quadtreePoint);
715710

716-
/* Compute bounds. */
717-
var x1 = Infinity, y1 = x1,
718-
x2 = -Infinity, y2 = x2;
719-
while (++i < n) {
720-
p = points[i];
721-
if (p.x < x1) x1 = p.x;
722-
if (p.y < y1) y1 = p.y;
723-
if (p.x > x2) x2 = p.x;
724-
if (p.y > y2) y2 = p.y;
711+
// Allow bounds to be specified explicitly.
712+
if (arguments.length < 5) {
713+
if (arguments.length === 3) {
714+
y2 = x2 = y1;
715+
y1 = x1;
716+
} else {
717+
x1 = y1 = Infinity;
718+
x2 = y2 = -Infinity;
719+
720+
// Compute bounds.
721+
while (++i < n) {
722+
p = points[i];
723+
if (p.x < x1) x1 = p.x;
724+
if (p.y < y1) y1 = p.y;
725+
if (p.x > x2) x2 = p.x;
726+
if (p.y > y2) y2 = p.y;
727+
}
728+
729+
// Squarify the bounds.
730+
var dx = x2 - x1,
731+
dy = y2 - y1;
732+
if (dx > dy) y2 = y1 + dx;
733+
else x2 = x1 + dy;
734+
}
725735
}
726736

727-
/* Squarify the bounds. */
728-
var dx = x2 - x1,
729-
dy = y2 - y1;
730-
if (dx > dy) y2 = y1 + dx;
731-
else x2 = x1 + dy;
732-
733-
/**
734-
* @ignore Recursively inserts the specified point <i>p</i> at the node
735-
* <i>n</i> or one of its descendants. The bounds are defined by [<i>x1</i>,
736-
* <i>x2</i>] and [<i>y1</i>, <i>y2</i>].
737-
*/
737+
// Recursively inserts the specified point p at the node n or one of its
738+
// descendants. The bounds are defined by [x1, x2] and [y1, y2].
738739
function insert(n, p, x1, y1, x2, y2) {
739740
if (isNaN(p.x) || isNaN(p.y)) return; // ignore invalid points
740741
if (n.leaf) {
741742
var v = n.point;
742743
if (v) {
743-
/*
744-
* If the point at this leaf node is at the same position as the new
745-
* point we are adding, we leave the point associated with the
746-
* internal node while adding the new point to a child node. This
747-
* avoids infinite recursion.
748-
*/
744+
// If the point at this leaf node is at the same position as the new
745+
// point we are adding, we leave the point associated with the
746+
// internal node while adding the new point to a child node. This
747+
// avoids infinite recursion.
749748
if ((Math.abs(v.x - p.x) + Math.abs(v.y - p.y)) < .01) {
750749
insertChild(n, p, x1, y1, x2, y2);
751750
} else {
@@ -761,41 +760,39 @@ d3.geom.quadtree = function(points) {
761760
}
762761
}
763762

764-
/**
765-
* @ignore Recursively inserts the specified point <i>p</i> into a
766-
* descendant of node <i>n</i>. The bounds are defined by [<i>x1</i>,
767-
* <i>x2</i>] and [<i>y1</i>, <i>y2</i>].
768-
*/
763+
// Recursively inserts the specified point p into a descendant of node n. The
764+
// bounds are defined by [x1, x2] and [y1, y2].
769765
function insertChild(n, p, x1, y1, x2, y2) {
770-
/* Compute the split point, and the quadrant in which to insert p. */
766+
// Compute the split point, and the quadrant in which to insert p.
771767
var sx = (x1 + x2) * .5,
772768
sy = (y1 + y2) * .5,
773769
right = p.x >= sx,
774770
bottom = p.y >= sy,
775771
i = (bottom << 1) + right;
776772

777-
/* Recursively insert into the child node. */
773+
// Recursively insert into the child node.
778774
n.leaf = false;
779775
n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());
780776

781-
/* Update the bounds as we recurse. */
777+
// Update the bounds as we recurse.
782778
if (right) x1 = sx; else x2 = sx;
783779
if (bottom) y1 = sy; else y2 = sy;
784780
insert(n, p, x1, y1, x2, y2);
785781
}
786782

787-
/* Create the root node. */
783+
// Create the root node.
788784
var root = d3_geom_quadtreeNode();
789785

790-
/* Insert all points. */
791-
i = -1;
792-
while (++i < n) insert(root, points[i], x1, y1, x2, y2);
786+
root.add = function(p) {
787+
insert(root, p, x1, y1, x2, y2);
788+
};
793789

794-
/* Register a visitor function for the root. */
795790
root.visit = function(f) {
796791
d3_geom_quadtreeVisit(f, root, x1, y1, x2, y2);
797792
};
798793

794+
// Insert all points.
795+
points.forEach(root.add);
799796
return root;
800797
};
801798

0 commit comments

Comments
 (0)