import { Vec3 } from "./vec3"; export class Octtree { constructor(dimensions, maxObjects = 10, maxLevels = 10) { this.dimensions = dimensions; this.maxObjects = maxObjects; this.maxLevels = maxLevels; this.root = new OctTreeNode(new Vec3({ x: 0, y: 0, z: 0 }), this.dimensions, maxLevels, maxObjects); } insert(obj) { this.root.insert(obj); } find(position, dimensions) { return this.root.find(position, dimensions); } } export class OctTreeNode { constructor(position, dimensions, maxLevels, maxObjects) { this.position = position; this.dimensions = dimensions; this.maxLevels = maxLevels; this.maxObjects = maxObjects; this.objects = []; this.nodes = []; } insert(obj) { this.objects.push(obj); if (this.objects.length > this.maxObjects) { this.split(); } } find(position, dimensions) { if (!this.nodes.length) { return this.objects; } const indecies = this.getIndeciesForRect(position, dimensions); let results = []; indecies.forEach((index) => { let res = this.nodes[index].find(position, dimensions); res.forEach((obj) => results.push(obj)); }); return results; } split() { const halfWidth = this.dimensions.x / 2; const halfHeight = this.dimensions.y / 2; const halfDepth = this.dimensions.z / 2; this.nodes[Direction.AboveUpperLeft] = new OctTreeNode(new Vec3({ x: this.position.x, y: this.position.y, z: this.position.z + halfDepth }), new Vec3({ x: halfWidth, y: halfHeight, z: halfDepth }), this.maxLevels, this.maxObjects); this.nodes[Direction.AboveUpperRight] = new OctTreeNode(new Vec3({ x: this.position.x + halfWidth, y: this.position.y, z: this.position.z + halfDepth }), new Vec3({ x: halfWidth, y: halfHeight, z: halfDepth }), this.maxLevels, this.maxObjects); this.nodes[Direction.AboveLowerRight] = new OctTreeNode(new Vec3({ x: this.position.x + halfWidth, y: this.position.y + halfHeight, z: this.position.z + halfDepth }), new Vec3({ x: halfWidth, y: halfHeight, z: halfDepth }), this.maxLevels, this.maxObjects); this.nodes[Direction.AboveLowerLeft] = new OctTreeNode(new Vec3({ x: this.position.x, y: this.position.y + halfHeight, z: this.position.z + halfDepth }), new Vec3({ x: halfWidth, y: halfHeight, z: halfDepth }), this.maxLevels, this.maxObjects); this.nodes[Direction.BelowUpperLeft] = new OctTreeNode(new Vec3({ x: this.position.x, y: this.position.y, z: this.position.z }), new Vec3({ x: halfWidth, y: halfHeight, z: halfDepth }), this.maxLevels, this.maxObjects); this.nodes[Direction.BelowUpperRight] = new OctTreeNode(new Vec3({ x: this.position.x + halfWidth, y: this.position.y, z: this.position.z }), new Vec3({ x: halfWidth, y: halfHeight, z: halfDepth }), this.maxLevels, this.maxObjects); this.nodes[Direction.BelowLowerRight] = new OctTreeNode(new Vec3({ x: this.position.x + halfWidth, y: this.position.y + halfHeight, z: this.position.z }), new Vec3({ x: halfWidth, y: halfHeight, z: halfDepth }), this.maxLevels, this.maxObjects); this.nodes[Direction.BelowLowerLeft] = new OctTreeNode(new Vec3({ x: this.position.x, y: this.position.y + halfHeight, z: this.position.z }), new Vec3({ x: halfWidth, y: halfHeight, z: halfDepth }), this.maxLevels, this.maxObjects); this.distributeObjectsToNodes(); } distributeObjectsToNodes() { if (this.nodes.length < 8) { this.split(); return; } this.objects.forEach((obj) => { const direction = this.getIndex(obj.position.x, obj.position.y, obj.position.z); this.nodes[direction].insert(obj); }); this.objects = []; } getIndex(x, y, z) { if (this.nodes.length === 0) { return Direction.Here; } const halfWidth = this.dimensions.x / 2; const halfHeight = this.dimensions.y / 2; const halfDepth = this.dimensions.z / 2; const isBelow = (z < this.position.z + halfDepth); const isLeft = (x < this.position.x + halfWidth); const isUpper = (y > this.position.y + halfHeight); if (isBelow) { if (isLeft) { if (isUpper) return Direction.AboveUpperLeft; else return Direction.AboveLowerLeft; } else { if (isUpper) return Direction.AboveUpperRight; else return Direction.AboveLowerRight; } } else { if (isLeft) { if (isUpper) return Direction.BelowUpperLeft; else return Direction.BelowLowerLeft; } else { if (isUpper) return Direction.BelowUpperRight; else return Direction.BelowLowerRight; } } } getIndeciesForRect(position, dimensions) { let indecies = new Set(); indecies.add(this.getIndex(position.x, position.y, position.z)); indecies.add(this.getIndex(position.x + dimensions.x, position.y + dimensions.y, position.z + dimensions.z)); return indecies; } } var Direction; (function (Direction) { Direction[Direction["AboveUpperLeft"] = 0] = "AboveUpperLeft"; Direction[Direction["AboveUpperRight"] = 1] = "AboveUpperRight"; Direction[Direction["AboveLowerRight"] = 2] = "AboveLowerRight"; Direction[Direction["AboveLowerLeft"] = 3] = "AboveLowerLeft"; Direction[Direction["BelowUpperLeft"] = 4] = "BelowUpperLeft"; Direction[Direction["BelowUpperRight"] = 5] = "BelowUpperRight"; Direction[Direction["BelowLowerRight"] = 6] = "BelowLowerRight"; Direction[Direction["BelowLowerLeft"] = 7] = "BelowLowerLeft"; Direction[Direction["Here"] = 8] = "Here"; })(Direction || (Direction = {}));