source: Dev/trunk/d3/src/geom/quadtree.js @ 76

Last change on this file since 76 was 76, checked in by fpvanagthoven, 14 years ago

d3

File size: 3.8 KB
Line 
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.
8d3.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
104function d3_geom_quadtreeNode() {
105  return {
106    leaf: true,
107    nodes: [],
108    point: null
109  };
110}
111
112function 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
124function d3_geom_quadtreePoint(p) {
125  return {
126    x: p[0],
127    y: p[1]
128  };
129}
Note: See TracBrowser for help on using the repository browser.