quadtree.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import * as THREE from 'https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js';
  2. export const quadtree = (function() {
  3. class CubeQuadTree {
  4. constructor(params) {
  5. this._params = params;
  6. this._sides = [];
  7. const r = params.radius;
  8. let m;
  9. const transforms = [];
  10. // +Y
  11. m = new THREE.Matrix4();
  12. m.makeRotationX(-Math.PI / 2);
  13. m.premultiply(new THREE.Matrix4().makeTranslation(0, r, 0));
  14. transforms.push(m);
  15. // -Y
  16. m = new THREE.Matrix4();
  17. m.makeRotationX(Math.PI / 2);
  18. m.premultiply(new THREE.Matrix4().makeTranslation(0, -r, 0));
  19. transforms.push(m);
  20. // +X
  21. m = new THREE.Matrix4();
  22. m.makeRotationY(Math.PI / 2);
  23. m.premultiply(new THREE.Matrix4().makeTranslation(r, 0, 0));
  24. transforms.push(m);
  25. // -X
  26. m = new THREE.Matrix4();
  27. m.makeRotationY(-Math.PI / 2);
  28. m.premultiply(new THREE.Matrix4().makeTranslation(-r, 0, 0));
  29. transforms.push(m);
  30. // +Z
  31. m = new THREE.Matrix4();
  32. m.premultiply(new THREE.Matrix4().makeTranslation(0, 0, r));
  33. transforms.push(m);
  34. // -Z
  35. m = new THREE.Matrix4();
  36. m.makeRotationY(Math.PI);
  37. m.premultiply(new THREE.Matrix4().makeTranslation(0, 0, -r));
  38. transforms.push(m);
  39. for (let t of transforms) {
  40. this._sides.push({
  41. transform: t.clone(),
  42. worldToLocal: t.clone().getInverse(t),
  43. quadtree: new QuadTree({
  44. size: r,
  45. min_node_size: params.min_node_size,
  46. localToWorld: t
  47. }),
  48. });
  49. }
  50. }
  51. GetChildren() {
  52. const children = [];
  53. for (let s of this._sides) {
  54. const side = {
  55. transform: s.transform,
  56. children: s.quadtree.GetChildren(),
  57. }
  58. children.push(side);
  59. }
  60. return children;
  61. }
  62. Insert(pos) {
  63. for (let s of this._sides) {
  64. s.quadtree.Insert(pos);
  65. }
  66. }
  67. }
  68. class QuadTree {
  69. constructor(params) {
  70. const s = params.size;
  71. const b = new THREE.Box3(
  72. new THREE.Vector3(-s, -s, 0),
  73. new THREE.Vector3(s, s, 0));
  74. this._root = {
  75. bounds: b,
  76. children: [],
  77. center: b.getCenter(new THREE.Vector3()),
  78. sphereCenter: b.getCenter(new THREE.Vector3()),
  79. size: b.getSize(new THREE.Vector3()),
  80. root: true,
  81. };
  82. this._params = params;
  83. this._root.sphereCenter = this._root.center.clone();
  84. this._root.sphereCenter.applyMatrix4(this._params.localToWorld);
  85. this._root.sphereCenter.normalize();
  86. this._root.sphereCenter.multiplyScalar(this._params.size);
  87. }
  88. GetChildren() {
  89. const children = [];
  90. this._GetChildren(this._root, children);
  91. return children;
  92. }
  93. _GetChildren(node, target) {
  94. if (node.children.length == 0) {
  95. target.push(node);
  96. return;
  97. }
  98. for (let c of node.children) {
  99. this._GetChildren(c, target);
  100. }
  101. }
  102. Insert(pos) {
  103. this._Insert(this._root, pos);
  104. }
  105. _Insert(child, pos) {
  106. const distToChild = this._DistanceToChild(child, pos);
  107. if (distToChild < child.size.x * 1.0 && child.size.x > this._params.min_node_size) {
  108. child.children = this._CreateChildren(child);
  109. for (let c of child.children) {
  110. this._Insert(c, pos);
  111. }
  112. }
  113. }
  114. _DistanceToChild(child, pos) {
  115. return child.sphereCenter.distanceTo(pos);
  116. }
  117. _CreateChildren(child) {
  118. const midpoint = child.bounds.getCenter(new THREE.Vector3());
  119. // Bottom left
  120. const b1 = new THREE.Box3(child.bounds.min, midpoint);
  121. // Bottom right
  122. const b2 = new THREE.Box3(
  123. new THREE.Vector3(midpoint.x, child.bounds.min.y, 0),
  124. new THREE.Vector3(child.bounds.max.x, midpoint.y, 0));
  125. // Top left
  126. const b3 = new THREE.Box3(
  127. new THREE.Vector3(child.bounds.min.x, midpoint.y, 0),
  128. new THREE.Vector3(midpoint.x, child.bounds.max.y, 0));
  129. // Top right
  130. const b4 = new THREE.Box3(midpoint, child.bounds.max);
  131. const children = [b1, b2, b3, b4].map(
  132. b => {
  133. return {
  134. bounds: b,
  135. children: [],
  136. center: b.getCenter(new THREE.Vector3()),
  137. size: b.getSize(new THREE.Vector3())
  138. };
  139. });
  140. for (let c of children) {
  141. c.sphereCenter = c.center.clone();
  142. c.sphereCenter.applyMatrix4(this._params.localToWorld);
  143. c.sphereCenter.normalize()
  144. c.sphereCenter.multiplyScalar(this._params.size);
  145. }
  146. return children;
  147. }
  148. }
  149. return {
  150. QuadTree: QuadTree,
  151. CubeQuadTree: CubeQuadTree,
  152. }
  153. })();