FLUJOS/VISUALIZACION/node_modules/d3-octree/dist/d3-octree.js
2025-11-07 00:06:12 +01:00

480 lines
14 KiB
JavaScript
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// https://github.com/vasturiano/d3-octree v1.0.2
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.d3 = global.d3 || {}));
})(this, (function (exports) { 'use strict';
function tree_add(d) {
const x = +this._x.call(null, d),
y = +this._y.call(null, d),
z = +this._z.call(null, d);
return add(this.cover(x, y, z), x, y, z, d);
}
function add(tree, x, y, z, d) {
if (isNaN(x) || isNaN(y) || isNaN(z)) return tree; // ignore invalid points
var parent,
node = tree._root,
leaf = {data: d},
x0 = tree._x0,
y0 = tree._y0,
z0 = tree._z0,
x1 = tree._x1,
y1 = tree._y1,
z1 = tree._z1,
xm,
ym,
zm,
xp,
yp,
zp,
right,
bottom,
deep,
i,
j;
// If the tree is empty, initialize the root as a leaf.
if (!node) return tree._root = leaf, tree;
// Find the existing leaf for the new point, or add it.
while (node.length) {
if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
if (deep = z >= (zm = (z0 + z1) / 2)) z0 = zm; else z1 = zm;
if (parent = node, !(node = node[i = deep << 2 | bottom << 1 | right])) return parent[i] = leaf, tree;
}
// Is the new point is exactly coincident with the existing point?
xp = +tree._x.call(null, node.data);
yp = +tree._y.call(null, node.data);
zp = +tree._z.call(null, node.data);
if (x === xp && y === yp && z === zp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree;
// Otherwise, split the leaf node until the old and new point are separated.
do {
parent = parent ? parent[i] = new Array(8) : tree._root = new Array(8);
if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
if (deep = z >= (zm = (z0 + z1) / 2)) z0 = zm; else z1 = zm;
} while ((i = deep << 2 | bottom << 1 | right) === (j = (zp >= zm) << 2 | (yp >= ym) << 1 | (xp >= xm)));
return parent[j] = node, parent[i] = leaf, tree;
}
function addAll(data) {
if (!Array.isArray(data)) data = Array.from(data);
const n = data.length;
const xz = new Float64Array(n);
const yz = new Float64Array(n);
const zz = new Float64Array(n);
let x0 = Infinity,
y0 = Infinity,
z0 = Infinity,
x1 = -Infinity,
y1 = -Infinity,
z1 = -Infinity;
// Compute the points and their extent.
for (let i = 0, d, x, y, z; i < n; ++i) {
if (isNaN(x = +this._x.call(null, d = data[i])) || isNaN(y = +this._y.call(null, d)) || isNaN(z = +this._z.call(null, d))) continue;
xz[i] = x;
yz[i] = y;
zz[i] = z;
if (x < x0) x0 = x;
if (x > x1) x1 = x;
if (y < y0) y0 = y;
if (y > y1) y1 = y;
if (z < z0) z0 = z;
if (z > z1) z1 = z;
}
// If there were no (valid) points, abort.
if (x0 > x1 || y0 > y1 || z0 > z1) return this;
// Expand the tree to cover the new points.
this.cover(x0, y0, z0).cover(x1, y1, z1);
// Add the new points.
for (let i = 0; i < n; ++i) {
add(this, xz[i], yz[i], zz[i], data[i]);
}
return this;
}
function tree_cover(x, y, z) {
if (isNaN(x = +x) || isNaN(y = +y) || isNaN(z = +z)) return this; // ignore invalid points
var x0 = this._x0,
y0 = this._y0,
z0 = this._z0,
x1 = this._x1,
y1 = this._y1,
z1 = this._z1;
// If the octree has no extent, initialize them.
// Integer extent are necessary so that if we later double the extent,
// the existing octant boundaries dont change due to floating point error!
if (isNaN(x0)) {
x1 = (x0 = Math.floor(x)) + 1;
y1 = (y0 = Math.floor(y)) + 1;
z1 = (z0 = Math.floor(z)) + 1;
}
// Otherwise, double repeatedly to cover.
else {
var t = x1 - x0 || 1,
node = this._root,
parent,
i;
while (x0 > x || x >= x1 || y0 > y || y >= y1 || z0 > z || z >= z1) {
i = (z < z0) << 2 | (y < y0) << 1 | (x < x0);
parent = new Array(8), parent[i] = node, node = parent, t *= 2;
switch (i) {
case 0: x1 = x0 + t, y1 = y0 + t, z1 = z0 + t; break;
case 1: x0 = x1 - t, y1 = y0 + t, z1 = z0 + t; break;
case 2: x1 = x0 + t, y0 = y1 - t, z1 = z0 + t; break;
case 3: x0 = x1 - t, y0 = y1 - t, z1 = z0 + t; break;
case 4: x1 = x0 + t, y1 = y0 + t, z0 = z1 - t; break;
case 5: x0 = x1 - t, y1 = y0 + t, z0 = z1 - t; break;
case 6: x1 = x0 + t, y0 = y1 - t, z0 = z1 - t; break;
case 7: x0 = x1 - t, y0 = y1 - t, z0 = z1 - t; break;
}
}
if (this._root && this._root.length) this._root = node;
}
this._x0 = x0;
this._y0 = y0;
this._z0 = z0;
this._x1 = x1;
this._y1 = y1;
this._z1 = z1;
return this;
}
function tree_data() {
var data = [];
this.visit(function(node) {
if (!node.length) do data.push(node.data); while (node = node.next)
});
return data;
}
function tree_extent(_) {
return arguments.length
? this.cover(+_[0][0], +_[0][1], +_[0][2]).cover(+_[1][0], +_[1][1], +_[1][2])
: isNaN(this._x0) ? undefined : [[this._x0, this._y0, this._z0], [this._x1, this._y1, this._z1]];
}
function Octant(node, x0, y0, z0, x1, y1, z1) {
this.node = node;
this.x0 = x0;
this.y0 = y0;
this.z0 = z0;
this.x1 = x1;
this.y1 = y1;
this.z1 = z1;
}
function tree_find(x, y, z, radius) {
var data,
x0 = this._x0,
y0 = this._y0,
z0 = this._z0,
x1,
y1,
z1,
x2,
y2,
z2,
x3 = this._x1,
y3 = this._y1,
z3 = this._z1,
octs = [],
node = this._root,
q,
i;
if (node) octs.push(new Octant(node, x0, y0, z0, x3, y3, z3));
if (radius == null) radius = Infinity;
else {
x0 = x - radius, y0 = y - radius, z0 = z - radius;
x3 = x + radius, y3 = y + radius, z3 = z + radius;
radius *= radius;
}
while (q = octs.pop()) {
// Stop searching if this octant cant contain a closer node.
if (!(node = q.node)
|| (x1 = q.x0) > x3
|| (y1 = q.y0) > y3
|| (z1 = q.z0) > z3
|| (x2 = q.x1) < x0
|| (y2 = q.y1) < y0
|| (z2 = q.z1) < z0) continue;
// Bisect the current octant.
if (node.length) {
var xm = (x1 + x2) / 2,
ym = (y1 + y2) / 2,
zm = (z1 + z2) / 2;
octs.push(
new Octant(node[7], xm, ym, zm, x2, y2, z2),
new Octant(node[6], x1, ym, zm, xm, y2, z2),
new Octant(node[5], xm, y1, zm, x2, ym, z2),
new Octant(node[4], x1, y1, zm, xm, ym, z2),
new Octant(node[3], xm, ym, z1, x2, y2, zm),
new Octant(node[2], x1, ym, z1, xm, y2, zm),
new Octant(node[1], xm, y1, z1, x2, ym, zm),
new Octant(node[0], x1, y1, z1, xm, ym, zm)
);
// Visit the closest octant first.
if (i = (z >= zm) << 2 | (y >= ym) << 1 | (x >= xm)) {
q = octs[octs.length - 1];
octs[octs.length - 1] = octs[octs.length - 1 - i];
octs[octs.length - 1 - i] = q;
}
}
// Visit this point. (Visiting coincident points isnt necessary!)
else {
var dx = x - +this._x.call(null, node.data),
dy = y - +this._y.call(null, node.data),
dz = z - +this._z.call(null, node.data),
d2 = dx * dx + dy * dy + dz * dz;
if (d2 < radius) {
var d = Math.sqrt(radius = d2);
x0 = x - d, y0 = y - d, z0 = z - d;
x3 = x + d, y3 = y + d, z3 = z + d;
data = node.data;
}
}
}
return data;
}
function tree_remove(d) {
if (isNaN(x = +this._x.call(null, d)) || isNaN(y = +this._y.call(null, d)) || isNaN(z = +this._z.call(null, d))) return this; // ignore invalid points
var parent,
node = this._root,
retainer,
previous,
next,
x0 = this._x0,
y0 = this._y0,
z0 = this._z0,
x1 = this._x1,
y1 = this._y1,
z1 = this._z1,
x,
y,
z,
xm,
ym,
zm,
right,
bottom,
deep,
i,
j;
// If the tree is empty, initialize the root as a leaf.
if (!node) return this;
// Find the leaf node for the point.
// While descending, also retain the deepest parent with a non-removed sibling.
if (node.length) while (true) {
if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
if (deep = z >= (zm = (z0 + z1) / 2)) z0 = zm; else z1 = zm;
if (!(parent = node, node = node[i = deep << 2 | bottom << 1 | right])) return this;
if (!node.length) break;
if (parent[(i + 1) & 7] || parent[(i + 2) & 7] || parent[(i + 3) & 7] || parent[(i + 4) & 7] || parent[(i + 5) & 7] || parent[(i + 6) & 7] || parent[(i + 7) & 7]) retainer = parent, j = i;
}
// Find the point to remove.
while (node.data !== d) if (!(previous = node, node = node.next)) return this;
if (next = node.next) delete node.next;
// If there are multiple coincident points, remove just the point.
if (previous) return (next ? previous.next = next : delete previous.next), this;
// If this is the root point, remove it.
if (!parent) return this._root = next, this;
// Remove this leaf.
next ? parent[i] = next : delete parent[i];
// If the parent now contains exactly one leaf, collapse superfluous parents.
if ((node = parent[0] || parent[1] || parent[2] || parent[3] || parent[4] || parent[5] || parent[6] || parent[7])
&& node === (parent[7] || parent[6] || parent[5] || parent[4] || parent[3] || parent[2] || parent[1] || parent[0])
&& !node.length) {
if (retainer) retainer[j] = node;
else this._root = node;
}
return this;
}
function removeAll(data) {
for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]);
return this;
}
function tree_root() {
return this._root;
}
function tree_size() {
var size = 0;
this.visit(function(node) {
if (!node.length) do ++size; while (node = node.next)
});
return size;
}
function tree_visit(callback) {
var octs = [], q, node = this._root, child, x0, y0, z0, x1, y1, z1;
if (node) octs.push(new Octant(node, this._x0, this._y0, this._z0, this._x1, this._y1, this._z1));
while (q = octs.pop()) {
if (!callback(node = q.node, x0 = q.x0, y0 = q.y0, z0 = q.z0, x1 = q.x1, y1 = q.y1, z1 = q.z1) && node.length) {
var xm = (x0 + x1) / 2, ym = (y0 + y1) / 2, zm = (z0 + z1) / 2;
if (child = node[7]) octs.push(new Octant(child, xm, ym, zm, x1, y1, z1));
if (child = node[6]) octs.push(new Octant(child, x0, ym, zm, xm, y1, z1));
if (child = node[5]) octs.push(new Octant(child, xm, y0, zm, x1, ym, z1));
if (child = node[4]) octs.push(new Octant(child, x0, y0, zm, xm, ym, z1));
if (child = node[3]) octs.push(new Octant(child, xm, ym, z0, x1, y1, zm));
if (child = node[2]) octs.push(new Octant(child, x0, ym, z0, xm, y1, zm));
if (child = node[1]) octs.push(new Octant(child, xm, y0, z0, x1, ym, zm));
if (child = node[0]) octs.push(new Octant(child, x0, y0, z0, xm, ym, zm));
}
}
return this;
}
function tree_visitAfter(callback) {
var octs = [], next = [], q;
if (this._root) octs.push(new Octant(this._root, this._x0, this._y0, this._z0, this._x1, this._y1, this._z1));
while (q = octs.pop()) {
var node = q.node;
if (node.length) {
var child, x0 = q.x0, y0 = q.y0, z0 = q.z0, x1 = q.x1, y1 = q.y1, z1 = q.z1, xm = (x0 + x1) / 2, ym = (y0 + y1) / 2, zm = (z0 + z1) / 2;
if (child = node[0]) octs.push(new Octant(child, x0, y0, z0, xm, ym, zm));
if (child = node[1]) octs.push(new Octant(child, xm, y0, z0, x1, ym, zm));
if (child = node[2]) octs.push(new Octant(child, x0, ym, z0, xm, y1, zm));
if (child = node[3]) octs.push(new Octant(child, xm, ym, z0, x1, y1, zm));
if (child = node[4]) octs.push(new Octant(child, x0, y0, zm, xm, ym, z1));
if (child = node[5]) octs.push(new Octant(child, xm, y0, zm, x1, ym, z1));
if (child = node[6]) octs.push(new Octant(child, x0, ym, zm, xm, y1, z1));
if (child = node[7]) octs.push(new Octant(child, xm, ym, zm, x1, y1, z1));
}
next.push(q);
}
while (q = next.pop()) {
callback(q.node, q.x0, q.y0, q.z0, q.x1, q.y1, q.z1);
}
return this;
}
function defaultX(d) {
return d[0];
}
function tree_x(_) {
return arguments.length ? (this._x = _, this) : this._x;
}
function defaultY(d) {
return d[1];
}
function tree_y(_) {
return arguments.length ? (this._y = _, this) : this._y;
}
function defaultZ(d) {
return d[2];
}
function tree_z(_) {
return arguments.length ? (this._z = _, this) : this._z;
}
function octree(nodes, x, y, z) {
var tree = new Octree(x == null ? defaultX : x, y == null ? defaultY : y, z == null ? defaultZ : z, NaN, NaN, NaN, NaN, NaN, NaN);
return nodes == null ? tree : tree.addAll(nodes);
}
function Octree(x, y, z, x0, y0, z0, x1, y1, z1) {
this._x = x;
this._y = y;
this._z = z;
this._x0 = x0;
this._y0 = y0;
this._z0 = z0;
this._x1 = x1;
this._y1 = y1;
this._z1 = z1;
this._root = undefined;
}
function leaf_copy(leaf) {
var copy = {data: leaf.data}, next = copy;
while (leaf = leaf.next) next = next.next = {data: leaf.data};
return copy;
}
var treeProto = octree.prototype = Octree.prototype;
treeProto.copy = function() {
var copy = new Octree(this._x, this._y, this._z, this._x0, this._y0, this._z0, this._x1, this._y1, this._z1),
node = this._root,
nodes,
child;
if (!node) return copy;
if (!node.length) return copy._root = leaf_copy(node), copy;
nodes = [{source: node, target: copy._root = new Array(8)}];
while (node = nodes.pop()) {
for (var i = 0; i < 8; ++i) {
if (child = node.source[i]) {
if (child.length) nodes.push({source: child, target: node.target[i] = new Array(8)});
else node.target[i] = leaf_copy(child);
}
}
}
return copy;
};
treeProto.add = tree_add;
treeProto.addAll = addAll;
treeProto.cover = tree_cover;
treeProto.data = tree_data;
treeProto.extent = tree_extent;
treeProto.find = tree_find;
treeProto.remove = tree_remove;
treeProto.removeAll = removeAll;
treeProto.root = tree_root;
treeProto.size = tree_size;
treeProto.visit = tree_visit;
treeProto.visitAfter = tree_visitAfter;
treeProto.x = tree_x;
treeProto.y = tree_y;
treeProto.z = tree_z;
exports.octree = octree;
}));