@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.
- package/build/meep.cjs +0 -1
- package/build/meep.module.js +0 -1
- package/package.json +1 -1
- package/src/engine/graphics/ecs/mesh/Mesh.d.ts +0 -1
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.d.ts +0 -5
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +0 -1
- package/src/engine/graphics/material/optimization/prototypeMaterialOptimizer.js +16 -19
- package/src/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +46 -47
- package/src/core/bvh2/BVHTasks.js +0 -65
- package/src/core/bvh2/BinaryNode.d.ts +0 -13
- package/src/core/bvh2/BinaryNode.js +0 -1188
- package/src/core/bvh2/BinaryNode.spec.js +0 -309
- package/src/core/bvh2/LeafNode.d.ts +0 -7
- package/src/core/bvh2/LeafNode.js +0 -147
- package/src/core/bvh2/Node.d.ts +0 -9
- package/src/core/bvh2/Node.js +0 -196
- package/src/core/bvh2/NodeValidator.js +0 -197
- package/src/core/bvh2/StacklessTraverser.js +0 -154
- package/src/core/bvh2/StacklessTraverser.spec.js +0 -109
- package/src/core/bvh2/serialization/deserializeBinaryNode.js +0 -40
- package/src/core/bvh2/serialization/deserializeBinaryNodeFromBinaryBuffer.js +0 -90
- package/src/core/bvh2/serialization/serializeBinaryNode.js +0 -31
- package/src/core/bvh2/serialization/serializeBinaryNodeToBinaryBuffer.js +0 -86
- package/src/core/bvh2/transform/BottomUpOptimizingRebuilder.js +0 -144
- package/src/core/bvh2/transform/RotationOptimizer.js +0 -123
- package/src/core/bvh2/transform/RotationOptimizer.spec.js +0 -303
- package/src/core/bvh2/transform/tryRotateSingleNode.js +0 -260
- package/src/core/bvh2/traversal/BVHVisitor.js +0 -30
- package/src/core/bvh2/traversal/RaycastBVHVisitor.js +0 -66
- package/src/core/bvh2/traversal/ThreeClippingPlaneComputingBVHVisitor.js +0 -384
- package/src/core/bvh2/traversal/ThreeFrustumsIntersectionBVHVisitor.js +0 -52
- package/src/core/bvh2/traversal/bvh_traverse_pre_order_using_stack.js +0 -43
- package/src/core/bvh2/traversal/queryBinaryNode_ClippingPlanes.d.ts +0 -5
- package/src/core/bvh2/traversal/queryBinaryNode_ClippingPlanes.js +0 -66
- package/src/core/bvh2/traversal/queryBinaryNode_CollectData.js +0 -49
- package/src/core/bvh2/traversal/queryBinaryNode_CollectLeaves.js +0 -51
- package/src/core/bvh2/traversal/queryBinaryNode_FrustumIntersections.js +0 -77
- package/src/core/bvh2/traversal/queryBinaryNode_SphereIntersections.js +0 -63
- package/src/core/bvh2/traversal/traverseBinaryNodeUsingVisitor.js +0 -50
- package/src/core/bvh2/traversal/traverseBinaryNodeUsingVisitor_DepthFirst_PreOrder.js +0 -34
- package/src/core/bvh2/util/find_least_common_ancestor.js +0 -34
- package/src/core/bvh2/visual/convert_bvh_to_dot_format_string.js +0 -50
- package/src/core/geom/2d/bvh/BinaryNode2.js +0 -152
- package/src/core/geom/2d/bvh/LeafNode2.js +0 -11
- package/src/core/geom/2d/bvh/Node2.js +0 -51
- package/src/engine/ecs/terrain/tiles/FirstRayIntersectionTerrainBVHVisitor.js +0 -74
- package/src/engine/graphics/geometry/bvh/BVHFromGeometry.js +0 -72
- package/src/engine/graphics/geometry/bvh/buffered/BVHGeometryRaycaster.js +0 -240
- package/src/engine/graphics/geometry/bvh/buffered/IndexedTraingleBoundsComputer.js +0 -43
- 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
|
-
|