source: Dev/branches/jQueryUI/client/d3/src/geom/quadtree.js @ 249

Last change on this file since 249 was 249, checked in by hendrikvanantwerpen, 13 years ago

This one's for Subversion, because it's so close...

First widget (stripped down sequencer).
Seperated client and server code in two direcotry trees.

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.