@woosh/meep-engine 2.67.0 → 2.69.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 (87) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/build/meep.cjs +698 -1270
  3. package/build/meep.min.js +1 -1
  4. package/build/meep.module.js +698 -1270
  5. package/package.json +1 -1
  6. package/src/core/bvh2/binary/2/BinaryUint32BVH.js +55 -28
  7. package/src/core/bvh2/binary/2/BinaryUint32BVH.spec.js +3 -3
  8. package/src/core/bvh2/binary/2/bvh32_query_user_data_overlaps_clipping_volume.js +94 -0
  9. package/src/core/bvh2/binary/2/bvh32_query_user_data_ray.js +17 -18
  10. package/src/core/bvh2/bvh3/query/BVHQueryIntersectsFrustum.js +4 -2
  11. package/src/core/geom/3d/aabb/AABB3.js +14 -14
  12. package/src/core/geom/3d/aabb/aabb3_array_intersects_clipping_volume_array.js +30 -0
  13. package/src/core/geom/3d/aabb/aabb3_intersects_clipping_volume_array.js +51 -0
  14. package/src/core/geom/3d/frustum/{read_frustum_planes_to_array.js → read_three_planes_to_array.js} +5 -3
  15. package/src/core/geom/3d/triangle/triangle_intersects_clipping_volume.js +51 -0
  16. package/src/engine/ecs/terrain/ecs/TerrainSystem.js +2 -2
  17. package/src/engine/ecs/terrain/ecs/makeTerrainWorkerProxy.js +1 -1
  18. package/src/engine/ecs/terrain/tiles/TerrainTile.js +9 -46
  19. package/src/engine/graphics/ecs/mesh/Mesh.d.ts +0 -1
  20. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.d.ts +0 -5
  21. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +0 -1
  22. package/src/engine/graphics/geometry/buffered/query/GeometrySpatialQueryAccelerator.d.ts +2 -2
  23. package/src/engine/graphics/geometry/buffered/query/GeometrySpatialQueryAccelerator.js +79 -36
  24. package/src/engine/graphics/geometry/buffered/query/bvh32_geometry_overlap_clipping_volume.js +88 -0
  25. package/src/engine/graphics/geometry/buffered/query/bvh32_geometry_raycast.js +108 -0
  26. package/src/engine/graphics/geometry/bvh/buffered/bvh32_from_indexed_geometry.js +4 -30
  27. package/src/engine/graphics/geometry/bvh/buffered/bvh32_from_unindexed_geometry.js +30 -0
  28. package/src/engine/graphics/geometry/bvh/buffered/bvh32_set_leaf_from_triangle.js +41 -0
  29. package/src/engine/graphics/material/optimization/prototypeMaterialOptimizer.js +16 -19
  30. package/src/engine/graphics/render/forward_plus/LightManager.js +2 -2
  31. package/src/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +46 -47
  32. package/src/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +2 -2
  33. package/src/engine/graphics/render/view/CameraView.js +8 -8
  34. package/src/core/bvh2/BVHTasks.js +0 -65
  35. package/src/core/bvh2/BinaryNode.d.ts +0 -13
  36. package/src/core/bvh2/BinaryNode.js +0 -1188
  37. package/src/core/bvh2/BinaryNode.spec.js +0 -309
  38. package/src/core/bvh2/LeafNode.d.ts +0 -7
  39. package/src/core/bvh2/LeafNode.js +0 -147
  40. package/src/core/bvh2/Node.d.ts +0 -9
  41. package/src/core/bvh2/Node.js +0 -196
  42. package/src/core/bvh2/NodeValidator.js +0 -197
  43. package/src/core/bvh2/StacklessTraverser.js +0 -154
  44. package/src/core/bvh2/StacklessTraverser.spec.js +0 -109
  45. package/src/core/bvh2/binary/BinaryBVH.js +0 -281
  46. package/src/core/bvh2/binary/IndexedBinaryBVH.js +0 -407
  47. package/src/core/bvh2/binary/IndexedBinaryBVH.spec.js +0 -27
  48. package/src/core/bvh2/binary/IndexedBinaryBVHVisitor.js +0 -11
  49. package/src/core/bvh2/binary/NodeType.js +0 -8
  50. package/src/core/bvh2/binary/RayLeafIntersectionVisitor.js +0 -59
  51. package/src/core/bvh2/serialization/deserializeBinaryNode.js +0 -40
  52. package/src/core/bvh2/serialization/deserializeBinaryNodeFromBinaryBuffer.js +0 -90
  53. package/src/core/bvh2/serialization/serializeBinaryNode.js +0 -31
  54. package/src/core/bvh2/serialization/serializeBinaryNodeToBinaryBuffer.js +0 -86
  55. package/src/core/bvh2/transform/BottomUpOptimizingRebuilder.js +0 -144
  56. package/src/core/bvh2/transform/RotationOptimizer.js +0 -123
  57. package/src/core/bvh2/transform/RotationOptimizer.spec.js +0 -303
  58. package/src/core/bvh2/transform/tryRotateSingleNode.js +0 -260
  59. package/src/core/bvh2/traversal/BVHVisitor.js +0 -30
  60. package/src/core/bvh2/traversal/RaycastBVHVisitor.js +0 -66
  61. package/src/core/bvh2/traversal/ThreeClippingPlaneComputingBVHVisitor.js +0 -384
  62. package/src/core/bvh2/traversal/ThreeFrustumsIntersectionBVHVisitor.js +0 -52
  63. package/src/core/bvh2/traversal/bvh_traverse_pre_order_using_stack.js +0 -43
  64. package/src/core/bvh2/traversal/queryBinaryNode_ClippingPlanes.d.ts +0 -5
  65. package/src/core/bvh2/traversal/queryBinaryNode_ClippingPlanes.js +0 -66
  66. package/src/core/bvh2/traversal/queryBinaryNode_CollectData.js +0 -49
  67. package/src/core/bvh2/traversal/queryBinaryNode_CollectLeaves.js +0 -51
  68. package/src/core/bvh2/traversal/queryBinaryNode_FrustumIntersections.js +0 -77
  69. package/src/core/bvh2/traversal/queryBinaryNode_SphereIntersections.js +0 -63
  70. package/src/core/bvh2/traversal/traverseBinaryNodeUsingVisitor.js +0 -50
  71. package/src/core/bvh2/traversal/traverseBinaryNodeUsingVisitor_DepthFirst_PreOrder.js +0 -34
  72. package/src/core/bvh2/util/find_least_common_ancestor.js +0 -34
  73. package/src/core/bvh2/visual/convert_bvh_to_dot_format_string.js +0 -50
  74. package/src/core/geom/2d/bvh/BinaryNode2.js +0 -152
  75. package/src/core/geom/2d/bvh/LeafNode2.js +0 -11
  76. package/src/core/geom/2d/bvh/Node2.js +0 -51
  77. package/src/core/geom/3d/aabb/aabb3_array_intersects_frustum_array.js +0 -20
  78. package/src/core/geom/3d/aabb/aabb3_intersects_frustum_array.js +0 -35
  79. package/src/engine/ecs/terrain/tiles/FirstRayIntersectionTerrainBVHVisitor.js +0 -74
  80. package/src/engine/graphics/geometry/buffered/query/ClippingPlaneContainmentComputingVisitor.js +0 -195
  81. package/src/engine/graphics/geometry/buffered/query/GeometryVisitor.js +0 -87
  82. package/src/engine/graphics/geometry/buffered/query/RaycastNearestHitComputingVisitor.js +0 -206
  83. package/src/engine/graphics/geometry/bvh/BVHFromGeometry.js +0 -72
  84. package/src/engine/graphics/geometry/bvh/buffered/BVHGeometryRaycaster.js +0 -240
  85. package/src/engine/graphics/geometry/bvh/buffered/BinaryBVHFromBufferGeometry.js +0 -123
  86. package/src/engine/graphics/geometry/bvh/buffered/IndexedTraingleBoundsComputer.js +0 -43
  87. package/src/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_objects.js +0 -133
@@ -1,11 +0,0 @@
1
- export class IndexedBinaryBVHVisitor {
2
- /**
3
- *
4
- * @param {number} address
5
- * @param {NodeType} type
6
- * @returns {boolean}
7
- */
8
- visit(address, type) {
9
-
10
- }
11
- }
@@ -1,8 +0,0 @@
1
- /**
2
- *
3
- * @enum {number}
4
- */
5
- export const NodeType = {
6
- LEAF: 0,
7
- BINARY: 1
8
- };
@@ -1,59 +0,0 @@
1
- import { noop } from "../../function/Functions.js";
2
- import { IndexedBinaryBVHVisitor } from "./IndexedBinaryBVHVisitor.js";
3
- import { NodeType } from "./NodeType.js";
4
- import { aabb3_intersects_ray } from "../../geom/3d/aabb/aabb3_intersects_ray.js";
5
-
6
- export class RayLeafIntersectionVisitor extends IndexedBinaryBVHVisitor {
7
- constructor() {
8
- super();
9
- this.callback = noop;
10
- this.callbackThisArg = null;
11
-
12
- this.originX = 0;
13
- this.originY = 0;
14
- this.originZ = 0;
15
-
16
- this.directionX = 0;
17
- this.directionY = 0;
18
- this.directionZ = 0;
19
-
20
- /**
21
- *
22
- * @type {IndexedBinaryBVH}
23
- */
24
- this.root = null;
25
- }
26
-
27
- visit(address, type) {
28
- const root = this.root;
29
-
30
- const data = root.data;
31
- const binaryNodeCount = root.binaryNodeCount;
32
-
33
- const x0 = data[address];
34
- const y0 = data[address + 1];
35
- const z0 = data[address + 2];
36
- const x1 = data[address + 3];
37
- const y1 = data[address + 4];
38
- const z1 = data[address + 5];
39
-
40
- const intersectionFound = aabb3_intersects_ray(x0, y0, z0, x1, y1, z1,
41
- this.originX, this.originY, this.originZ,
42
- this.directionX, this.directionY, this.directionZ
43
- );
44
-
45
- if (!intersectionFound) {
46
- return false;
47
- }
48
-
49
- if (type === NodeType.LEAF) {
50
- const value = address / 6 - binaryNodeCount;
51
-
52
- this.callback.call(this.callbackThisArg, value, address, type);
53
-
54
- return false;
55
- } else {
56
- return true;
57
- }
58
- }
59
- }
@@ -1,40 +0,0 @@
1
- import { BinaryNode } from "../BinaryNode.js";
2
- import { deserializeLeafNode, LeafNode } from "../LeafNode.js";
3
- import { deserializeAABB3 } from "../../geom/3d/aabb/deserializeAABB3.js";
4
-
5
- /**
6
- *
7
- * @param {BinaryBuffer} buffer
8
- * @param {BinaryNode} node
9
- * @param {function(buffer:BinaryBuffer):void} leafValueDeserializer
10
- */
11
- function deserializeBinaryNode(buffer, node, leafValueDeserializer) {
12
- deserializeAABB3(buffer, node);
13
-
14
- function deserializeChild() {
15
- const nodeType = buffer.readUint8();
16
- if (nodeType === 0) {
17
- return null;
18
- } else if (nodeType === 1) {
19
- const leafNode = new LeafNode();
20
- deserializeLeafNode(buffer, leafNode, leafValueDeserializer);
21
- leafNode.parentNode = node;
22
- return leafNode;
23
- } else if (nodeType === 2) {
24
- const binaryNode = new BinaryNode();
25
- deserializeBinaryNode(buffer, binaryNode, leafValueDeserializer);
26
- binaryNode.parentNode = node;
27
- return binaryNode;
28
- }
29
- }
30
-
31
- const leftNode = deserializeChild();
32
- const rightNode = deserializeChild();
33
-
34
- node.left = leftNode;
35
- node.right = rightNode;
36
-
37
- node.updateLeafNodeCount();
38
- }
39
-
40
- export { deserializeBinaryNode };
@@ -1,90 +0,0 @@
1
- import { BinaryNode } from "../BinaryNode.js";
2
- import { LeafNode } from "../LeafNode.js";
3
- import { deserializeAABB3Encoded_v0 } from "../../geom/3d/aabb/deserializeAABB3Encoded_v0.js";
4
- import { deserializeAABB3 } from "../../geom/3d/aabb/deserializeAABB3.js";
5
-
6
- /**
7
- *
8
- * @param {BinaryNode} root
9
- * @param {BinaryBuffer} buffer
10
- * @param {function(buffer:BinaryBuffer):*} leafValueDeserializer
11
- */
12
- export function deserializeBinaryNodeFromBinaryBuffer(root, buffer, leafValueDeserializer) {
13
- //read bounds
14
- deserializeAABB3(buffer, root);
15
-
16
- /**
17
- *
18
- * @param {BinaryNode} parent
19
- * @returns {BinaryNode}
20
- */
21
- function readBinaryNode(parent) {
22
-
23
- const node = new BinaryNode();
24
-
25
- node.parentNode = parent;
26
-
27
- //read bounds
28
- deserializeAABB3Encoded_v0(buffer, node, parent.x0, parent.y0, parent.z0, parent.x1, parent.y1, parent.z1);
29
-
30
- //read marker
31
- const marker = buffer.readUint8();
32
-
33
- if ((marker & 3) === 3) {
34
- node.left = readBinaryNode(node);
35
- } else if ((marker & 2) === 2) {
36
- node.left = readLeafNode(node);
37
- } else {
38
- node.left = null;
39
- }
40
-
41
- if ((marker & 12) === 12) {
42
- node.right = readBinaryNode(node);
43
- } else if ((marker & 8) === 8) {
44
- node.right = readLeafNode(node);
45
- } else {
46
- node.right = null;
47
- }
48
-
49
- node.updateLeafNodeCount();
50
-
51
- return node;
52
- }
53
-
54
- /**
55
- *
56
- * @param {BinaryNode} parent
57
- * @returns {LeafNode}
58
- */
59
- function readLeafNode(parent) {
60
- const node = new LeafNode();
61
-
62
- node.parentNode = parent;
63
-
64
- //read bounds
65
- deserializeAABB3Encoded_v0(buffer, node, parent.x0, parent.y0, parent.z0, parent.x1, parent.y1, parent.z1);
66
-
67
- node.object = leafValueDeserializer(buffer);
68
-
69
- return node;
70
- }
71
-
72
- //read marker
73
- const marker = buffer.readUint8();
74
-
75
- if ((marker & 3) === 3) {
76
- root.left = readBinaryNode(root);
77
- } else if ((marker & 2) === 2) {
78
- root.left = readLeafNode(root);
79
- } else {
80
- root.left = null;
81
- }
82
-
83
- if ((marker & 12) === 12) {
84
- root.right = readBinaryNode(root);
85
- } else if ((marker & 8) === 8) {
86
- root.right = readLeafNode(root);
87
- } else {
88
- root.right = null;
89
- }
90
- }
@@ -1,31 +0,0 @@
1
- import {serializeAABB3} from "../../geom/3d/aabb/serializeAABB3.js";
2
- import {isLeaf, serializeLeafNode} from "../LeafNode.js";
3
-
4
- /**
5
- *
6
- * @param {BinaryBuffer} buffer
7
- * @param {BinaryNode} node
8
- * @param {function(buffer:BinaryBuffer,value:any):void} leafValueSerializer
9
- */
10
- function serializeBinaryNode(buffer, node, leafValueSerializer) {
11
- serializeAABB3(buffer, node);
12
-
13
- function serializeChild(child) {
14
- if (child === null) {
15
- buffer.writeUint8(0);
16
- } else {
17
- if (isLeaf(child)) {
18
- buffer.writeUint8(1);
19
- serializeLeafNode(buffer, child, leafValueSerializer);
20
- } else {
21
- buffer.writeUint8(2);
22
- serializeBinaryNode(buffer, child, leafValueSerializer);
23
- }
24
- }
25
- }
26
-
27
- serializeChild(node.left);
28
- serializeChild(node.right);
29
- }
30
-
31
- export {serializeBinaryNode};
@@ -1,86 +0,0 @@
1
- import { serializeAABB3 } from "../../geom/3d/aabb/serializeAABB3.js";
2
- import { serializeAABB3Encoded_v0 } from "../../geom/3d/aabb/serializeAABB3Encoded_v0.js";
3
-
4
- /**
5
- *
6
- * @param {BinaryBuffer} buffer
7
- * @param {BinaryNode} node
8
- * @param {BinaryNode} parent
9
- * @param {function(buffer:BinaryBuffer, value:*):void} leafValueSerializer
10
- */
11
- function writeBinaryNode(buffer, node, parent, leafValueSerializer) {
12
- serializeAABB3Encoded_v0(buffer, node, parent.x0, parent.y0, parent.z0, parent.x1, parent.y1, parent.z1);
13
-
14
- writeBinaryNodeContents(buffer, node, leafValueSerializer);
15
- }
16
-
17
- /**
18
- *
19
- * @param {BinaryBuffer} buffer
20
- * @param {BinaryNode} node
21
- * @param {function(buffer:BinaryBuffer, value:*):void} leafValueSerializer
22
- */
23
- function writeBinaryNodeContents(buffer, node, leafValueSerializer) {
24
-
25
- //build header marker for the node
26
- let marker = 0;
27
-
28
- const right = node.right;
29
-
30
- if (right !== null) {
31
- if (right.isLeafNode) {
32
- marker |= 8;
33
- } else {
34
- marker |= 12;
35
- }
36
- }
37
-
38
- const left = node.left;
39
-
40
- if (left !== null) {
41
- if (left.isLeafNode) {
42
- marker |= 2;
43
- } else {
44
- marker |= 3;
45
- }
46
- }
47
-
48
- buffer.writeUint8(marker);
49
-
50
- if ((marker & 3) === 3) {
51
- writeBinaryNode(buffer, left, node, leafValueSerializer);
52
- } else if ((marker & 2) === 2) {
53
- writeLeafNode(buffer, left, node, leafValueSerializer);
54
- }
55
-
56
- if ((marker & 12) === 12) {
57
- writeBinaryNode(buffer, right, node, leafValueSerializer);
58
- } else if ((marker & 8) === 8) {
59
- writeLeafNode(buffer, right, node, leafValueSerializer);
60
- }
61
- }
62
-
63
- /**
64
- *
65
- * @param {BinaryBuffer} buffer
66
- * @param {LeafNode} node
67
- * @param {BinaryNode} parent
68
- * @param {function(buffer:BinaryBuffer, value:*):void} leafValueSerializer
69
- */
70
- function writeLeafNode(buffer, node, parent, leafValueSerializer) {
71
- serializeAABB3Encoded_v0(buffer, node, parent.x0, parent.y0, parent.z0, parent.x1, parent.y1, parent.z1);
72
- leafValueSerializer(buffer, node.object);
73
- }
74
-
75
- /**
76
- * Writing is lossy, all descendants have their bounds quantized to uin16
77
- * @param {BinaryNode} root
78
- * @param {BinaryBuffer} buffer
79
- * @param {function(buffer:BinaryBuffer, value:*):void} leafValueSerializer
80
- */
81
- export function serializeBinaryNodeToBinaryBuffer(root, buffer, leafValueSerializer) {
82
- //write initial size
83
- serializeAABB3(buffer, root);
84
-
85
- writeBinaryNodeContents(buffer, root, leafValueSerializer);
86
- }
@@ -1,144 +0,0 @@
1
- import { BinaryNode } from "../BinaryNode.js";
2
- import { isLeaf } from "../LeafNode.js";
3
- import { surfaceAreaHeuristic } from "../sah/surfaceAreaHeuristic.js";
4
- import { aabb3_score_boxes_SAH } from "../../geom/3d/aabb/aabb3_score_boxes_SAH.js";
5
- import { aabb3_box_surface_area_2 } from "../../geom/3d/aabb/aabb3_box_surface_area_2.js";
6
-
7
- function BottomUpOptimizingRebuilder() {
8
- this.root = null;
9
- this.nodes = [];
10
- /**
11
- * @type {function(left:NodeDescription, right:NodeDescription):number} heuristic Cost function of pairing two nodes, lower value means better pairing
12
- */
13
- this.heuristic = aabb3_score_boxes_SAH;
14
- }
15
-
16
- /**
17
- *
18
- * @param {BinaryNode} root
19
- */
20
- BottomUpOptimizingRebuilder.prototype.init = function (root) {
21
- this.root = root;
22
- const nodes = this.nodes = [];
23
- const binaryNodePool = this.binaryNodePool = [];
24
-
25
- //first extract all leaf nodes
26
- root.traversePreOrderUsingStack(function (node) {
27
- if (isLeaf(node)) {
28
- nodes.push(node);
29
- } else if (node !== root) {
30
- //collect intermediate nodes for reuse
31
- binaryNodePool.push(node);
32
- }
33
- });
34
- };
35
- /**
36
- * Factory to allow reuse of existing node, avoiding garbage collection
37
- * @returns {BinaryNode}
38
- */
39
- BottomUpOptimizingRebuilder.prototype.makeBinaryNode = function () {
40
- if (this.binaryNodePool.length > 0) {
41
- return this.binaryNodePool.pop();
42
- } else {
43
- return new BinaryNode();
44
- }
45
- };
46
-
47
- /**
48
- *
49
- * @param {number} maxSteps
50
- * @returns {boolean} true when complete
51
- */
52
- BottomUpOptimizingRebuilder.prototype.compute = function (maxSteps) {
53
- const self = this;
54
- /**
55
- *
56
- * @type {Array.<NodeDescription>}
57
- */
58
- const nodes = this.nodes;
59
-
60
- let nodeCount = nodes.length;
61
-
62
- const heuristic = this.heuristic;
63
-
64
- let stepsRemaining = maxSteps;
65
-
66
-
67
- while (nodeCount > 2 && stepsRemaining-- >= 0) {
68
- let bestI = -1;
69
- let bestJ = -1;
70
- let bestCost = Number.POSITIVE_INFINITY;
71
- for (let i = 0; i < nodeCount - 1; i++) {
72
- const first = nodes[i];
73
- for (let j = i + 1; j < nodeCount; j++) {
74
- const second = nodes[j];
75
-
76
- const cost = heuristic(first, second);
77
-
78
- if (cost < bestCost) {
79
- bestCost = cost;
80
-
81
- bestI = i;
82
- bestJ = j;
83
- }
84
- }
85
- }
86
-
87
- const first = nodes[bestI];
88
- const second = nodes[bestJ];
89
-
90
- const binaryNode = self.makeBinaryNode();
91
- binaryNode.setChildren(first, second);
92
-
93
- //transplant new node in place of the second removed node
94
- nodes[bestI] = binaryNode;
95
- nodes.splice(bestJ, 1);
96
-
97
- nodeCount--;
98
- }
99
-
100
- const root = this.root;
101
-
102
- if (nodeCount === 2) {
103
- root.setChildren(nodes[0], nodes[1]);
104
- return true;
105
- } else if (nodeCount === 1) {
106
- root.left = nodes[0];
107
- root.left.parentNode = root;
108
- root.refit();
109
- return true;
110
- } else if (nodeCount === 0) {
111
- //no nodes, we're done
112
- return true;
113
- } else {
114
- //not done yet
115
- return false;
116
- }
117
- };
118
-
119
- const leafCounts = new Map();
120
-
121
- function leaves(node) {
122
- if (leafCounts.has(node)) {
123
- return leafCounts.get(node);
124
- } else {
125
- const count = countLeaves(node);
126
- leafCounts.set(node, count);
127
- return count;
128
- }
129
- }
130
-
131
- function sah(left, right) {
132
- const leftArea = aabb3_box_surface_area_2(left);
133
- const rightArea = aabb3_box_surface_area_2(right);
134
-
135
- const leftLeaves = leaves(left);
136
- const rightLeaves = leaves(right);
137
-
138
- const commonArea = aabb3_score_boxes_SAH(left, right);
139
-
140
- return surfaceAreaHeuristic(commonArea, leftArea, rightArea, leftLeaves, rightLeaves);
141
- }
142
-
143
-
144
- export { BottomUpOptimizingRebuilder };
@@ -1,123 +0,0 @@
1
- import { BinaryNode } from "../BinaryNode.js";
2
- import { isLeaf } from "../LeafNode.js";
3
- import { StacklessTraverser } from "../StacklessTraverser.js";
4
- import { tryRotateSingleNode } from "./tryRotateSingleNode.js";
5
-
6
-
7
- /**
8
- *
9
- * @type {(BinaryNode|LeafNode)[]}
10
- */
11
- const stack = [];
12
- let stackPointer = 0;
13
-
14
- /**
15
- * * @param {BinaryNode} node
16
- * @param {Map.<NodeDescription,int>} leafCounts
17
- */
18
- function getLeafCount(node, leafCounts) {
19
- if (isLeaf(node)) {
20
- return 1;
21
- }
22
-
23
- let result = 0;
24
-
25
- let n;
26
-
27
- const storedValue = leafCounts.get(node);
28
-
29
- if (storedValue !== undefined) {
30
- return storedValue;
31
- }
32
-
33
- const stackOffset = stackPointer;
34
-
35
- stack[stackPointer++] = node;
36
-
37
- while (stackPointer-- > stackOffset) {
38
-
39
- n = stack[stackPointer];
40
-
41
-
42
- const storedValue = leafCounts.get(node);
43
-
44
- if (storedValue !== undefined) {
45
- result += storedValue;
46
- continue;
47
- }
48
-
49
-
50
- if (n.isBinaryNode) {
51
-
52
- if (n.right !== null) {
53
- stack[stackPointer++] = n.right;
54
- }
55
-
56
- if (n.left !== null) {
57
- stack[stackPointer++] = n.left;
58
- }
59
-
60
- } else {
61
-
62
- result++;
63
- }
64
-
65
- }
66
-
67
- //drop the stack frame
68
- stackPointer = stackOffset;
69
-
70
- leafCounts.set(node, result);
71
-
72
- return result;
73
- }
74
-
75
- /**
76
- *
77
- * @param {BinaryNode} root
78
- * @param {int} maxIterations
79
- */
80
- export function optimize(root, maxIterations = 1000) {
81
- const traverser = new StacklessTraverser();
82
-
83
- traverser.init(root);
84
-
85
- let changeCounter = 0;
86
-
87
- const leafCounts = new Map();
88
-
89
- function visit(node) {
90
-
91
- if (isLeaf(node)) {
92
- //skip leaves
93
- return true;
94
- }
95
-
96
- const rotationType = tryRotateSingleNode(node, leafCounts);
97
- if (rotationType !== 0) {
98
- changeCounter++;
99
- }
100
- }
101
-
102
- let oldChangeCounter = changeCounter;
103
-
104
- let i;
105
- for (i = 0; i < maxIterations; i++) {
106
- const canAdvance = traverser.advance(visit);
107
- if (!canAdvance) {
108
- //check if we have made any rotations in this traversal pass
109
- if (oldChangeCounter === changeCounter) {
110
- //done, no changes
111
- break;
112
- } else {
113
- oldChangeCounter = changeCounter;
114
- }
115
-
116
- //re-initialize the traverser
117
- traverser.init(root);
118
- }
119
-
120
- }
121
-
122
- return changeCounter;
123
- }