[76] | 1 | // Constructs a new quadtree for the specified array of points. A quadtree is a |
---|
| 2 | // two-dimensional recursive spatial subdivision. This implementation uses |
---|
| 3 | // square partitions, dividing each square into four equally-sized squares. Each |
---|
| 4 | // point exists in a unique node; if multiple points are in the same position, |
---|
| 5 | // some points may be stored on internal nodes rather than leaf nodes. Quadtrees |
---|
| 6 | // can be used to accelerate various spatial operations, such as the Barnes-Hut |
---|
| 7 | // approximation for computing n-body forces, or collision detection. |
---|
| 8 | d3.geom.quadtree = function(points, x1, y1, x2, y2) { |
---|
| 9 | var p, |
---|
| 10 | i = -1, |
---|
| 11 | n = points.length; |
---|
| 12 | |
---|
| 13 | // Type conversion for deprecated API. |
---|
| 14 | if (n && isNaN(points[0].x)) points = points.map(d3_geom_quadtreePoint); |
---|
| 15 | |
---|
| 16 | // Allow bounds to be specified explicitly. |
---|
| 17 | if (arguments.length < 5) { |
---|
| 18 | if (arguments.length === 3) { |
---|
| 19 | y2 = x2 = y1; |
---|
| 20 | y1 = x1; |
---|
| 21 | } else { |
---|
| 22 | x1 = y1 = Infinity; |
---|
| 23 | x2 = y2 = -Infinity; |
---|
| 24 | |
---|
| 25 | // Compute bounds. |
---|
| 26 | while (++i < n) { |
---|
| 27 | p = points[i]; |
---|
| 28 | if (p.x < x1) x1 = p.x; |
---|
| 29 | if (p.y < y1) y1 = p.y; |
---|
| 30 | if (p.x > x2) x2 = p.x; |
---|
| 31 | if (p.y > y2) y2 = p.y; |
---|
| 32 | } |
---|
| 33 | |
---|
| 34 | // Squarify the bounds. |
---|
| 35 | var dx = x2 - x1, |
---|
| 36 | dy = y2 - y1; |
---|
| 37 | if (dx > dy) y2 = y1 + dx; |
---|
| 38 | else x2 = x1 + dy; |
---|
| 39 | } |
---|
| 40 | } |
---|
| 41 | |
---|
| 42 | // Recursively inserts the specified point p at the node n or one of its |
---|
| 43 | // descendants. The bounds are defined by [x1, x2] and [y1, y2]. |
---|
| 44 | function insert(n, p, x1, y1, x2, y2) { |
---|
| 45 | if (isNaN(p.x) || isNaN(p.y)) return; // ignore invalid points |
---|
| 46 | if (n.leaf) { |
---|
| 47 | var v = n.point; |
---|
| 48 | if (v) { |
---|
| 49 | // If the point at this leaf node is at the same position as the new |
---|
| 50 | // point we are adding, we leave the point associated with the |
---|
| 51 | // internal node while adding the new point to a child node. This |
---|
| 52 | // avoids infinite recursion. |
---|
| 53 | if ((Math.abs(v.x - p.x) + Math.abs(v.y - p.y)) < .01) { |
---|
| 54 | insertChild(n, p, x1, y1, x2, y2); |
---|
| 55 | } else { |
---|
| 56 | n.point = null; |
---|
| 57 | insertChild(n, v, x1, y1, x2, y2); |
---|
| 58 | insertChild(n, p, x1, y1, x2, y2); |
---|
| 59 | } |
---|
| 60 | } else { |
---|
| 61 | n.point = p; |
---|
| 62 | } |
---|
| 63 | } else { |
---|
| 64 | insertChild(n, p, x1, y1, x2, y2); |
---|
| 65 | } |
---|
| 66 | } |
---|
| 67 | |
---|
| 68 | // Recursively inserts the specified point p into a descendant of node n. The |
---|
| 69 | // bounds are defined by [x1, x2] and [y1, y2]. |
---|
| 70 | function insertChild(n, p, x1, y1, x2, y2) { |
---|
| 71 | // Compute the split point, and the quadrant in which to insert p. |
---|
| 72 | var sx = (x1 + x2) * .5, |
---|
| 73 | sy = (y1 + y2) * .5, |
---|
| 74 | right = p.x >= sx, |
---|
| 75 | bottom = p.y >= sy, |
---|
| 76 | i = (bottom << 1) + right; |
---|
| 77 | |
---|
| 78 | // Recursively insert into the child node. |
---|
| 79 | n.leaf = false; |
---|
| 80 | n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode()); |
---|
| 81 | |
---|
| 82 | // Update the bounds as we recurse. |
---|
| 83 | if (right) x1 = sx; else x2 = sx; |
---|
| 84 | if (bottom) y1 = sy; else y2 = sy; |
---|
| 85 | insert(n, p, x1, y1, x2, y2); |
---|
| 86 | } |
---|
| 87 | |
---|
| 88 | // Create the root node. |
---|
| 89 | var root = d3_geom_quadtreeNode(); |
---|
| 90 | |
---|
| 91 | root.add = function(p) { |
---|
| 92 | insert(root, p, x1, y1, x2, y2); |
---|
| 93 | }; |
---|
| 94 | |
---|
| 95 | root.visit = function(f) { |
---|
| 96 | d3_geom_quadtreeVisit(f, root, x1, y1, x2, y2); |
---|
| 97 | }; |
---|
| 98 | |
---|
| 99 | // Insert all points. |
---|
| 100 | points.forEach(root.add); |
---|
| 101 | return root; |
---|
| 102 | }; |
---|
| 103 | |
---|
| 104 | function d3_geom_quadtreeNode() { |
---|
| 105 | return { |
---|
| 106 | leaf: true, |
---|
| 107 | nodes: [], |
---|
| 108 | point: null |
---|
| 109 | }; |
---|
| 110 | } |
---|
| 111 | |
---|
| 112 | function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) { |
---|
| 113 | if (!f(node, x1, y1, x2, y2)) { |
---|
| 114 | var sx = (x1 + x2) * .5, |
---|
| 115 | sy = (y1 + y2) * .5, |
---|
| 116 | children = node.nodes; |
---|
| 117 | if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy); |
---|
| 118 | if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy); |
---|
| 119 | if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2); |
---|
| 120 | if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2); |
---|
| 121 | } |
---|
| 122 | } |
---|
| 123 | |
---|
| 124 | function d3_geom_quadtreePoint(p) { |
---|
| 125 | return { |
---|
| 126 | x: p[0], |
---|
| 127 | y: p[1] |
---|
| 128 | }; |
---|
| 129 | } |
---|