@woosh/meep-engine 2.67.0 → 2.68.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/build/meep.cjs +0 -1
  2. package/build/meep.module.js +0 -1
  3. package/package.json +1 -1
  4. package/src/engine/graphics/ecs/mesh/Mesh.d.ts +0 -1
  5. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.d.ts +0 -5
  6. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +0 -1
  7. package/src/engine/graphics/material/optimization/prototypeMaterialOptimizer.js +16 -19
  8. package/src/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +46 -47
  9. package/src/core/bvh2/BVHTasks.js +0 -65
  10. package/src/core/bvh2/BinaryNode.d.ts +0 -13
  11. package/src/core/bvh2/BinaryNode.js +0 -1188
  12. package/src/core/bvh2/BinaryNode.spec.js +0 -309
  13. package/src/core/bvh2/LeafNode.d.ts +0 -7
  14. package/src/core/bvh2/LeafNode.js +0 -147
  15. package/src/core/bvh2/Node.d.ts +0 -9
  16. package/src/core/bvh2/Node.js +0 -196
  17. package/src/core/bvh2/NodeValidator.js +0 -197
  18. package/src/core/bvh2/StacklessTraverser.js +0 -154
  19. package/src/core/bvh2/StacklessTraverser.spec.js +0 -109
  20. package/src/core/bvh2/serialization/deserializeBinaryNode.js +0 -40
  21. package/src/core/bvh2/serialization/deserializeBinaryNodeFromBinaryBuffer.js +0 -90
  22. package/src/core/bvh2/serialization/serializeBinaryNode.js +0 -31
  23. package/src/core/bvh2/serialization/serializeBinaryNodeToBinaryBuffer.js +0 -86
  24. package/src/core/bvh2/transform/BottomUpOptimizingRebuilder.js +0 -144
  25. package/src/core/bvh2/transform/RotationOptimizer.js +0 -123
  26. package/src/core/bvh2/transform/RotationOptimizer.spec.js +0 -303
  27. package/src/core/bvh2/transform/tryRotateSingleNode.js +0 -260
  28. package/src/core/bvh2/traversal/BVHVisitor.js +0 -30
  29. package/src/core/bvh2/traversal/RaycastBVHVisitor.js +0 -66
  30. package/src/core/bvh2/traversal/ThreeClippingPlaneComputingBVHVisitor.js +0 -384
  31. package/src/core/bvh2/traversal/ThreeFrustumsIntersectionBVHVisitor.js +0 -52
  32. package/src/core/bvh2/traversal/bvh_traverse_pre_order_using_stack.js +0 -43
  33. package/src/core/bvh2/traversal/queryBinaryNode_ClippingPlanes.d.ts +0 -5
  34. package/src/core/bvh2/traversal/queryBinaryNode_ClippingPlanes.js +0 -66
  35. package/src/core/bvh2/traversal/queryBinaryNode_CollectData.js +0 -49
  36. package/src/core/bvh2/traversal/queryBinaryNode_CollectLeaves.js +0 -51
  37. package/src/core/bvh2/traversal/queryBinaryNode_FrustumIntersections.js +0 -77
  38. package/src/core/bvh2/traversal/queryBinaryNode_SphereIntersections.js +0 -63
  39. package/src/core/bvh2/traversal/traverseBinaryNodeUsingVisitor.js +0 -50
  40. package/src/core/bvh2/traversal/traverseBinaryNodeUsingVisitor_DepthFirst_PreOrder.js +0 -34
  41. package/src/core/bvh2/util/find_least_common_ancestor.js +0 -34
  42. package/src/core/bvh2/visual/convert_bvh_to_dot_format_string.js +0 -50
  43. package/src/core/geom/2d/bvh/BinaryNode2.js +0 -152
  44. package/src/core/geom/2d/bvh/LeafNode2.js +0 -11
  45. package/src/core/geom/2d/bvh/Node2.js +0 -51
  46. package/src/engine/ecs/terrain/tiles/FirstRayIntersectionTerrainBVHVisitor.js +0 -74
  47. package/src/engine/graphics/geometry/bvh/BVHFromGeometry.js +0 -72
  48. package/src/engine/graphics/geometry/bvh/buffered/BVHGeometryRaycaster.js +0 -240
  49. package/src/engine/graphics/geometry/bvh/buffered/IndexedTraingleBoundsComputer.js +0 -43
  50. package/src/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_objects.js +0 -133
@@ -1,1188 +0,0 @@
1
- /**
2
- * Created by Alex on 17/11/2014.
3
- */
4
-
5
-
6
- import { assert } from "../assert.js";
7
- import { arrayQuickSort } from "../collection/array/arrayQuickSort.js";
8
- import { aabb3_box_surface_area_2 } from "../geom/3d/aabb/aabb3_box_surface_area_2.js";
9
- import { aabb3_combined_surface_area } from "../geom/3d/aabb/aabb3_combined_surface_area.js";
10
- import { aabb3_intersects_aabb3 } from "../geom/3d/aabb/aabb3_intersects_aabb3.js";
11
- import { max2 } from "../math/max2.js";
12
- import { min2 } from "../math/min2.js";
13
- import { computeSampleStandardDeviation } from "../math/statistics/computeSampleStandardDeviation.js";
14
- import { isLeaf, LeafNode } from "./LeafNode.js";
15
- import { Node } from "./Node.js";
16
- import { surfaceAreaHeuristic } from "./sah/surfaceAreaHeuristic.js";
17
- import { BVHVisitor } from "./traversal/BVHVisitor.js";
18
- import { traverseBinaryNodeUsingVisitor } from "./traversal/traverseBinaryNodeUsingVisitor.js";
19
-
20
-
21
- /**
22
- * @callback BinaryNode~Visitor
23
- * @param {Node} node
24
- * @returns {boolean} flag, controls traversal of descendants. If false - no traversal is done over descendants
25
- */
26
-
27
-
28
- /**
29
- *
30
- * @type {number}
31
- */
32
- let stackPointer = 0;
33
- /**
34
- *
35
- * @type {Node[]}
36
- */
37
- const stack = [];
38
-
39
- /**
40
- * @deprecated use {@link BVH} instead
41
- */
42
- export class BinaryNode extends Node {
43
- constructor() {
44
- super();
45
-
46
- /**
47
- *
48
- * @type {null|BinaryNode|LeafNode}
49
- */
50
- this.parentNode = null;
51
-
52
- /**
53
- *
54
- * @type {null|Node|LeafNode|BinaryNode}
55
- */
56
- this.left = null;
57
-
58
- /**
59
- *
60
- * @type {null|Node|LeafNode|BinaryNode}
61
- */
62
- this.right = null;
63
-
64
- /**
65
- * Number of leaf nodes in the hierarchy
66
- * @deprecated
67
- * @type {number}
68
- * @private
69
- */
70
- this.leafNodeCount = 0;
71
-
72
- /**
73
- * Leaf node will have height 0, root node will have height equal to maximum depth of the tree
74
- * @type {number}
75
- */
76
- this.height = 0;
77
- }
78
-
79
- /**
80
- * Same as traversePreOrder but without recursion. This runs faster thanks to avoidance of function call overhead. Especially useful for deeper trees.
81
- * @param {BinaryNode~Visitor} visitor
82
- * @param [thisArg]
83
- * @deprecated use visitor-based traversal instead of callback-based
84
- */
85
- traversePreOrderUsingStack(visitor, thisArg) {
86
- let visitCount = 0;
87
-
88
- const stackOffset = stackPointer;
89
-
90
- stack[stackPointer++] = this;
91
- let n;
92
- while (stackPointer-- > stackOffset) {
93
-
94
- visitCount++;
95
-
96
- n = stack[stackPointer];
97
-
98
- const traverseDeeper = visitor.call(thisArg, n);
99
-
100
- if (traverseDeeper !== false && n.isBinaryNode) {
101
- if (n.right !== null) {
102
- stack[stackPointer++] = n.right;
103
- }
104
- if (n.left !== null) {
105
- stack[stackPointer++] = n.left;
106
- }
107
- }
108
- }
109
-
110
- // drop stack frame
111
- stackPointer = stackOffset;
112
-
113
- return visitCount;
114
- }
115
-
116
- /**
117
- * Traverse leaf nodes in a fast manner
118
- * @param {function(node:LeafNode)} visitor
119
- * @param {*} [thisArg]
120
- */
121
- traverseLeavesPreOrderUsingStack(visitor, thisArg) {
122
- let visitCount = 0;
123
-
124
- const stackOffset = stackPointer;
125
-
126
- stack[stackPointer++] = this;
127
-
128
- let n;
129
-
130
- while (stackPointer-- > stackOffset) {
131
-
132
- visitCount++;
133
-
134
- n = stack[stackPointer];
135
-
136
- if (n.isLeafNode) {
137
- visitor.call(thisArg, n);
138
- } else {
139
- //a binary node
140
- if (n.right !== null) {
141
- stack[stackPointer++] = n.right;
142
- }
143
- if (n.left !== null) {
144
- stack[stackPointer++] = n.left;
145
- }
146
- }
147
- }
148
-
149
- // drop stack frame
150
- stackPointer = stackOffset;
151
-
152
- return visitCount;
153
- }
154
-
155
-
156
- /**
157
- * Contains no children
158
- * @returns {boolean}
159
- */
160
- isEmpty() {
161
- return this.left === null && this.right === null;
162
- }
163
-
164
- reset() {
165
- this.left = null;
166
- this.right = null;
167
-
168
- this.leafNodeCount = 0;
169
- this.height = 0;
170
-
171
- this.setNegativelyInfiniteBounds();
172
- }
173
-
174
- /**
175
- *
176
- * @param {Node|BinaryNode} left
177
- * @param {Node|BinaryNode} right
178
- */
179
- setChildren(left, right) {
180
- this.left = left;
181
- this.right = right;
182
-
183
- left.parentNode = this;
184
- right.parentNode = this;
185
- }
186
-
187
- /**
188
- *
189
- * @param {Node} child
190
- */
191
- setChildLeft(child) {
192
- assert.isNull(this.left, 'left');
193
-
194
- this.left = child;
195
- child.parentNode = this;
196
- }
197
-
198
- /**
199
- *
200
- * @param {Node} child
201
- */
202
- setChildRight(child) {
203
- assert.isNull(this.right, 'right');
204
-
205
- this.right = child;
206
- child.parentNode = this;
207
- }
208
-
209
- /**
210
- * For incremental insertion, a sibling needs to be found, newly inserted node will be parented together with this sibling
211
- * @see https://github.com/erincatto/box2d/blob/9dc24a6fd4f32442c4bcf80791de47a0a7d25afb/src/collision/b2_dynamic_tree.cpp#L197
212
- * @private
213
- * @param {AABB3} box
214
- * @returns {BinaryNode|LeafNode}
215
- */
216
- __insertion_findSiblingFor(box) {
217
-
218
- let node = this;
219
- let cost_left = 0;
220
- let cost_right = 0;
221
-
222
- while (node.isBinaryNode === true) {
223
- const left = node.left;
224
- const right = node.right;
225
-
226
- const area = aabb3_box_surface_area_2(node);
227
-
228
- const combined_area = aabb3_combined_surface_area(node, box);
229
-
230
- //cost of creating a new parent for this node and the new leaf
231
- const cost = combined_area;
232
-
233
- // minimum cost of pushing the leaf further down the tree
234
- const inheritance_cost = combined_area - area;
235
-
236
- // cost of descending left
237
- if (left !== null) {
238
- const combined_left = aabb3_combined_surface_area(left, box);
239
- if (left.isLeafNode) {
240
- cost_left = combined_left + inheritance_cost;
241
- } else {
242
- cost_left = combined_left - aabb3_box_surface_area_2(left) + inheritance_cost;
243
- }
244
- } else {
245
- cost_left = Infinity;
246
- }
247
-
248
- // cost of descending right
249
- if (right !== null) {
250
-
251
- const combined_right = aabb3_combined_surface_area(right, box);
252
- if (right.isLeafNode) {
253
- cost_right = combined_right + inheritance_cost;
254
- } else {
255
- cost_right = combined_right - aabb3_box_surface_area_2(right) + inheritance_cost;
256
- }
257
- } else {
258
- cost_right = Infinity;
259
- }
260
-
261
- if (cost < cost_left && cost < cost_right) {
262
- // descending either branch is too expensive
263
- break;
264
- }
265
-
266
- if (cost_left < cost_right && left !== null) {
267
- node = left;
268
- } else if (right !== null) {
269
- node = right;
270
- } else {
271
- break;
272
- }
273
- }
274
-
275
- return node;
276
- }
277
-
278
- /**
279
- *
280
- * @param {AABB3} box
281
- * @returns {Node|BinaryNode|LeafNode}
282
- */
283
- findParentFor(box) {
284
- let n = this;
285
- let aCost = 0;
286
- let bCost = 0;
287
-
288
- for (; ;) {
289
-
290
- const a = n.left;
291
- const b = n.right;
292
-
293
- if (a === null || b === null) {
294
- //unbalanced node, good candidate already
295
- return n;
296
- }
297
-
298
- const aIsBinary = a.isBinaryNode;
299
- const bIsBinary = b.isBinaryNode;
300
-
301
- aCost = a.costForInclusion(box);
302
- bCost = b.costForInclusion(box);
303
-
304
- if (aCost === bCost) {
305
-
306
- if (a.isLeafNode) {
307
-
308
- return a;
309
-
310
- } else if (b.isLeafNode) {
311
-
312
- return b;
313
-
314
- }
315
-
316
- //change costs to be based on balance
317
- aCost = a.leafNodeCount / aabb3_box_surface_area_2(a);
318
- bCost = b.leafNodeCount / aabb3_box_surface_area_2(b);
319
- }
320
-
321
- if (aCost === bCost) {
322
- //still the same, toss a coin
323
- aCost = Math.random();
324
- bCost = 1 - aCost;
325
- }
326
-
327
- if (aCost < bCost) {
328
- if (aIsBinary) {
329
- n = a;
330
- } else {
331
- return a;
332
- }
333
- } else {
334
- if (bIsBinary) {
335
- n = b;
336
- } else {
337
- return b;
338
- }
339
- }
340
- }
341
- }
342
-
343
- traverse(visitor) {
344
- if (this.left !== null) {
345
- const cA = visitor(this.left);
346
- if (cA !== false) {
347
- this.left.traverse(visitor);
348
- }
349
- }
350
- if (this.right !== null) {
351
- const cB = visitor(this.right);
352
- if (cB !== false) {
353
- this.right.traverse(visitor);
354
- }
355
- }
356
- }
357
-
358
- /**
359
- * Bottom-up tree traversal, children first
360
- * @param visitor
361
- */
362
- traversePostOrder(visitor) {
363
- //left
364
- if (this.left instanceof BinaryNode) {
365
- this.left.traversePostOrder(visitor);
366
- } else if (this.left instanceof LeafNode) {
367
- visitor(this.left);
368
- }
369
- //right
370
- if (this.right instanceof BinaryNode) {
371
- this.right.traversePostOrder(visitor);
372
- } else if (this.right instanceof LeafNode) {
373
- visitor(this.right);
374
- }
375
- visitor(this);
376
- }
377
-
378
- traversePreOrder(visitor) {
379
- const carryOn = visitor(this);
380
- if (carryOn !== false) {
381
- //left
382
- if (this.left instanceof BinaryNode) {
383
- this.left.traversePreOrder(visitor);
384
- } else if (this.left instanceof LeafNode) {
385
- visitor(this.left);
386
- }
387
- //right
388
- if (this.right instanceof BinaryNode) {
389
- this.right.traversePreOrder(visitor);
390
- } else if (this.right instanceof LeafNode) {
391
- visitor(this.right);
392
- }
393
- }
394
- }
395
-
396
- refitFor2() {
397
- const a = this.left;
398
- const b = this.right;
399
-
400
- const x0 = min2(a.x0, b.x0);
401
- const y0 = min2(a.y0, b.y0);
402
- const z0 = min2(a.z0, b.z0);
403
-
404
- const x1 = max2(a.x1, b.x1);
405
- const y1 = max2(a.y1, b.y1);
406
- const z1 = max2(a.z1, b.z1);
407
-
408
- this.setBounds(x0, y0, z0, x1, y1, z1);
409
- }
410
-
411
- bubbleRefit() {
412
- let n = this;
413
-
414
- n.refit();
415
-
416
- //bubble up
417
- for (; ;) {
418
- //record old node size
419
- const _x0 = n.x0;
420
- const _y0 = n.y0;
421
- const _z0 = n.z0;
422
- const _x1 = n.x1;
423
- const _y1 = n.y1;
424
- const _z1 = n.z1;
425
-
426
- n = n.parentNode;
427
-
428
- if (n === null) {
429
- // hit the root
430
- return;
431
- }
432
-
433
-
434
- //check if this node violates bounds of the parent
435
- let flag = false;
436
-
437
- if (_x0 < n.x0) {
438
- n.x0 = _x0;
439
- flag = true;
440
- }
441
- if (_y0 < n.y0) {
442
- n.y0 = _y0;
443
- flag = true;
444
- }
445
- if (_z0 < n.z0) {
446
- n.z0 = _z0;
447
- flag = true;
448
- }
449
-
450
- if (_x1 > n.x1) {
451
- n.x1 = _x1;
452
- flag = true;
453
- }
454
- if (_y1 > n.y1) {
455
- n.y1 = _y1;
456
- flag = true;
457
- }
458
- if (_z1 > n.z1) {
459
- n.z1 = _z1;
460
- flag = true;
461
- }
462
-
463
- if (!flag) {
464
- //no violation, we can stop here
465
- break;
466
- }
467
- }
468
- }
469
-
470
- refit() {
471
- if (this.left !== null && this.right !== null) {
472
- this.refitFor2();
473
- } else if (this.left !== null) {
474
- this.copy(this.left);
475
- } else if (this.right !== null) {
476
- this.copy(this.right);
477
- }
478
- }
479
-
480
- sumSurfaceArea() {
481
- let result = 0;
482
- this.traversePreOrderUsingStack(function (node) {
483
- const nodeArea = node.computeSurfaceArea();
484
- result += nodeArea;
485
- });
486
-
487
- return result;
488
- }
489
-
490
- countDescendants() {
491
- let result = 0;
492
- this.traversePreOrderUsingStack(function (node) {
493
- result++;
494
- });
495
- return result;
496
- }
497
-
498
- /**
499
- * @deprecated Incorrect usage of SAH
500
- * @return {number}
501
- */
502
- computeSAH() {
503
- let leftLeaves, rightLeaves, leftArea, rightArea;
504
-
505
- const left = this.left;
506
-
507
- if (left === null) {
508
- leftArea = 0;
509
- leftLeaves = 0;
510
- } else {
511
- leftArea = aabb3_box_surface_area_2(left);
512
- leftLeaves = left.leafNodeCount;
513
- }
514
-
515
- const right = this.right;
516
- if (right === null) {
517
- rightArea = 0;
518
- rightLeaves = 0;
519
- } else {
520
- rightArea = aabb3_box_surface_area_2(right);
521
- rightLeaves = right.leafNodeCount;
522
- }
523
-
524
- const thisArea = aabb3_box_surface_area_2(this);
525
-
526
- return surfaceAreaHeuristic(thisArea, leftArea, rightArea, leftLeaves, rightLeaves);
527
- }
528
-
529
- updateHeight() {
530
- let node = this;
531
- let n = 0;
532
-
533
- while (node !== null) {
534
- n = 0;
535
-
536
- const right = node.right;
537
-
538
- if (right !== null) {
539
- n = right.height;
540
- }
541
-
542
- const left = this.left;
543
-
544
- if (left !== null) {
545
- n = max2(n, left.height);
546
- }
547
-
548
- node.height = n + 1;
549
-
550
- // propagate update up the tree
551
- node = node.parentNode;
552
- }
553
- }
554
-
555
- /**
556
- * @deprecated
557
- */
558
- updateLeafNodeCount() {
559
- let node = this;
560
-
561
- while (node !== null) {
562
- let n = 0;
563
-
564
- const right = node.right;
565
-
566
- if (right !== null) {
567
- if (right.isLeafNode) {
568
- n++;
569
- } else {
570
- n += right.leafNodeCount;
571
- }
572
- }
573
-
574
- const left = this.left;
575
-
576
- if (left !== null) {
577
- if (left.isLeafNode) {
578
- n++;
579
- } else {
580
- n += left.leafNodeCount;
581
- }
582
- }
583
-
584
- node.leafNodeCount = n;
585
-
586
- // propagate update up the tree
587
- node = node.parentNode;
588
- }
589
-
590
- }
591
-
592
- /**
593
- * As a result of rotation, this node 'becomes' the right node, and left node get's replaced by the right node with necessary adjustments
594
- */
595
- rotateLeft() {
596
-
597
- /**
598
- *
599
- * @type {BinaryNode}
600
- */
601
- const r = this.right;
602
-
603
- const l = this.left;
604
-
605
- const rL = r.left;
606
- const rR = r.right;
607
-
608
- this.left = r;
609
- this.right = rR;
610
-
611
- if (rR !== null) {
612
- rR.parentNode = this;
613
- }
614
-
615
- r.left = l;
616
- if (l !== null) {
617
- l.parentNode = r;
618
- }
619
-
620
- r.right = rL;
621
-
622
- r.updateLeafNodeCount();
623
- r.updateHeight();
624
-
625
- r.bubbleRefit();
626
- }
627
-
628
- rotateRight() {
629
- const r = this.right;
630
-
631
- const left = this.left;
632
-
633
- const lL = left.left;
634
- const lR = left.right;
635
-
636
- if (lL !== null) {
637
- lL.parentNode = this;
638
- }
639
-
640
- left.right = r;
641
- if (r !== null) {
642
- r.parentNode = left;
643
- }
644
-
645
- left.left = lR;
646
-
647
- left.updateLeafNodeCount();
648
- left.updateHeight();
649
-
650
- left.bubbleRefit();
651
- }
652
-
653
- /**
654
- *
655
- * @param {function(index:int):LeafNode} leafFactory
656
- * @param {int} numNodes
657
- */
658
- insertManyBoxes2(leafFactory, numNodes) {
659
- let i, n;
660
- //create leaf nodes
661
- const nodes = new Array(numNodes);
662
-
663
- for (i = 0; i < numNodes; i++) {
664
- //leaf needs to be set up inside the callback
665
- n = leafFactory(i);
666
-
667
- nodes[i] = n;
668
- }
669
-
670
- //sort leaves
671
- arrayQuickSort(nodes, n => n.computeMortonCode(), null, 0, max2(0, numNodes - 1));
672
-
673
- let remaining_nodes = numNodes;
674
-
675
- while (remaining_nodes > 2) {
676
-
677
- //pair
678
- for (i = 0; i < remaining_nodes - 1; i += 2) {
679
- const a = nodes[i];
680
- const b = nodes[i + 1];
681
-
682
- n = new BinaryNode();
683
-
684
- n.setChildren(a, b);
685
-
686
- n.updateHeight();
687
- n.refitFor2();
688
-
689
- nodes[i >> 1] = n;
690
- }
691
-
692
- const numNodesMod2 = remaining_nodes & 1; //faster version of %2
693
-
694
- if (numNodesMod2 !== 0) {
695
- //shift remaining node up so it will be considered later
696
- nodes[i >> 1] = nodes[i];
697
- }
698
-
699
- remaining_nodes = (remaining_nodes >> 1) + numNodesMod2;
700
- }
701
-
702
- //finally insert these boxes from this node
703
- for (i = 0; i < remaining_nodes; i++) {
704
- n = nodes[i];
705
- this.insertNode(n);
706
- }
707
- }
708
-
709
- /**
710
- *
711
- * @param {LeafNode[]} result destination
712
- * @param {number} x0
713
- * @param {number} y0
714
- * @param {number} z0
715
- * @param {number} x1
716
- * @param {number} y1
717
- * @param {number} z1
718
- * @returns {number} number of objects added to the result
719
- */
720
- requestLeafIntersectionsAABB3(result, x0, y0, z0, x1, y1, z1) {
721
- const startOffset = stackPointer;
722
-
723
- stack[stackPointer++] = this;
724
-
725
- let count = 0;
726
-
727
- while (stackPointer > startOffset) {
728
- stackPointer--;
729
- const node = stack[stackPointer];
730
-
731
- if (!aabb3_intersects_aabb3(
732
- x0, y0, z0, x1, y1, z1,
733
- node.x0, node.y0, node.z0, node.x1, node.y1, node.z1
734
- )) {
735
- //no overlap
736
- continue;
737
- }
738
-
739
- if (node.isLeafNode) {
740
- result[count++] = node;
741
-
742
- count++;
743
- } else {
744
- const left = node.left;
745
- if (left !== null) {
746
- stack[stackPointer++] = left;
747
- }
748
-
749
- const right = node.right;
750
- if (right !== null) {
751
- stack[stackPointer++] = right;
752
- }
753
- }
754
- }
755
-
756
- return count;
757
- }
758
-
759
- traverseSegmentLeafIntersections(startX, startY, startZ, endX, endY, endZ, visitor) {
760
- this.traversePreOrder(function (node) {
761
- let b = node.intersectSegment(startX, startY, startZ, endX, endY, endZ);
762
- if (!b) {
763
- return false;
764
- }
765
- if (node instanceof LeafNode) {
766
- visitor(node);
767
- return false;
768
- } else {
769
- return true;
770
- }
771
- });
772
- }
773
-
774
- /**
775
- *
776
- * @param {Frustum[]} frustums Collection of THREE.js Frustums
777
- * @param {function(node:LeafNode, boolean)} visitor
778
- * @returns {number}
779
- * @deprecated Use {@link ThreeFrustumsIntersectionBVHVisitor}
780
- */
781
- threeTraverseFrustumsIntersections(frustums, visitor) {
782
- const numFrustums = frustums.length;
783
-
784
- /**
785
- *
786
- * @param {LeafNode|BinaryNode} node
787
- * @returns {boolean}
788
- */
789
- function visitNode(node) {
790
- let b = false;
791
- let i = 0;
792
-
793
- for (; i < numFrustums; i++) {
794
-
795
- const degree = node.intersectFrustumDegree(frustums[i]);
796
-
797
- if (degree === 2) {
798
- //completely inside frustum
799
-
800
- if (node.isLeafNode) {
801
- visitor(node, true);
802
- } else {
803
- node.traverseLeavesPreOrderUsingStack(fastVisitLeafNodeIntersection, visitor);
804
- }
805
-
806
- //prevent further traversal
807
- return false;
808
-
809
- } else if (degree === 1) {
810
-
811
- //partially inside frustum
812
- b = true;
813
-
814
- }
815
- }
816
-
817
- if (!b) {
818
- return false;
819
- }
820
-
821
- if (node.isLeafNode) {
822
- visitor(node, false);
823
- }
824
-
825
- return true;
826
- }
827
-
828
- return this.traversePreOrderUsingStack(visitNode);
829
- }
830
-
831
- /**
832
- * As recursion goes on, we remove frustums and planes from checks reducing total number of checks necessary
833
- * @param {Array.<THREE.Frustum>} frustums
834
- * @param {function} visitor
835
- * @returns {number}
836
- */
837
- threeTraverseFrustumsIntersections2(frustums, visitor) {
838
- const numFrustums = frustums.length;
839
-
840
- function visitLeaves(node) {
841
- if (node instanceof LeafNode) {
842
- visitor(node);
843
- return false;
844
- } else {
845
- return true;
846
- }
847
- }
848
-
849
- function fastTraverseLeaves(node) {
850
- if (node instanceof LeafNode) {
851
- visitor(node);
852
- } else {
853
- node.traversePreOrderUsingStack(visitLeaves);
854
- }
855
- }
856
-
857
-
858
- function isFlagSet(mask, index) {
859
- return mask & (1 << index) !== 0;
860
- }
861
-
862
- function clearFlag(mask, index) {
863
- return mask & ~(1 << index);
864
- }
865
-
866
- function removeElementFromClone(original, clone, mask, originalIndex) {
867
- if (clone === original) {
868
- //clone planes
869
- clone = clone.slice();
870
- }
871
- //remove the plane from new set
872
- clone.splice(originalIndex, 1);
873
- return clone;
874
- }
875
-
876
- function processVolumesIntersections(node, planeSets, planeSetCount) {
877
- let newPlaneSets = planeSets;
878
- for (let iPS = planeSetCount - 1; iPS >= 0; iPS--) {
879
-
880
- const planes = planeSets[iPS];
881
- let newPlanes = planes;
882
- const numPlanes = planes.length;
883
-
884
- //check plane set
885
- for (let i = numPlanes - 1; i >= 0; i--) {
886
- const plane = planes[i];
887
- const planeSide = node.computePlaneSide(plane);
888
- if (planeSide < 0) {
889
- //completely inside
890
- newPlanes = removeElementFromClone(planes, newPlanes, i);
891
- } else if (planeSide > 0) {
892
- //on the wrong side of the plane
893
- //drop plane set
894
- newPlaneSets = removeElementFromClone(planeSets, newPlaneSets, iPS);
895
-
896
- break;
897
- }
898
- }
899
-
900
- //update plane sets as needed
901
- if (newPlanes !== planes && newPlaneSets.indexOf(planes) !== -1) {
902
- //replace
903
- if (newPlaneSets === planeSets) {
904
- //clone if needed
905
- newPlaneSets = newPlaneSets.slice();
906
- }
907
- newPlaneSets[iPS] = newPlanes;
908
- }
909
- }
910
-
911
- return newPlaneSets;
912
- }
913
-
914
- function traverseVolumeIntersections(node, planeSets, numPlaneSets) {
915
- function internalVisitor(node) {
916
- let newPlaneSet = processVolumesIntersections(node, planeSets, numPlaneSets);
917
- if (newPlaneSet !== planeSets) {
918
- let newPlaneSetCount = newPlaneSet.length;
919
- if (newPlaneSetCount !== 0) {
920
- //some intersections
921
-
922
- //check if all plane sets are trivial (contain no test planes)
923
- let trivialPlaneSets = 0;
924
- for (let i = 0; i < newPlaneSetCount; i++) {
925
- if (newPlaneSet[i].length === 0) {
926
- trivialPlaneSets++;
927
- }
928
- }
929
-
930
- if (isLeaf(node)) {
931
- visitor(node);
932
- } else {
933
- if (trivialPlaneSets === newPlaneSetCount) {
934
- fastTraverseLeaves(node);
935
- } else {
936
- traverseVolumeIntersections(node, newPlaneSet, newPlaneSetCount);
937
- }
938
- }
939
- }
940
- } else {
941
- if (isLeaf(node)) {
942
- visitor(node);
943
- } else {
944
- return true;
945
- }
946
- }
947
-
948
- return false;
949
- }
950
-
951
- node.traversePreOrderUsingStack(internalVisitor);
952
- }
953
-
954
- function startTraversal(node) {
955
- let planeSets = [];
956
- for (let i = 0; i < numFrustums; i++) {
957
- const frustum = frustums[i];
958
- const planes = frustum.planes;
959
- planeSets.push(planes);
960
- }
961
- traverseVolumeIntersections(node, planeSets, numFrustums);
962
- }
963
-
964
- startTraversal(this);
965
- }
966
-
967
- /**
968
- *
969
- * @param {number} startX
970
- * @param {number} startY
971
- * @param {number} startZ
972
- * @param {number} directionX
973
- * @param {number} directionY
974
- * @param {number} directionZ
975
- * @param {function(node:LeafNode)} visitor
976
- * @param thisArg
977
- * @deprecated use {@link RaycastBVHVisitor} instead
978
- */
979
- traverseRayLeafIntersections(startX, startY, startZ, directionX, directionY, directionZ, visitor, thisArg) {
980
- this.traversePreOrderUsingStack(function (node) {
981
- let b = node.intersectRay(startX, startY, startZ, directionX, directionY, directionZ);
982
-
983
- if (!b) {
984
- //no intersection, terminate this branch
985
- return false;
986
- }
987
-
988
- if (isLeaf(node)) {
989
- //leaf node, supply to visitor
990
- visitor.call(thisArg, node);
991
- return false;
992
- } else {
993
- //intermediate node, continue traversal
994
- return true;
995
- }
996
- });
997
- }
998
-
999
- /**
1000
- * Fraction of balanced nodes in the tree (those that have both children)
1001
- * @returns {number}
1002
- */
1003
- computeBalanceFactor() {
1004
-
1005
- const bvhVisitor = new BVHVisitor();
1006
-
1007
-
1008
- const depths = [];
1009
-
1010
- bvhVisitor.visitLeaf = (leaf) => {
1011
- const depth = leaf.computeDepth();
1012
-
1013
- depths.push(depth);
1014
- };
1015
-
1016
- traverseBinaryNodeUsingVisitor(this, bvhVisitor)
1017
-
1018
- if (depths.length === 0) {
1019
- return 1;
1020
- } else {
1021
- return computeSampleStandardDeviation(depths);
1022
- }
1023
-
1024
- }
1025
-
1026
- /**
1027
- * @template T
1028
- * @param {number} x0
1029
- * @param {number} y0
1030
- * @param {number} z0
1031
- * @param {number} x1
1032
- * @param {number} y1
1033
- * @param {number} z1
1034
- * @param {T} value
1035
- * @returns {LeafNode}
1036
- */
1037
- insert(x0, y0, z0, x1, y1, z1, value) {
1038
- const leaf = new LeafNode(value, x0, y0, z0, x1, y1, z1);
1039
- this.insertNode(leaf);
1040
- return leaf;
1041
- }
1042
-
1043
- /**
1044
- *
1045
- * @param {Node|BinaryNode|LeafNode} child
1046
- */
1047
- insertNode(child) {
1048
-
1049
- assert.notNull(child, "child");
1050
- assert.defined(child, "child");
1051
- assert.isInstanceOf(child, Node, 'child', "Node");
1052
- assert.equal(child.parentNode, null, "parentNode must be null, otherwise Node still belongs to another tree");
1053
-
1054
- const sibling = this.__insertion_findSiblingFor(child);
1055
-
1056
- let parent = sibling.parentNode;
1057
-
1058
- if (parent === null) {
1059
- // "sibling" is the root node
1060
-
1061
- parent = sibling;
1062
-
1063
- if (sibling.left === null) {
1064
- sibling.setChildLeft(child);
1065
- } else if (sibling.right === null) {
1066
- sibling.setChildRight(child);
1067
- } else {
1068
- parent = new BinaryNode();
1069
-
1070
- parent.setChildren(sibling.right, child);
1071
- sibling.right = parent;
1072
- parent.parentNode = sibling;
1073
- }
1074
-
1075
- } else {
1076
-
1077
- // non-root
1078
-
1079
- if (parent.left === sibling && parent.right === null) {
1080
-
1081
- // right node is free, take it
1082
- parent.setChildRight(child);
1083
-
1084
- } else if (parent.right === sibling && parent.left === null) {
1085
-
1086
- // left node is free, take it
1087
- parent.setChildLeft(child);
1088
-
1089
- } else {
1090
-
1091
- parent = transplantNewCommonParent(sibling, child)
1092
-
1093
- }
1094
-
1095
- }
1096
-
1097
- // walk back up the tree fixing heights and bounds
1098
- do {
1099
- // parent = this.balance();
1100
-
1101
- const left = parent.left;
1102
- const right = parent.right;
1103
-
1104
- parent.height = 1 + max2(left !== null ? left.height : 0, right !== null ? right.height : 0);
1105
- parent.refit();
1106
-
1107
- parent = parent.parentNode;
1108
- } while (parent !== null);
1109
- }
1110
-
1111
- /**
1112
- * @param {boolean} deep
1113
- * @returns {BinaryNode}
1114
- */
1115
- clone(deep = false) {
1116
- const clone = new BinaryNode();
1117
-
1118
- clone.x0 = this.x0;
1119
- clone.y0 = this.y0;
1120
- clone.z0 = this.z0;
1121
- clone.x1 = this.x1;
1122
- clone.y1 = this.y1;
1123
- clone.z1 = this.z1;
1124
-
1125
- clone.leafNodeCount = this.leafNodeCount;
1126
-
1127
- clone.parentNode = this.parentNode;
1128
-
1129
- if (deep === true) {
1130
- if (this.left !== null) {
1131
- clone.left = this.left.clone(true);
1132
- clone.left.parentNode = clone;
1133
- }
1134
- if (this.right !== null) {
1135
- clone.right = this.right.clone(true);
1136
- clone.right.parentNode = clone;
1137
- }
1138
- } else {
1139
- clone.left = this.left;
1140
- clone.right = this.right;
1141
- }
1142
-
1143
- clone.modifiers = this.modifiers;
1144
-
1145
- return clone;
1146
- }
1147
- }
1148
-
1149
- /**
1150
- * @readonly
1151
- * @type {boolean}
1152
- */
1153
- BinaryNode.prototype.isBinaryNode = true;
1154
-
1155
- /**
1156
- * @private
1157
- * Used in intersection traversal methods. Should be invoked via Function.apply and Function.call only and not be called directly
1158
- * @param {LeafNode} node
1159
- */
1160
- function fastVisitLeafNodeIntersection(node) {
1161
- this(node, true);
1162
- }
1163
-
1164
- /**
1165
- *
1166
- * @param {Node} node
1167
- * @param {Node} child
1168
- * @return {BinaryNode}
1169
- */
1170
- function transplantNewCommonParent(node, child) {
1171
- const bNode = new BinaryNode();
1172
-
1173
- //
1174
- const parent = node.parentNode;
1175
- if (node === parent.left) {
1176
- parent.left = bNode;
1177
- } else if (node === parent.right) {
1178
- parent.right = bNode;
1179
- } else {
1180
- throw new Error("Not a child of specified parent node(impostor)");
1181
- }
1182
-
1183
- bNode.setChildren(node, child);
1184
- bNode.parentNode = parent;
1185
-
1186
- return bNode;
1187
- }
1188
-