Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
package.src.geom.quadtree.js Maven / Gradle / Ivy
import "../core/functor";
import "../math/abs";
import "geom";
import "point";
d3.geom.quadtree = function(points, x1, y1, x2, y2) {
var x = d3_geom_pointX,
y = d3_geom_pointY,
compat;
// For backwards-compatibility.
if (compat = arguments.length) {
x = d3_geom_quadtreeCompatX;
y = d3_geom_quadtreeCompatY;
if (compat === 3) {
y2 = y1;
x2 = x1;
y1 = x1 = 0;
}
return quadtree(points);
}
function quadtree(data) {
var d,
fx = d3_functor(x),
fy = d3_functor(y),
xs,
ys,
i,
n,
x1_,
y1_,
x2_,
y2_;
if (x1 != null) {
x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2;
} else {
// Compute bounds, and cache points temporarily.
x2_ = y2_ = -(x1_ = y1_ = Infinity);
xs = [], ys = [];
n = data.length;
if (compat) for (i = 0; i < n; ++i) {
d = data[i];
if (d.x < x1_) x1_ = d.x;
if (d.y < y1_) y1_ = d.y;
if (d.x > x2_) x2_ = d.x;
if (d.y > y2_) y2_ = d.y;
xs.push(d.x);
ys.push(d.y);
} else for (i = 0; i < n; ++i) {
var x_ = +fx(d = data[i], i),
y_ = +fy(d, i);
if (x_ < x1_) x1_ = x_;
if (y_ < y1_) y1_ = y_;
if (x_ > x2_) x2_ = x_;
if (y_ > y2_) y2_ = y_;
xs.push(x_);
ys.push(y_);
}
}
// Squarify the bounds.
var dx = x2_ - x1_,
dy = y2_ - y1_;
if (dx > dy) y2_ = y1_ + dx;
else x2_ = x1_ + dy;
// Recursively inserts the specified point p at the node n or one of its
// descendants. The bounds are defined by [x1, x2] and [y1, y2].
function insert(n, d, x, y, x1, y1, x2, y2) {
if (isNaN(x) || isNaN(y)) return; // ignore invalid points
if (n.leaf) {
var nx = n.x,
ny = n.y;
if (nx != null) {
// If the point at this leaf node is at the same position as the new
// point we are adding, we leave the point associated with the
// internal node while adding the new point to a child node. This
// avoids infinite recursion.
if ((abs(nx - x) + abs(ny - y)) < 0.01) {
insertChild(n, d, x, y, x1, y1, x2, y2);
} else {
var nPoint = n.point;
n.x = n.y = n.point = null;
insertChild(n, nPoint, nx, ny, x1, y1, x2, y2);
insertChild(n, d, x, y, x1, y1, x2, y2);
}
} else {
n.x = x, n.y = y, n.point = d;
}
} else {
insertChild(n, d, x, y, x1, y1, x2, y2);
}
}
// Recursively inserts the specified point [x, y] into a descendant of node
// n. The bounds are defined by [x1, x2] and [y1, y2].
function insertChild(n, d, x, y, x1, y1, x2, y2) {
// Compute the split point, and the quadrant in which to insert p.
var xm = (x1 + x2) * 0.5,
ym = (y1 + y2) * 0.5,
right = x >= xm,
below = y >= ym,
i = below << 1 | right;
// Recursively insert into the child node.
n.leaf = false;
n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());
// Update the bounds as we recurse.
if (right) x1 = xm; else x2 = xm;
if (below) y1 = ym; else y2 = ym;
insert(n, d, x, y, x1, y1, x2, y2);
}
// Create the root node.
var root = d3_geom_quadtreeNode();
root.add = function(d) {
insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_);
};
root.visit = function(f) {
d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_);
};
// Find the closest point to the specified point.
// TODO allow the initial search extent to be specified?
// TODO allow the initial minimum distance to be specified?
// TODO allow searching below any node?
root.find = function(point) {
return d3_geom_quadtreeFind(root, point[0], point[1], x1_, y1_, x2_, y2_);
};
// Insert all points.
i = -1;
if (x1 == null) {
while (++i < n) {
insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_);
}
--i; // index of last insertion
} else data.forEach(root.add);
// Discard captured fields.
xs = ys = data = d = null;
return root;
}
quadtree.x = function(_) {
return arguments.length ? (x = _, quadtree) : x;
};
quadtree.y = function(_) {
return arguments.length ? (y = _, quadtree) : y;
};
quadtree.extent = function(_) {
if (!arguments.length) return x1 == null ? null : [[x1, y1], [x2, y2]];
if (_ == null) x1 = y1 = x2 = y2 = null;
else x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], y2 = +_[1][1];
return quadtree;
};
quadtree.size = function(_) {
if (!arguments.length) return x1 == null ? null : [x2 - x1, y2 - y1];
if (_ == null) x1 = y1 = x2 = y2 = null;
else x1 = y1 = 0, x2 = +_[0], y2 = +_[1];
return quadtree;
};
return quadtree;
};
function d3_geom_quadtreeCompatX(d) { return d.x; }
function d3_geom_quadtreeCompatY(d) { return d.y; }
function d3_geom_quadtreeNode() {
return {
leaf: true,
nodes: [],
point: null,
x: null,
y: null
};
}
function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) {
if (!f(node, x1, y1, x2, y2)) {
var sx = (x1 + x2) * 0.5,
sy = (y1 + y2) * 0.5,
children = node.nodes;
if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy);
if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy);
if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2);
if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2);
}
}
function d3_geom_quadtreeFind(root, x, y, x0, y0, x3, y3) {
var minDistance2 = Infinity,
closestPoint;
(function find(node, x1, y1, x2, y2) {
// stop searching if this cell can’t contain a closer node
if (x1 > x3 || y1 > y3 || x2 < x0 || y2 < y0) return;
// visit this point
if (point = node.point) {
var point,
dx = x - node.x,
dy = y - node.y,
distance2 = dx * dx + dy * dy;
if (distance2 < minDistance2) {
var distance = Math.sqrt(minDistance2 = distance2);
x0 = x - distance, y0 = y - distance;
x3 = x + distance, y3 = y + distance;
closestPoint = point;
}
}
// bisect the current node
var children = node.nodes,
xm = (x1 + x2) * 0.5,
ym = (y1 + y2) * 0.5,
right = x >= xm,
below = y >= ym;
// visit closest cell first
for (var i = below << 1 | right, j = i + 4; i < j; ++i) {
if (node = children[i & 3]) switch (i & 3) {
case 0: find(node, x1, y1, xm, ym); break;
case 1: find(node, xm, y1, x2, ym); break;
case 2: find(node, x1, ym, xm, y2); break;
case 3: find(node, xm, ym, x2, y2); break;
}
}
})(root, x0, y0, x3, y3);
return closestPoint;
}