UNPKG

angular-3d-viewer

Version:
161 lines (142 loc) 4.91 kB
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); } }