@woosh/meep-engine 2.34.31 → 2.34.35

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 (33) hide show
  1. package/core/assert.js +11 -0
  2. package/core/bvh2/BinaryNode.js +213 -26
  3. package/core/bvh2/Node.d.ts +3 -0
  4. package/core/bvh2/aabb3/AABB3.js +4 -3
  5. package/core/bvh2/aabb3/AABB3Math.js +1 -1
  6. package/core/bvh2/transform/RotationOptimizer.js +2 -262
  7. package/core/bvh2/transform/tryRotateSingleNode.js +259 -0
  8. package/core/collection/list/List.js +0 -34
  9. package/core/collection/table/DataTypeByteSizes.js +16 -0
  10. package/core/events/signal/Signal.js +1 -1
  11. package/engine/Engine.js +5 -0
  12. package/engine/asset/loaders/ArrayBufferLoader.js +7 -0
  13. package/engine/asset/loaders/image/ImageRGBADataLoader.js +11 -6
  14. package/engine/development/performance/AbstractMetric.js +4 -0
  15. package/engine/development/performance/RingBufferMetric.js +4 -0
  16. package/engine/ecs/EntityBuilder.js +12 -5
  17. package/engine/ecs/EntityComponentDataset.js +26 -6
  18. package/engine/ecs/attachment/AttachmentSystem.js +1 -1
  19. package/engine/ecs/sockets/AttachmentSockets.js +11 -1
  20. package/engine/ecs/transform/Transform.js +1 -1
  21. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +16 -3
  22. package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +3 -0
  23. package/engine/graphics/ecs/mesh-v2/sample/load_gltf.js +60 -0
  24. package/engine/graphics/ecs/mesh-v2/{prototypeShadedGeometry.js → sample/prototypeShadedGeometry.js} +5 -5
  25. package/engine/graphics/ecs/mesh-v2/three_object_to_entity_composition.js +37 -0
  26. package/engine/graphics/micron/build/buildMicronGeometryFromBufferGeometry.js +15 -0
  27. package/engine/graphics/micron/build/compute_micron_buffer_array_constructor.js +2 -0
  28. package/engine/graphics/micron/build/fill_patch_geometry_data.js +39 -5
  29. package/engine/graphics/micron/prototypeVirtualGeometry.js +7 -1
  30. package/engine/graphics/micron/render/instanced/AttributeDataTexture.js +3 -0
  31. package/engine/graphics/micron/render/instanced/shader/shader_rewrite_standard.js +23 -0
  32. package/engine/sound/ecs/emitter/SoundEmitterSystem.js +1 -1
  33. package/package.json +1 -1
package/core/assert.js CHANGED
@@ -316,6 +316,17 @@ assert.defined = function (value, name = "value") {
316
316
 
317
317
  };
318
318
 
319
+ /**
320
+ *
321
+ * @param {*} value
322
+ * @param {String} [name]
323
+ */
324
+ assert.isNull = function (value, name){
325
+ if (value !== null) {
326
+ throw new Error(`${name} is NOT null`);
327
+ }
328
+ }
329
+
319
330
  /**
320
331
  *
321
332
  * @param {*} value
@@ -8,7 +8,7 @@ import { arrayQuickSort } from "../collection/array/arrayQuickSort.js";
8
8
  import { max2 } from "../math/max2.js";
9
9
  import { min2 } from "../math/min2.js";
10
10
  import { computeSampleStandardDeviation } from "../math/statistics/computeSampleStandardDeviation.js";
11
- import { aabb3_intersect_aabb3, boxSurfaceArea2 } from "./aabb3/AABB3Math.js";
11
+ import { _boxSurfaceArea2, aabb3_intersect_aabb3, boxSurfaceArea2 } from "./aabb3/AABB3Math.js";
12
12
  import { isLeaf, LeafNode } from "./LeafNode.js";
13
13
  import { Node } from "./Node.js";
14
14
  import { surfaceAreaHeuristic } from "./sah/surfaceAreaHeuristic.js";
@@ -139,13 +139,135 @@ BinaryNode.prototype.setChildren = function (left, right) {
139
139
  right.parentNode = this;
140
140
  };
141
141
 
142
+ /**
143
+ *
144
+ * @param {Node} child
145
+ */
146
+ BinaryNode.prototype.setChildLeft = function (child) {
147
+ assert.isNull(this.left, 'left');
148
+
149
+ this.left = child;
150
+
151
+ this.updateLeafNodeCount();
152
+
153
+ this.refit();
154
+
155
+ child.parentNode = this;
156
+ }
157
+
158
+ /**
159
+ *
160
+ * @param {Node} child
161
+ */
162
+ BinaryNode.prototype.setChildRight = function (child) {
163
+ assert.isNull(this.right, 'right');
164
+
165
+ this.right = child;
166
+
167
+ this.updateLeafNodeCount();
168
+
169
+ this.refit();
170
+
171
+ child.parentNode = this;
172
+ }
173
+
174
+ /**
175
+ * @see "Dynamic BVH" by Erin Catto / Blizzard
176
+ * @param {AABB3} node
177
+ * @param {AABB3} addition
178
+ * @returns {number}
179
+ */
180
+ function inclusion_surface_area_heuristic(node, addition) {
181
+ const x0 = min2(node.x0, addition.x0);
182
+ const y0 = min2(node.y0, addition.y0);
183
+ const z0 = min2(node.z0, addition.z0);
184
+
185
+ const x1 = max2(node.x1, addition.x1);
186
+ const y1 = max2(node.y1, addition.y1);
187
+ const z1 = max2(node.z1, addition.z1);
188
+
189
+ return _boxSurfaceArea2(x0, y0, z0, x1, y1, z1) - boxSurfaceArea2(node);
190
+ }
191
+
192
+ /**
193
+ *
194
+ * @param {BinaryNode|LeafNode} node
195
+ * @param {AABB3} addition
196
+ */
197
+ function inclusion_cost_lower_bound(node, addition) {
198
+ let n = node;
199
+ let r = boxSurfaceArea2(addition);
200
+
201
+ while (n !== null) {
202
+
203
+ r += n.costForInclusion(addition);
204
+
205
+ n = n.parentNode;
206
+ }
207
+
208
+ return r;
209
+ }
210
+
211
+ /**
212
+ * For incremental insertion, a sibling needs to be found, newly inserted node will be parented together with this sibling
213
+ * @param {AABB3} box
214
+ * @returns {BinaryNode|LeafNode}
215
+ */
216
+ BinaryNode.prototype.__insertion_findSiblingFor = function (box) {
217
+
218
+ const open_set = [this];
219
+ let cursor = 1;
220
+
221
+ let best_cost = Infinity;
222
+ let best_node = this;
223
+
224
+ while (cursor > 0) {
225
+ const node = open_set[--cursor];
226
+
227
+ const cost = inclusion_surface_area_heuristic(node, box);
228
+
229
+ if (cost < best_cost) {
230
+ best_cost = cost;
231
+ best_node = node;
232
+ }
233
+
234
+ if (node.isBinaryNode) {
235
+
236
+ if (node.isProtected()) {
237
+ continue;
238
+ }
239
+
240
+ // consider pushing children into the queue
241
+
242
+ // compute lower bound for cost
243
+ const c_low = inclusion_cost_lower_bound(node, box);
244
+
245
+ if (c_low < best_cost) {
246
+ // worth-while to explore children
247
+ if (node.left !== null) {
248
+ open_set[cursor++] = node.left;
249
+ }
250
+ if (node.right !== null) {
251
+ open_set[cursor++] = node.right
252
+ }
253
+ }
254
+ }
255
+
256
+
257
+ }
258
+
259
+ return best_node;
260
+ }
261
+
142
262
  /**
143
263
  *
144
264
  * @param {AABB3} box
145
- * @returns {Node}
265
+ * @returns {Node|BinaryNode|LeafNode}
146
266
  */
147
267
  BinaryNode.prototype.findParentFor = function (box) {
148
268
  let n = this;
269
+ let aCost = 0;
270
+ let bCost = 0;
149
271
 
150
272
  for (; ;) {
151
273
 
@@ -181,8 +303,8 @@ BinaryNode.prototype.findParentFor = function (box) {
181
303
  }
182
304
  }
183
305
 
184
- let aCost = a.costForInclusion(box);
185
- let bCost = b.costForInclusion(box);
306
+ aCost = a.costForInclusion(box);
307
+ bCost = b.costForInclusion(box);
186
308
 
187
309
  if (aCost === bCost) {
188
310
 
@@ -196,9 +318,9 @@ BinaryNode.prototype.findParentFor = function (box) {
196
318
 
197
319
  }
198
320
 
199
- //change costs to be surface areas instead
200
- aCost = a.computeSAH();
201
- bCost = b.computeSAH();
321
+ //change costs to be based on balance
322
+ aCost = a.leafNodeCount / boxSurfaceArea2(a);
323
+ bCost = b.leafNodeCount / boxSurfaceArea2(b);
202
324
  }
203
325
 
204
326
  if (aCost === bCost) {
@@ -419,11 +541,12 @@ BinaryNode.prototype.bubbleRefit = function () {
419
541
  n = n.parentNode;
420
542
 
421
543
  if (n === null) {
544
+ // hit the root
422
545
  return;
423
546
  }
424
547
 
425
- //check if this node violates bounds of the parent
426
548
 
549
+ //check if this node violates bounds of the parent
427
550
  let flag = false;
428
551
 
429
552
  if (_x0 < n.x0) {
@@ -518,26 +641,29 @@ function countLeaves(node) {
518
641
  }
519
642
 
520
643
  /**
521
- *
644
+ * @deprecated Incorrect usage of SAH
522
645
  * @return {number}
523
646
  */
524
647
  BinaryNode.prototype.computeSAH = function () {
525
648
  let leftLeaves, rightLeaves, leftArea, rightArea;
526
649
 
527
- if (this.left === null) {
650
+ const left = this.left;
651
+
652
+ if (left === null) {
528
653
  leftArea = 0;
529
654
  leftLeaves = 0;
530
655
  } else {
531
- leftArea = boxSurfaceArea2(this.left);
532
- leftLeaves = this.left.leafNodeCount;
656
+ leftArea = boxSurfaceArea2(left);
657
+ leftLeaves = left.leafNodeCount;
533
658
  }
534
659
 
535
- if (this.right === null) {
660
+ const right = this.right;
661
+ if (right === null) {
536
662
  rightArea = 0;
537
663
  rightLeaves = 0;
538
664
  } else {
539
- rightArea = boxSurfaceArea2(this.right);
540
- rightLeaves = this.right.leafNodeCount;
665
+ rightArea = boxSurfaceArea2(right);
666
+ rightLeaves = right.leafNodeCount;
541
667
  }
542
668
 
543
669
  const thisArea = boxSurfaceArea2(this);
@@ -1065,34 +1191,96 @@ function transplantNewCommonParent(node, child) {
1065
1191
 
1066
1192
  parent.bubbleExpandToFit(bNode);
1067
1193
 
1194
+ parent.updateLeafNodeCount();
1195
+
1068
1196
  return bNode;
1069
1197
  }
1070
1198
 
1199
+
1071
1200
  /**
1072
1201
  *
1073
1202
  * @param {Node|BinaryNode|LeafNode} child
1074
1203
  */
1075
1204
  BinaryNode.prototype.insertNode = function (child) {
1076
- assert.notEqual(child, null, "child node is null");
1077
- assert.notEqual(child, undefined, "child node is undefined");
1078
- assert.ok(child instanceof Node, undefined, "child node is not an instance of Node");
1205
+
1206
+ assert.notNull(child, "child");
1207
+ assert.defined(child, "child");
1208
+ assert.isInstanceOf(child, Node, 'child', "Node");
1209
+ assert.equal(child.parentNode, null, "parentNode must be null, otherwise Node still belongs to another tree");
1210
+
1211
+ const sibling = this.__insertion_findSiblingFor(child);
1212
+
1213
+ const sibling_parent = sibling.parentNode;
1214
+ if (sibling_parent === null) {
1215
+ // root node
1216
+
1217
+ if (sibling.left === null) {
1218
+ sibling.setChildLeft(child);
1219
+ } else if (sibling.right === null) {
1220
+ sibling.setChildRight(child);
1221
+ } else {
1222
+ const parent = new BinaryNode();
1223
+
1224
+ parent.setChildren(sibling.right, child);
1225
+ sibling.right = parent;
1226
+ parent.parentNode = sibling;
1227
+ }
1228
+
1229
+ } else {
1230
+
1231
+ // non-root
1232
+
1233
+ if (sibling_parent.left === sibling && sibling_parent.right === null) {
1234
+
1235
+ // right node is free, take it
1236
+ sibling_parent.setChildRight(child);
1237
+
1238
+ } else if (sibling_parent.right === sibling && sibling_parent.left === null) {
1239
+
1240
+ // left node is free, take it
1241
+ sibling_parent.setChildLeft(child);
1242
+
1243
+ } else {
1244
+
1245
+ transplantNewCommonParent(sibling, child)
1246
+
1247
+ }
1248
+
1249
+ sibling_parent.bubbleRefit();
1250
+
1251
+ }
1252
+ }
1253
+
1254
+ /**
1255
+ * @deprecated
1256
+ * @param {Node|BinaryNode|LeafNode} child
1257
+ */
1258
+ BinaryNode.prototype.insertNode_old = function (child) {
1259
+ assert.notNull(child, "child");
1260
+ assert.defined(child, "child");
1261
+ assert.isInstanceOf(child, Node, 'child', "Node");
1079
1262
  assert.equal(child.parentNode, null, "parentNode must be null, otherwise Node still belongs to another tree");
1080
1263
 
1081
1264
  const node = this.findParentFor(child);
1082
1265
 
1083
1266
  let bNode;
1084
1267
 
1085
- if (node.isBinaryNode) {
1086
- if ((node.isProtected() && node !== this)) {
1087
- transplantNewCommonParent(node, child);
1088
- } else if (node.left === null) {
1268
+ if (
1269
+ node.isBinaryNode &&
1270
+ !(node.isProtected() && node !== this) // protected node, can't insert into this subtree
1271
+ ) {
1272
+
1273
+ if (node.left === null) {
1089
1274
  node.left = child;
1090
1275
  child.parentNode = node;
1091
1276
  node.bubbleExpandToFit(child);
1277
+
1092
1278
  } else if (node.right === null) {
1279
+
1093
1280
  node.right = child;
1094
1281
  child.parentNode = node;
1095
1282
  node.bubbleExpandToFit(child);
1283
+
1096
1284
  } else {
1097
1285
  //take right child and insert another binary node there
1098
1286
  bNode = new BinaryNode();
@@ -1106,18 +1294,17 @@ BinaryNode.prototype.insertNode = function (child) {
1106
1294
  node.updateLeafNodeCount();
1107
1295
  } else {
1108
1296
  //need to do transplanting and introduce a new common parent
1109
- bNode = transplantNewCommonParent(node, child);
1297
+ transplantNewCommonParent(node, child);
1110
1298
 
1111
- bNode.updateLeafNodeCount();
1112
1299
  }
1113
1300
 
1114
1301
  };
1115
1302
 
1116
1303
  /**
1117
- *
1304
+ * @param {boolean} deep
1118
1305
  * @returns {BinaryNode}
1119
1306
  */
1120
- BinaryNode.prototype.clone = function (deep) {
1307
+ BinaryNode.prototype.clone = function (deep = false) {
1121
1308
  const clone = new BinaryNode();
1122
1309
 
1123
1310
  clone.x0 = this.x0;
@@ -3,4 +3,7 @@ import {BinaryNode} from "./BinaryNode";
3
3
 
4
4
  export class Node<T> extends AABB3 {
5
5
  public parentNode: BinaryNode<T>
6
+
7
+
8
+ readonly leafNodeCount: number
6
9
  }
@@ -6,7 +6,7 @@
6
6
  import { aabb3_computeDistanceAbovePlane } from "../../geom/3d/aabb/aabb3_computeDistanceAbovePlane.js";
7
7
  import { computeAABB3PlaneSide } from "../../geom/3d/aabb/computeAABB3PlaneSide.js";
8
8
  import computeMortonCode from "../../geom/3d/morton/Morton.js";
9
- import { _boxSurfaceArea2, intersectRay, intersectSegment } from "./AABB3Math.js";
9
+ import { boxSurfaceArea, intersectRay, intersectSegment } from "./AABB3Math.js";
10
10
  import { aabb3_build_corners } from "../../geom/3d/aabb/aabb3_build_corners.js";
11
11
  import { assert } from "../../assert.js";
12
12
 
@@ -81,7 +81,7 @@ AABB3.prototype.computeMortonCode = function () {
81
81
  * @returns {number}
82
82
  */
83
83
  AABB3.prototype.computeSurfaceArea = function () {
84
- return _boxSurfaceArea2(this.x0, this.y0, this.z0, this.x1, this.y1, this.z1);
84
+ return boxSurfaceArea(this.x0, this.y0, this.z0, this.x1, this.y1, this.z1);
85
85
  };
86
86
 
87
87
  /**
@@ -296,7 +296,8 @@ AABB3.prototype.costForInclusion = function (other) {
296
296
  };
297
297
 
298
298
  /**
299
- *
299
+ * Surface area delta when including a given AABB
300
+ * 0 means that including a given AABB would not cause any change to total surface area
300
301
  * @param {number} x0
301
302
  * @param {number} y0
302
303
  * @param {number} z0
@@ -540,7 +540,7 @@ function boxSurfaceArea(x0, y0, z0, x1, y1, z1) {
540
540
  const dx = x1 - x0;
541
541
  const dy = y1 - y0;
542
542
  const dz = z1 - z0;
543
- return (dx * dy + dy * dz + dz * dx) * 2; //2 of each side
543
+ return (dy * (dx + dz) + dz * dx) * 2; //2 of each side
544
544
  }
545
545
 
546
546
  /**
@@ -1,8 +1,7 @@
1
- import { boxSurfaceArea2 as computeArea, scoreBoxesSAH as computeAreaFor2 } from "../aabb3/AABB3Math.js";
2
1
  import { BinaryNode } from "../BinaryNode.js";
3
2
  import { isLeaf } from "../LeafNode.js";
4
- import { surfaceAreaHeuristic as sah } from "../sah/surfaceAreaHeuristic.js";
5
3
  import { StacklessTraverser } from "../StacklessTraverser.js";
4
+ import { tryRotateSingleNode } from "./tryRotateSingleNode.js";
6
5
 
7
6
 
8
7
  /**
@@ -73,266 +72,12 @@ function getLeafCount(node, leafCounts) {
73
72
  return result;
74
73
  }
75
74
 
76
- /**
77
- *
78
- * @param {Node} node
79
- * @param {BinaryNode} parent
80
- */
81
- function setParent(node, parent) {
82
- node.parentNode = parent;
83
- }
84
-
85
- /**
86
- * Based on paper "Fast, Effective BVH Updates for Animated Scenes" Kopta et. al. (url: http://www.cs.utah.edu/~thiago/papers/rotations.pdf)
87
- * @param {BinaryNode} node
88
- * @param {Map.<NodeDescription,int>} leafCounts
89
- * @returns {int} value from 0 to 6, 0 means no rotation has taken place
90
- */
91
- function tryRotateSingleNode(node, leafCounts) {
92
-
93
-
94
- const left = node.left;
95
- const right = node.right;
96
-
97
- if (left === null || right === null) {
98
- return 0;
99
- }
100
-
101
- let bestRotation = 0;
102
-
103
-
104
- const nodeArea = computeArea(node);
105
- const leftArea = computeArea(left);
106
- const rightArea = computeArea(right);
107
-
108
- const leftLeaves = left.leafNodeCount;
109
- const rightLeaves = right.leafNodeCount;
110
-
111
-
112
- let bestCost = sah(
113
- nodeArea,
114
- leftArea,
115
- rightArea,
116
- leftLeaves,
117
- rightLeaves
118
- );
119
-
120
- let candidateCost;
121
-
122
- let leftLeftArea,
123
- leftRightArea,
124
- rightLeftArea,
125
- rightRightArea;
126
-
127
- let leftLeft,
128
- leftRight,
129
- rightLeft,
130
- rightRight;
131
-
132
- let leftLeftLeaves,
133
- leftRightLeaves,
134
- rightLeftLeaves,
135
- rightRightLeaves;
136
-
137
- let considerLeft = !isLeaf(left);
138
-
139
- if (considerLeft) {
140
- leftLeft = left.left;
141
- leftRight = left.right;
142
-
143
- considerLeft = (leftLeft !== null && leftRight !== null);
144
- if (considerLeft) {
145
-
146
- leftLeftArea = computeArea(leftLeft);
147
- leftRightArea = computeArea(leftRight);
148
-
149
- leftLeftLeaves = leftLeft.leafNodeCount;
150
- leftRightLeaves = leftRight.leafNodeCount;
151
-
152
- // (1) N N //
153
- // / \ / \ //
154
- // L R -----> L LL //
155
- // / \ / \ //
156
- // LL LR R LR //
157
- candidateCost = sah(nodeArea, computeAreaFor2(right, leftRight), leftLeftArea, rightLeaves + leftRightLeaves, leftLeftLeaves);
158
-
159
- if (candidateCost < bestCost) {
160
- bestRotation = 1;
161
- bestCost = candidateCost;
162
- }
163
-
164
- // (2) N N //
165
- // / \ / \ //
166
- // L R -----> L LR //
167
- // / \ / \ //
168
- // LL LR LL R //
169
- candidateCost = sah(nodeArea, computeAreaFor2(leftLeft, right), leftRightArea, leftLeftLeaves + rightLeaves, leftRightLeaves);
170
-
171
-
172
- if (candidateCost < bestCost) {
173
- bestRotation = 2;
174
- bestCost = candidateCost;
175
- }
176
- }
177
- }
178
- if (!isLeaf(right)) {
179
- rightLeft = right.left;
180
- rightRight = right.right;
181
- if (rightLeft !== null && rightRight !== null) {
182
-
183
- rightLeftArea = computeArea(rightLeft);
184
- rightRightArea = computeArea(rightRight);
185
-
186
- rightLeftLeaves = rightLeft.leafNodeCount;
187
- rightRightLeaves = rightRight.leafNodeCount;
188
-
189
- // (3) N N //
190
- // / \ / \ //
191
- // L R -----> RL R //
192
- // / \ / \ //
193
- // RL RR L RR //
194
- candidateCost = sah(nodeArea, rightLeftArea, computeAreaFor2(left, rightRight), rightLeftLeaves, leftLeaves + rightRightLeaves);
195
-
196
- if (candidateCost < bestCost) {
197
- bestRotation = 3;
198
- bestCost = candidateCost;
199
- }
200
-
201
- // (4) N N //
202
- // / \ / \ //
203
- // L R -----> RR R //
204
- // / \ / \ //
205
- // RL RR RL L //
206
- candidateCost = sah(nodeArea, rightRightArea, computeAreaFor2(rightLeft, left), rightRightLeaves, rightLeftLeaves + leftLeaves);
207
-
208
-
209
- if (candidateCost < bestCost) {
210
- bestRotation = 4;
211
- bestCost = candidateCost;
212
- }
213
-
214
- if (considerLeft) {
215
- //both child nodes are not leaf
216
-
217
- // (5) N N //
218
- // / \ / \ //
219
- // L R -----> L R //
220
- // / \ / \ / \ / \ //
221
- // LL LR RL RR LL RL LR RR //
222
- candidateCost = sah(
223
- nodeArea,
224
- computeAreaFor2(leftLeft, rightLeft),
225
- computeAreaFor2(leftRight, rightRight),
226
- leftLeftLeaves + rightLeftLeaves,
227
- leftRightLeaves + rightRightLeaves
228
- );
229
-
230
-
231
- if (candidateCost < bestCost) {
232
- bestRotation = 5;
233
- bestCost = candidateCost;
234
- }
235
-
236
- // (6) N N //
237
- // / \ / \ //
238
- // L R -----> L R //
239
- // / \ / \ / \ / \ //
240
- // LL LR RL RR LL RR RL LR //
241
- candidateCost = sah(
242
- nodeArea,
243
- computeAreaFor2(leftLeft, rightRight),
244
- computeAreaFor2(rightLeft, leftRight),
245
- leftLeftLeaves + rightRightLeaves,
246
- rightLeftLeaves + leftRightLeaves
247
- );
248
-
249
- if (candidateCost < bestCost) {
250
- bestRotation = 6;
251
- }
252
- }
253
- }
254
- }
255
-
256
- switch (bestRotation) {
257
- case 0:
258
- //no rotation
259
- break;
260
- case 1:
261
- node.right = leftLeft;
262
- setParent(leftLeft, node);
263
- left.left = right;
264
- setParent(right, left);
265
-
266
- left.refit();
267
- //update leaf count
268
- node.left.updateLeafNodeCount();
269
- break;
270
- case 2:
271
- node.right = leftRight;
272
- setParent(leftRight, node);
273
- left.right = right;
274
- setParent(right, left);
275
-
276
- left.refit();
277
- //update leaf count
278
- node.left.updateLeafNodeCount();
279
- break;
280
- case 3:
281
- node.left = rightLeft;
282
- setParent(rightLeft, node);
283
- right.left = left;
284
- setParent(left, right);
285
-
286
- right.refit();
287
- //update leaf count
288
- node.right.updateLeafNodeCount();
289
- break;
290
- case 4:
291
- node.left = rightRight;
292
- setParent(rightRight, node);
293
- right.right = left;
294
- setParent(left, right);
295
-
296
- right.refit();
297
- //update leaf count
298
- node.right.updateLeafNodeCount();
299
- break;
300
- case 5:
301
- left.right = rightLeft;
302
- setParent(rightLeft, left);
303
- right.left = leftRight;
304
- setParent(leftRight, right);
305
-
306
- left.refit();
307
- right.refit();
308
-
309
- //update leaf count
310
- node.left.updateLeafNodeCount();
311
- node.right.updateLeafNodeCount();
312
- break;
313
- case 6:
314
- left.right = rightRight;
315
- setParent(rightRight, left);
316
- right.right = leftRight;
317
- setParent(leftRight, right);
318
-
319
- left.refit();
320
- right.refit();
321
- //update leaf count
322
- node.left.updateLeafNodeCount();
323
- node.right.updateLeafNodeCount();
324
- break;
325
- }
326
-
327
- return bestRotation;
328
- }
329
-
330
75
  /**
331
76
  *
332
77
  * @param {BinaryNode} root
333
78
  * @param {int} maxIterations
334
79
  */
335
- function optimize(root, maxIterations = 1000) {
80
+ export function optimize(root, maxIterations = 1000) {
336
81
  const traverser = new StacklessTraverser();
337
82
 
338
83
  traverser.init(root);
@@ -376,8 +121,3 @@ function optimize(root, maxIterations = 1000) {
376
121
 
377
122
  return changeCounter;
378
123
  }
379
-
380
- export {
381
- optimize,
382
- tryRotateSingleNode
383
- };