angular-3d-viewer
Version:
161 lines (142 loc) • 4.91 kB
JavaScript
import { Box3D } from './box3d.js';
import { Coord3D, CoordIsEqual3D } from './coord3d.js';
import { IsGreaterOrEqual, IsLowerOrEqual } from './geometry.js';
export class OctreeNode
{
constructor (boundingBox, level)
{
this.boundingBox = boundingBox;
this.level = level;
this.pointItems = [];
this.childNodes = [];
}
AddPoint (point, data, options)
{
let node = this.FindNodeForPoint (point);
if (node === null) {
return false;
}
if (node.FindPointDirectly (point) !== null) {
return false;
}
if (node.pointItems.length < options.maxPointsPerNode || node.level >= options.maxTreeDepth) {
node.AddPointDirectly (point, data);
return true;
} else {
node.CreateChildNodes ();
let oldPointItems = node.pointItems;
node.pointItems = [];
for (let i = 0; i < oldPointItems.length; i++) {
let pointItem = oldPointItems[i];
if (!node.AddPoint (pointItem.point, pointItem.data, options)) {
return false;
}
}
return node.AddPoint (point, data, options);
}
}
FindPoint (point)
{
let node = this.FindNodeForPoint (point);
if (node === null) {
return null;
}
return node.FindPointDirectly (point);
}
AddPointDirectly (point, data)
{
this.pointItems.push ({
point : point,
data : data
});
}
FindPointDirectly (point)
{
for (let i = 0; i < this.pointItems.length; i++) {
let pointItem = this.pointItems[i];
if (CoordIsEqual3D (point, pointItem.point)) {
return pointItem.data;
}
}
return null;
}
FindNodeForPoint (point)
{
if (!this.IsPointInBounds (point)) {
return null;
}
if (this.childNodes.length === 0) {
return this;
}
for (let i = 0; i < this.childNodes.length; i++) {
let childNode = this.childNodes[i];
let foundNode = childNode.FindNodeForPoint (point);
if (foundNode !== null) {
return foundNode;
}
}
return null;
}
CreateChildNodes ()
{
function AddChildNode (node, minX, minY, minZ, sizeX, sizeY, sizeZ)
{
let box = new Box3D (
new Coord3D (minX, minY, minZ),
new Coord3D (minX + sizeX, minY + sizeY, minZ + sizeZ)
);
node.childNodes.push (new OctreeNode (box, node.level + 1));
}
let min = this.boundingBox.min;
let center = this.boundingBox.GetCenter ();
let sizeX = (this.boundingBox.max.x - this.boundingBox.min.x) / 2.0;
let sizeY = (this.boundingBox.max.y - this.boundingBox.min.y) / 2.0;
let sizeZ = (this.boundingBox.max.z - this.boundingBox.min.z) / 2.0;
AddChildNode (this, min.x, min.y, min.z, sizeX, sizeY, sizeZ);
AddChildNode (this, center.x, min.y, min.z, sizeX, sizeY, sizeZ);
AddChildNode (this, min.x, center.y, min.z, sizeX, sizeY, sizeZ);
AddChildNode (this, center.x, center.y, min.z, sizeX, sizeY, sizeZ);
AddChildNode (this, min.x, min.y, center.z, sizeX, sizeY, sizeZ);
AddChildNode (this, center.x, min.y, center.z, sizeX, sizeY, sizeZ);
AddChildNode (this, min.x, center.y, center.z, sizeX, sizeY, sizeZ);
AddChildNode (this, center.x, center.y, center.z, sizeX, sizeY, sizeZ);
}
IsPointInBounds (point)
{
let isEqual =
IsGreaterOrEqual (point.x, this.boundingBox.min.x) &&
IsGreaterOrEqual (point.y, this.boundingBox.min.y) &&
IsGreaterOrEqual (point.z, this.boundingBox.min.z) &&
IsLowerOrEqual (point.x, this.boundingBox.max.x) &&
IsLowerOrEqual (point.y, this.boundingBox.max.y) &&
IsLowerOrEqual (point.z, this.boundingBox.max.z);
return isEqual;
}
}
export class Octree
{
constructor (boundingBox, options)
{
this.options = {
maxPointsPerNode : 10,
maxTreeDepth : 10
};
if (options !== undefined) {
if (options.maxPointsPerNode !== undefined) {
this.options.maxPointsPerNode = options.maxPointsPerNode;
}
if (options.maxTreeDepth !== undefined) {
this.options.maxTreeDepth = options.maxTreeDepth;
}
}
this.rootNode = new OctreeNode (boundingBox, 0);
}
AddPoint (point, data)
{
return this.rootNode.AddPoint (point, data, this.options);
}
FindPoint (point)
{
return this.rootNode.FindPoint (point);
}
}