import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.112.1/build/three.module.js'; export const quadtree = (function() { class CubeQuadTree { constructor(params) { this._params = params; this._sides = []; const r = params.radius; let m; const transforms = []; // +Y m = new THREE.Matrix4(); m.makeRotationX(-Math.PI / 2); m.premultiply(new THREE.Matrix4().makeTranslation(0, r, 0)); transforms.push(m); // -Y m = new THREE.Matrix4(); m.makeRotationX(Math.PI / 2); m.premultiply(new THREE.Matrix4().makeTranslation(0, -r, 0)); transforms.push(m); // +X m = new THREE.Matrix4(); m.makeRotationY(Math.PI / 2); m.premultiply(new THREE.Matrix4().makeTranslation(r, 0, 0)); transforms.push(m); // -X m = new THREE.Matrix4(); m.makeRotationY(-Math.PI / 2); m.premultiply(new THREE.Matrix4().makeTranslation(-r, 0, 0)); transforms.push(m); // +Z m = new THREE.Matrix4(); m.premultiply(new THREE.Matrix4().makeTranslation(0, 0, r)); transforms.push(m); // -Z m = new THREE.Matrix4(); m.makeRotationY(Math.PI); m.premultiply(new THREE.Matrix4().makeTranslation(0, 0, -r)); transforms.push(m); for (let t of transforms) { this._sides.push({ transform: t.clone(), worldToLocal: t.clone().getInverse(t), quadtree: new QuadTree({ size: r, min_node_size: params.min_node_size, localToWorld: t }), }); } } GetChildren() { const children = []; for (let s of this._sides) { const side = { transform: s.transform, children: s.quadtree.GetChildren(), } children.push(side); } return children; } Insert(pos) { for (let s of this._sides) { s.quadtree.Insert(pos); } } } class QuadTree { constructor(params) { const s = params.size; const b = new THREE.Box3( new THREE.Vector3(-s, -s, 0), new THREE.Vector3(s, s, 0)); this._root = { bounds: b, children: [], center: b.getCenter(new THREE.Vector3()), sphereCenter: b.getCenter(new THREE.Vector3()), size: b.getSize(new THREE.Vector3()), root: true, }; this._params = params; this._root.sphereCenter = this._root.center.clone(); this._root.sphereCenter.applyMatrix4(this._params.localToWorld); this._root.sphereCenter.normalize(); this._root.sphereCenter.multiplyScalar(this._params.size); } GetChildren() { const children = []; this._GetChildren(this._root, children); return children; } _GetChildren(node, target) { if (node.children.length == 0) { target.push(node); return; } for (let c of node.children) { this._GetChildren(c, target); } } Insert(pos) { this._Insert(this._root, pos); } _Insert(child, pos) { const distToChild = this._DistanceToChild(child, pos); if (distToChild < child.size.x * 1.0 && child.size.x > this._params.min_node_size) { child.children = this._CreateChildren(child); for (let c of child.children) { this._Insert(c, pos); } } } _DistanceToChild(child, pos) { return child.sphereCenter.distanceTo(pos); } _CreateChildren(child) { const midpoint = child.bounds.getCenter(new THREE.Vector3()); // Bottom left const b1 = new THREE.Box3(child.bounds.min, midpoint); // Bottom right const b2 = new THREE.Box3( new THREE.Vector3(midpoint.x, child.bounds.min.y, 0), new THREE.Vector3(child.bounds.max.x, midpoint.y, 0)); // Top left const b3 = new THREE.Box3( new THREE.Vector3(child.bounds.min.x, midpoint.y, 0), new THREE.Vector3(midpoint.x, child.bounds.max.y, 0)); // Top right const b4 = new THREE.Box3(midpoint, child.bounds.max); const children = [b1, b2, b3, b4].map( b => { return { bounds: b, children: [], center: b.getCenter(new THREE.Vector3()), size: b.getSize(new THREE.Vector3()) }; }); for (let c of children) { c.sphereCenter = c.center.clone(); c.sphereCenter.applyMatrix4(this._params.localToWorld); c.sphereCenter.normalize() c.sphereCenter.multiplyScalar(this._params.size); } return children; } } return { QuadTree: QuadTree, CubeQuadTree: CubeQuadTree, } })();