Skip to content

Commit

Permalink
Merge 4e70d21 into d047778
Browse files Browse the repository at this point in the history
  • Loading branch information
Eronana committed Jul 2, 2018
2 parents d047778 + 4e70d21 commit 0f7e9c6
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ npm-debug.log
coverage
rbush3d.js
rbush3d.min.js
package-lock.json
6 changes: 6 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,15 @@ interface ToBBox {

interface RBush3D {
all():BBox[];
search(bbox:any):any[];
search(bbox:BBox):BBox[];
collides(bbox:any):boolean;
collides(bbox:BBox):boolean;
raycastInv(ox:number, oy:number, oz:number, idx:number, idy:number, idz:number, length = Infinity):BBox|undefined;
raycast(ox:number, oy:number, oz:number, dx:number, dy:number, dz:number, length = Infinity):BBox|undefined;
load(data:any[]):this;
load(data:BBox[]):this;
insert(item:any):this;
insert(item:BBox):this;
clear():this;
remove(item:BBox, equalsFn?:EqualsFn):this;
Expand Down
64 changes: 64 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module.exports = rbush3d;
module.exports.default = rbush3d;

var quickselect = require('quickselect');
var Heap = require('heap');

function rbush3d(maxEntries, format) {
if (!(this instanceof rbush3d)) return new rbush3d(maxEntries, format);
Expand Down Expand Up @@ -81,6 +82,49 @@ rbush3d.prototype = {
return false;
},

raycastInv: function (ox, oy, oz, idx, idy, idz, length) {
length = length || Infinity;
var node = this.data,
toBBox = this.toBBox,
result,
dist = length;

if (idx === Infinity && idy === Infinity && idz === Infinity) return undefined;
if (boxRayIntersects(node, ox, oy, oz, idx, idy, idz) === Infinity) return undefined;

var nodesToSearch = new Heap(function (a, b) {
return a.dist - b.dist;
});
nodesToSearch.push({
dist: dist,
node: node,
});
while (!nodesToSearch.empty() && nodesToSearch.top().dist <= dist) {
node = nodesToSearch.pop().node;
for (var i = 0, len = node.children.length; i < len; i++) {
var child = node.children[i];
var childBBox = node.leaf ? toBBox(child) : child;
var d = boxRayIntersects(childBBox, ox, oy, oz, idx, idy, idz);
if (d < dist) {
if (!node.leaf) {
nodesToSearch.push({
dist: d,
node: child,
});
} else {
dist = d;
result = child;
}
}
}
}
return result;
},

raycast: function (ox, oy, oz, dx, dy, dz, length) {
return this.raycastInv(ox, oy, oz, 1 / dx, 1 / dy, 1 / dz, length);
},

load: function (data) {
if (!(data && data.length)) return this;

Expand Down Expand Up @@ -575,6 +619,26 @@ function intersects(a, b) {
b.maxZ >= a.minZ;
}

function boxRayIntersects(box, ox, oy, oz, idx, idy, idz) {
var tx0 = (box.minX - ox) * idx;
var tx1 = (box.maxX - ox) * idx;
var ty0 = (box.minY - oy) * idy;
var ty1 = (box.maxY - oy) * idy;
var tz0 = (box.minZ - oz) * idz;
var tz1 = (box.maxZ - oz) * idz;

var z0 = Math.min(tz0, tz1);
var z1 = Math.max(tz0, tz1);
var y0 = Math.min(ty0, ty1);
var y1 = Math.max(ty0, ty1);
var x0 = Math.min(tx0, tx1);
var x1 = Math.max(tx0, tx1);

var tmin = Math.max(x0, y0, z0);
var tmax = Math.min(x1, y1, z1);
return tmax < 0 || tmin > tmax ? Infinity : tmin;
}

function createNode(children) {
return {
children: children,
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rbush-3d",
"version": "0.0.2",
"version": "0.0.3",
"description": "High-performance 3D spatial index for cuboids (based on R*-tree with bulk loading and bulk insertion algorithms)",
"homepage": "https://github.com/eronana/rbush-3d",
"repository": {
Expand Down Expand Up @@ -53,6 +53,7 @@
}
},
"dependencies": {
"heap": "^0.2.6",
"quickselect": "^1.0.0"
}
}
95 changes: 95 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,41 @@ function intersects(a, b) {
b.maxZ >= a.minZ;
}

function boxRayIntersects(box, ox, oy, oz, idx, idy, idz) {
var tx0 = (box.minX - ox) * idx;
var tx1 = (box.maxX - ox) * idx;
var ty0 = (box.minY - oy) * idy;
var ty1 = (box.maxY - oy) * idy;
var tz0 = (box.minZ - oz) * idz;
var tz1 = (box.maxZ - oz) * idz;

var z0 = Math.min(tz0, tz1);
var z1 = Math.max(tz0, tz1);
var y0 = Math.min(ty0, ty1);
var y1 = Math.max(ty0, ty1);
var x0 = Math.min(tx0, tx1);
var x1 = Math.max(tx0, tx1);

var tmin = Math.max(x0, y0, z0);
var tmax = Math.min(x1, y1, z1);
return tmax < 0 || tmin > tmax ? Infinity : tmin;
}

function bfRaycast(data, ox, oy, oz, dx, dy, dz) {
if (!dx && !dy && !dz) return undefined;
var idx = 1 / dx, idy = 1 / dy, idz = 1 / dz;
var dist = Infinity;
var result;
data.forEach(function (node) {
var d = boxRayIntersects(node, ox, oy, oz, idx, idy, idz);
if (d < dist) {
dist = d;
result = node;
}
});
return result;
}

function bfSearch(bbox, data) {
return data.filter(function (node) {
return intersects(bbox, node);
Expand Down Expand Up @@ -514,3 +549,63 @@ t('#collides with random data', function (t) {
});
t.end();
});

t('#raycast with one bbox', function (t) {
var tree = rbush3d();
tree.insert({
minX: 1,
minY: 1,
minZ: 1,
maxX: 100,
maxY: 100,
maxZ: 100,
});
t.equal(tree.raycast(0, 0, 0, 1, 0, 0), undefined);
t.equal(tree.raycast(0, 0, 0, 0, 1, 0), undefined);
t.equal(tree.raycast(0, 0, 0, 0, 0, 1), undefined);
t.equal(tree.raycast(0, 0, 0, 1, 1, 0), undefined);
t.equal(tree.raycast(0, 0, 0, 0, 1, 1), undefined);
t.equal(tree.raycast(0, 0, 0, 1, 0, 1), undefined);
t.equal(tree.raycast(0, 0, 0, -1, 0, 0), undefined);
t.equal(tree.raycast(0, 0, 0, 0, -1, 0), undefined);
t.equal(tree.raycast(0, 0, 0, 0, 0, -1), undefined);
t.equal(tree.raycast(0, 0, 0, -1, -1, 0), undefined);
t.equal(tree.raycast(0, 0, 0, 0, -1, -1), undefined);
t.equal(tree.raycast(0, 0, 0, -1, 0, -1), undefined);
t.equal(tree.raycast(0, 0, 0, -1, -1, -1), undefined);
t.equal(tree.raycast(50, 50, 50, 0, 0, 0), undefined);
t.notEqual(tree.raycast(0, 0, 0, 1, 1, 1), undefined);
t.notEqual(tree.raycast(20, 20, 20, 1, 1, 1), undefined);
t.notEqual(tree.raycast(50, 50, 0, 0, 0, 1), undefined);
t.end();
});

t('#raycast with finite length', function (t) {
var tree = rbush3d();
tree.insert({
minX: 100,
minY: 100,
minZ: 100,
maxX: 200,
maxY: 200,
maxZ: 200,
});
t.equal(tree.raycast(0, 0, 0, 1, 1, 1, 99), undefined);
t.notEqual(tree.raycast(0, 0, 0, 1, 1, 1, 101), undefined);
t.equal(tree.raycast(150, 150, 50, 0, 0, 1, 49), undefined);
t.notEqual(tree.raycast(150, 150, 50, 0, 0, 1, 51), undefined);
t.end();
});

t('#raycast with ramdom bboxes', function (t) {
var randomBoxes = randBoxes(2000, 200);
var randomRays = randBoxes(2000, 200);
var tree = rbush3d(8).load(randomBoxes);
const data = tree.all();
randomRays.forEach(function (ray) {
return t.equal(
bfRaycast(data, ray.minX, ray.minY, ray.minZ, ray.maxX, ray.maxY, ray.maxZ),
tree.raycast(ray.minX, ray.minY, ray.minZ, ray.maxX, ray.maxY, ray.maxZ));
});
t.end();
});

0 comments on commit 0f7e9c6

Please sign in to comment.