RA = {
function splitX(points, x) {
const inside = [],
outside = [];
for (let p of points) {
if (p.x <= x) inside.push(p);
else outside.push(p);
}
return { inside, outside };
}
function splitY(points, y) {
const inside = [],
outside = [];
for (let p of points) {
if (p.y <= y) inside.push(p);
else outside.push(p);
}
return { inside, outside };
}
const half = gridPoints ? (x) => ~~(x / 2) : (x) => x / 2;
class RA {
constructor(points = [], maxLevel = 20) {
this.box = new MBR(...points);
this.points = points;
this.left = this.right = null;
if (points.length == 0) return this;
const bsize = this.box.size();
if (
maxLevel == 0 ||
Math.max(bsize.x, bsize.y) <= Number.EPSILON ||
(gridPoints && (bsize.x + 1) * (bsize.y + 1) == points.length)
)
return;
let { inside, outside } =
bsize.x > bsize.y
? splitX(points, this.box.min.x + half(bsize.x))
: splitY(points, this.box.min.y + half(bsize.y));
this.left = new RA(inside, maxLevel - 1);
this.right = new RA(outside, maxLevel - 1);
}
// Height (number of levels) of the tree
height() {
if (!this.left) return 0;
return 1 + Math.max(this.left.height(), this.right.height());
}
// Iterates over internal nodes at level l or leaves if at shallower levels
*approximation(l) {
if (l == 0 || !this.left) yield this;
else {
yield* this.left.approximation(l - 1);
yield* this.right.approximation(l - 1);
}
}
// Return this tree cut at level l
cutTree(l) {
let result = new RA();
result.box = this.box;
result.points = this.points;
if (l > 0 && this.left) {
result.left = this.left.cutTree(l - 1);
result.right = this.right.cutTree(l - 1);
}
return result;
}
// Return this tree simplified so as to ignore splits
// for approximately full nodes
approxTree(fillRate = 0.99) {
let result = new RA();
result.box = this.box;
result.points = this.points;
const bsize = this.box.size();
if (
this.left &&
(bsize.x + 1) * (bsize.y + 1) * fillRate >= result.points.length
) {
result.left = this.left.approxTree(fillRate);
result.right = this.right.approxTree(fillRate);
}
return result;
}
// Returns the distance to a point p
distance(p) {
let best = null;
let bestDist = Number.POSITIVE_INFINITY;
this.distanceSteps = 0;
const traverse = (node) => {
if (bestDist == 0) return;
this.distanceSteps++;
if (!node.left) {
let d = node.box.pointDist(p);
if (d < bestDist) [best, bestDist] = [node, d];
return;
}
let dleft = node.left.box.pointDist(p);
let dright = node.right.box.pointDist(p);
if (dleft < dright) {
if (dleft < bestDist) traverse(node.left);
if (dright < bestDist) traverse(node.right);
} else {
if (dright < bestDist) traverse(node.right);
if (dleft < bestDist) traverse(node.left);
}
};
traverse(this);
return bestDist;
}
}
return RA;
}