@woosh/meep-engine 2.48.23 → 2.49.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 (142) hide show
  1. package/editor/tools/GridPaintTool.js +1 -1
  2. package/editor/tools/paint/TerrainPaintTool.js +1 -1
  3. package/editor/view/GridPickCoordinateView.js +1 -1
  4. package/package.json +1 -1
  5. package/src/core/UUID.js +2 -0
  6. package/src/core/assert.js +4 -1
  7. package/src/core/binary/ctz32.js +1 -1
  8. package/src/core/binary/operations/bitCount.spec.js +19 -0
  9. package/src/core/binary/uint82float.spec.js +7 -0
  10. package/src/core/bvh2/bvh3/EBBVHLeafProxy.js +3 -0
  11. package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.js +5 -4
  12. package/src/core/bvh2/transform/RotationOptimizer.spec.js +161 -155
  13. package/src/core/codegen/LineBuilder.js +12 -3
  14. package/src/core/codegen/LineBuilder.spec.js +7 -0
  15. package/src/core/collection/HashMap.js +486 -237
  16. package/src/core/collection/HashMap.spec.js +110 -1
  17. package/src/core/collection/array/{typedArrayToDataType.js → typed/typedArrayToDataType.js} +1 -1
  18. package/src/core/collection/array/weightedRandomFromArray.spec.js +20 -0
  19. package/src/core/debug/matchers/AnyOf.js +1 -2
  20. package/src/core/geom/2d/aabb/AABB2.spec.js +1 -1
  21. package/src/core/geom/2d/aabb/aabb2_compute_center_from_multiple.js +19 -0
  22. package/src/core/geom/2d/quad-tree/qt_collect_by_circle.js +3 -3
  23. package/src/core/geom/2d/quad-tree/qt_query_data_nearest_to_point.js +7 -9
  24. package/src/core/geom/3d/aabb/aabb3_compute_plane_side.js +17 -15
  25. package/src/core/geom/3d/aabb/aabb3_compute_plane_side.spec.js +25 -0
  26. package/src/core/geom/3d/aabb/aabb3_detailed_volume_intersection.js +1 -1
  27. package/src/core/geom/3d/aabb/aabb3_from_v3_array.js +3 -0
  28. package/src/core/geom/3d/aabb/aabb3_from_v3_array.spec.js +32 -0
  29. package/src/core/geom/3d/aabb/aabb3_intersects_aabb3.spec.js +115 -0
  30. package/src/core/geom/3d/aabb/aabb3_raycast.js +6 -1
  31. package/src/core/geom/3d/aabb/serializeAABB3Encoded_v0.js +6 -6
  32. package/src/core/geom/3d/{CircleMath.js → compute_circle_bounding_box.js} +1 -1
  33. package/src/core/geom/3d/decompose_matrix_4_array.js +18 -19
  34. package/src/core/geom/3d/frustum/frustum3_computeNearestPointToPoint.js +1 -1
  35. package/src/{engine/graphics/ecs/mesh-v2 → core/geom/3d/matrix}/allocate_transform_m4.js +1 -1
  36. package/src/core/geom/3d/normal/hemioct/decode_hemioct_to_unit.js +26 -0
  37. package/src/core/geom/3d/normal/hemioct/encode_unit3_hemioct.js +0 -26
  38. package/src/core/geom/3d/normal/hemioct/unit_hemioct.spec.js +2 -1
  39. package/src/core/geom/3d/plane/computePlaneLineIntersection.js +51 -0
  40. package/src/core/geom/3d/plane/computePlanePlaneIntersection.js +77 -0
  41. package/src/core/geom/3d/plane/computePlaneRayIntersection.js +55 -0
  42. package/src/core/geom/3d/plane/plane3_computeLineSegmentIntersection.js +50 -0
  43. package/src/core/geom/3d/plane/planeRayIntersection.js +14 -0
  44. package/src/core/geom/3d/{tetrahedra/in_sphere_fast.js → sphere/in_sphere3d_fast.js} +1 -1
  45. package/src/core/geom/3d/{tetrahedra/in_sphere_robust.js → sphere/in_sphere3d_robust.js} +1 -1
  46. package/src/core/geom/3d/sphere/sphere_array_intersects_point.js +2 -2
  47. package/src/core/geom/3d/sphere/{sphereIntersectsPoint.js → sphere_intersects_point.js} +7 -4
  48. package/src/core/geom/3d/sphere/sphere_intersects_point.spec.js +134 -0
  49. package/src/core/geom/3d/sphere/sphere_intersects_ray.spec.js +49 -0
  50. package/src/core/geom/3d/sphere/sphere_radius_sqr_from_v3_array_transformed.js +11 -7
  51. package/src/core/geom/3d/tetrahedra/delaunay/{debug_validate_mesh.js → debug/debug_validate_mesh.js} +1 -1
  52. package/src/core/geom/3d/tetrahedra/delaunay/{push_boundary_with_validation.js → debug/push_boundary_with_validation.js} +1 -1
  53. package/src/core/geom/3d/tetrahedra/delaunay/{validate_cavity_boundary.js → debug/validate_cavity_boundary.js} +2 -2
  54. package/src/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_compute_cavity.js +2 -2
  55. package/src/core/geom/3d/triangle/computeTriangleRayIntersection.js +0 -164
  56. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentric.js +87 -0
  57. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentricEdge.js +81 -0
  58. package/src/core/geom/{rayTriangleIntersection.js → 3d/triangle/rayTriangleIntersection.js} +2 -2
  59. package/src/core/geom/ConicRay.js +160 -152
  60. package/src/core/geom/Matrix4.js +2 -0
  61. package/src/core/geom/Quaternion.js +19 -1
  62. package/src/core/geom/packing/max-rect/MaxRectangles.js +4 -214
  63. package/src/core/geom/packing/max-rect/cost/costByBestShortSide.js +11 -0
  64. package/src/core/geom/packing/max-rect/cost/costByRemainingArea.js +14 -0
  65. package/src/core/geom/packing/max-rect/cutArea.js +79 -0
  66. package/src/core/geom/packing/max-rect/findBestContainer.js +58 -0
  67. package/src/core/geom/packing/max-rect/packOneBox.js +49 -0
  68. package/src/core/geom/v3_dot.js +1 -1
  69. package/src/core/graph/layout/CircleLayout.js +1 -1
  70. package/src/core/graph/layout/{BoxLayouter.js → box/BoxLayouter.js} +6 -50
  71. package/src/core/graph/layout/box/applyCentralGravityAABB2.js +29 -0
  72. package/src/core/json/resolvePath.spec.js +14 -0
  73. package/src/core/land/reactive/{compiler/ReactiveCompiler.spec.js → compileReactiveExpression.spec.js} +17 -17
  74. package/src/core/math/random/MersenneTwister.spec.js +19 -0
  75. package/src/core/math/random/randomGaussian.spec.js +9 -0
  76. package/src/core/math/statistics/computeStatisticalMean.js +2 -2
  77. package/src/core/model/reactive/model/arithmetic/ReactiveAdd.js +1 -1
  78. package/src/core/model/reactive/model/arithmetic/ReactiveDivide.js +3 -1
  79. package/src/core/model/reactive/model/arithmetic/ReactiveMultiply.js +1 -1
  80. package/src/core/model/reactive/model/arithmetic/ReactiveNegate.js +3 -1
  81. package/src/core/model/reactive/model/arithmetic/ReactiveSubtract.js +1 -1
  82. package/src/core/model/reactive/model/comparative/ReactiveEquals.js +1 -1
  83. package/src/core/model/reactive/model/comparative/ReactiveGreaterThan.js +3 -1
  84. package/src/core/model/reactive/model/comparative/ReactiveGreaterThanOrEqual.js +3 -1
  85. package/src/core/model/reactive/model/comparative/ReactiveLessThan.js +3 -1
  86. package/src/core/model/reactive/model/comparative/ReactiveLessThanOrEqual.js +3 -1
  87. package/src/core/model/reactive/model/comparative/ReactiveNotEquals.js +1 -1
  88. package/src/core/model/reactive/model/logic/ReactiveAnd.js +1 -1
  89. package/src/core/model/reactive/model/logic/ReactiveNot.js +3 -1
  90. package/src/core/model/reactive/model/logic/ReactiveOr.js +1 -1
  91. package/src/core/primitives/numbers/computeHashFloat.spec.js +7 -0
  92. package/src/core/process/task/util/iteratorTask.js +3 -1
  93. package/src/engine/animation/curve/AnimationCurve.js +34 -5
  94. package/src/engine/animation/curve/AnimationCurve.spec.js +100 -0
  95. package/src/engine/asset/AssetTransformer.js +1 -0
  96. package/src/engine/computeStridedIntegerArrayHash.js +4 -2
  97. package/src/engine/ecs/components/Renderable.d.ts +1 -1
  98. package/src/{ecs → engine/ecs}/grid/pick.js +4 -4
  99. package/src/engine/ecs/parent/entity_node_compute_bounding_box.js +1 -1
  100. package/src/engine/ecs/storage/binary/collection/BinaryCollectionSerializer.js +1 -18
  101. package/src/engine/ecs/systems/MotionSystem.js +7 -1
  102. package/src/engine/ecs/systems/SynchronizePositionSystem.js +8 -2
  103. package/src/engine/ecs/transform/Transform.js +1 -1
  104. package/src/engine/graphics/camera/makeScreenScissorFrustum.js +3 -3
  105. package/src/engine/graphics/camera/testClippingPlaneComputation.js +13 -13
  106. package/src/engine/graphics/ecs/camera/Camera.js +1 -1
  107. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.js +1 -1
  108. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.js +9 -0
  109. package/src/engine/graphics/geometry/MikkT/MikkTSpace.js +1 -1
  110. package/src/engine/graphics/geometry/MikkT/STSpace.js +1 -1
  111. package/src/engine/graphics/geometry/bvh/buffered/BVHGeometryRaycaster.js +1 -1
  112. package/src/engine/graphics/material/optimization/MaterialOptimizationContext.js +1 -1
  113. package/src/engine/graphics/particles/particular/engine/MovingBoundingBox.js +1 -1
  114. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +1 -0
  115. package/src/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +1 -1
  116. package/src/engine/graphics/postprocess/threejs/postprocessing/TexturePass.js +2 -2
  117. package/src/engine/graphics/sh3/path_tracer/GeometryBVHBatched.js +2 -2
  118. package/src/engine/graphics/texture/sampler/Sampler2D.js +1 -1
  119. package/src/engine/graphics/texture/sampler/sampler2d_compute_texel_value_conversion_scale_to_uint8.js +1 -1
  120. package/src/engine/intelligence/behavior/Behavior.spec.js +15 -0
  121. package/src/engine/intelligence/mcts/MoveEdge.js +1 -1
  122. package/src/engine/reference/v1/ReferenceManager.js +3 -0
  123. package/src/engine/reference/v2/Reference.js +33 -37
  124. package/src/engine/sound/sopra/README.md +6 -0
  125. package/src/generation/automata/CaveGeneratorCellularAutomata.js +10 -7
  126. package/src/generation/automata/CaveGeneratorCellularAutomata.spec.js +12 -0
  127. package/src/generation/automata/CellularAutomata.js +5 -4
  128. package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.js +25 -9
  129. package/src/view/minimap/dom/MinimapCameraView.js +1 -1
  130. package/src/core/geom/Plane.js +0 -250
  131. package/src/core/land/reactive/ReactiveLexer.js +0 -158
  132. package/src/core/land/reactive/ReactiveLexer.ts +0 -181
  133. package/src/core/land/reactive/ReactiveListener.ts +0 -323
  134. package/src/core/land/reactive/ReactiveParser.js +0 -1573
  135. package/src/core/land/reactive/ReactiveParser.ts +0 -1776
  136. package/src/core/land/reactive/ReactiveVisitor.js +0 -1
  137. package/src/core/land/reactive/ReactiveVisitor.ts +0 -218
  138. package/src/core/land/reactive/compiler/ReactiveCompiler.js +0 -350
  139. package/src/core/land/reactive/compiler/ReactiveNearlyCompiler.js +0 -166
  140. package/src/core/land/reactive/compiler/ReactiveParser.js +0 -34
  141. package/src/core/land/reactive/nearley/ReactiveNearley.js +0 -187
  142. /package/src/{engine/graphics/ecs/mesh-v2 → core/geom/3d/vector}/allocate_v3.js +0 -0
@@ -12,7 +12,7 @@ import TopDownCameraControllerSystem
12
12
  from "../../src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js";
13
13
  import { hex2rgb } from "../../src/core/color/hex2rgb.js";
14
14
  import { obtainTerrain } from "../../src/engine/ecs/terrain/util/obtainTerrain.js";
15
- import { pick } from "../../src/ecs/grid/pick.js";
15
+ import { pick } from "../../src/engine/ecs/grid/pick.js";
16
16
 
17
17
  class GridPaintTool extends Tool {
18
18
  constructor() {
@@ -8,7 +8,7 @@ import ObservedString from "../../../src/core/model/ObservedString.js";
8
8
  import { GameAssetType } from "../../../src/engine/asset/GameAssetType.js";
9
9
  import Vector1 from "../../../src/core/geom/Vector1.js";
10
10
  import { obtainTerrain } from "../../../src/engine/ecs/terrain/util/obtainTerrain.js";
11
- import { pick } from "../../../src/ecs/grid/pick.js";
11
+ import { pick } from "../../../src/engine/ecs/grid/pick.js";
12
12
 
13
13
  export class TerrainPaintTool extends Tool {
14
14
  constructor() {
@@ -2,7 +2,7 @@ import View from "../../src/view/View.js";
2
2
  import domify from "../../src/view/DOM.js";
3
3
  import { PointerDevice } from "../../src/engine/input/devices/PointerDevice.js";
4
4
  import { obtainTerrain } from "../../src/engine/ecs/terrain/util/obtainTerrain.js";
5
- import { pick } from "../../src/ecs/grid/pick.js";
5
+ import { pick } from "../../src/engine/ecs/grid/pick.js";
6
6
 
7
7
  class GridPickCoordinateView extends View {
8
8
  /**
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "description": "Fully featured ECS game engine written in JavaScript",
6
6
  "type": "module",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.48.23",
8
+ "version": "2.49.0",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
package/src/core/UUID.js CHANGED
@@ -10,6 +10,8 @@ function replacer(c) {
10
10
  const rx = /[xy]/g;
11
11
 
12
12
  /**
13
+ * Generates a variant 4 fully random UUID in string format
14
+ * NOTE: Prefer to use UUID component class instead as that implementation is more robust and has better entropy when it comes to randomness
13
15
  * @returns {string}
14
16
  */
15
17
  function uuid() {
@@ -3,7 +3,10 @@ import { isTypedArray } from "./collection/array/typed/isTypedArray.js";
3
3
  import { InMemoryDescriptor } from "./debug/InMemoryDescriptor.js";
4
4
 
5
5
  function equal(a, b, m) {
6
- assert(a === b, m) // eslint-disable-line eqeqeq
6
+ if (a !== b) {
7
+ const message = m !== undefined ? m : `${a} !== ${b}`;
8
+ throw new Error(message);
9
+ }
7
10
  }
8
11
 
9
12
  function notEqual(a, b, m) {
@@ -4,7 +4,7 @@
4
4
  * @param {number} x expected to be an integer
5
5
  * @return {number}
6
6
  */
7
- function ctz32(x) {
7
+ export function ctz32(x) {
8
8
  let n = 0;
9
9
 
10
10
  if ((x & 0xffff) === 0) {
@@ -0,0 +1,19 @@
1
+ import { bitCount } from "./bitCount.js";
2
+
3
+ test("no set bits", () => {
4
+ expect(bitCount(0)).toBe(0)
5
+ });
6
+
7
+ test("1 set bit", () => {
8
+
9
+ for (let i = 0; i < 32; i++) {
10
+ expect(bitCount(1 << i)).toBe(1)
11
+ }
12
+ });
13
+
14
+ test("2 set bit together", () => {
15
+
16
+ for (let i = 0; i < 31; i++) {
17
+ expect(bitCount(0b11 << i)).toBe(2)
18
+ }
19
+ });
@@ -0,0 +1,7 @@
1
+ import { uint82float } from "./uint82float.js";
2
+
3
+ test("correctness", () => {
4
+ expect(uint82float(0)).toBe(0);
5
+ expect(uint82float(1)).toBeCloseTo(1 / 255);
6
+ expect(uint82float(255)).toBe(1);
7
+ });
@@ -32,6 +32,7 @@ export class EBBVHLeafProxy {
32
32
  * @param {number} data Must be a uint32
33
33
  */
34
34
  link(tree, data) {
35
+ assert.equal(this.is_linked, false, 'already linked');
35
36
  assert.defined(tree, 'tree');
36
37
  assert.isNonNegativeInteger(data, 'data');
37
38
 
@@ -47,6 +48,8 @@ export class EBBVHLeafProxy {
47
48
  }
48
49
 
49
50
  unlink() {
51
+ assert.equal(this.is_linked, true, 'not linked');
52
+
50
53
  this.#tree.remove_leaf(this.#node_id);
51
54
  this.#tree.release_node(this.#node_id);
52
55
 
@@ -27,7 +27,7 @@ export function compute_tight_near_far_clipping_planes(result, result_offset, co
27
27
  const root = bvh.root;
28
28
 
29
29
  if (root === NULL_NODE) {
30
- return 0;
30
+ return false;
31
31
  }
32
32
 
33
33
  /**
@@ -67,8 +67,8 @@ export function compute_tight_near_far_clipping_planes(result, result_offset, co
67
67
  const _y1 = scratch_aabb[4];
68
68
  const _z1 = scratch_aabb[5];
69
69
 
70
- for (let i = 0; i < 6; i++) {
71
- const plane_address = i * 4;
70
+ for (let plane_index = 0; plane_index < 6; plane_index++) {
71
+ const plane_address = plane_index * 4;
72
72
 
73
73
  //read out plane
74
74
  const plane_normal_x = frustum[plane_address];
@@ -112,7 +112,7 @@ export function compute_tight_near_far_clipping_planes(result, result_offset, co
112
112
  continue node_loop;
113
113
  }
114
114
 
115
- if ((constrained_planes_mask & (1 << i)) !== 0) {
115
+ if ((constrained_planes_mask & (1 << plane_index)) !== 0) {
116
116
  // plane is constrained, we're done here
117
117
  continue;
118
118
  }
@@ -152,4 +152,5 @@ export function compute_tight_near_far_clipping_planes(result, result_offset, co
152
152
  }
153
153
  }
154
154
 
155
+ return true;
155
156
  }
@@ -100,198 +100,204 @@ function pair(left, right) {
100
100
  return node;
101
101
  }
102
102
 
103
- test("empty node", () => {
104
- const node = new BinaryNode();
105
- node.setInfiniteBounds();
106
103
 
107
- optimize(node, 100);
104
+ describe.skip("suite", () => {
108
105
 
109
- expect(node.left).toBeNull();
110
- expect(node.right).toBeNull();
111
- });
112
106
 
113
- test("does nothing on optimal 2 child tree", () => {
114
- const a = leaf(0, 1, "hello");
115
- const b = leaf(2, 3, "goodbye");
107
+ test("empty node", () => {
108
+ const node = new BinaryNode();
109
+ node.setInfiniteBounds();
116
110
 
117
- const root = pair(a, b);
111
+ optimize(node, 100);
118
112
 
119
- const optimized = optimize(root, 100);
120
- expect(optimized).toBe(0);
113
+ expect(node.left).toBeNull();
114
+ expect(node.right).toBeNull();
115
+ });
121
116
 
122
- //positions preserved
123
- expect(root.left.object).toEqual(a.object);
124
- expect(root.right.object).toEqual(b.object);
117
+ test("does nothing on optimal 2 child tree", () => {
118
+ const a = leaf(0, 1, "hello");
119
+ const b = leaf(2, 3, "goodbye");
125
120
 
126
- //parent node is root
127
- expect(root.left.parentNode).toEqual(root);
128
- expect(root.right.parentNode).toEqual(root);
121
+ const root = pair(a, b);
129
122
 
130
- expect(root).toBeValid();
131
- });
123
+ const optimized = optimize(root, 100);
124
+ expect(optimized).toBe(0);
132
125
 
133
- test("does nothing on optimal depth 2 tree", () => {
134
- const a = leaf(-2, -1, "a");
135
- const b = leaf(-1, 0, "b");
136
- const c = leaf(0, 1, "c");
137
- const d = leaf(1, 2, "d");
126
+ //positions preserved
127
+ expect(root.left.object).toEqual(a.object);
128
+ expect(root.right.object).toEqual(b.object);
138
129
 
139
- const n0 = pair(a, b);
140
- const n1 = pair(c, d);
130
+ //parent node is root
131
+ expect(root.left.parentNode).toEqual(root);
132
+ expect(root.right.parentNode).toEqual(root);
141
133
 
142
- const root = pair(n0, n1);
134
+ expect(root).toBeValid();
135
+ });
143
136
 
144
- const optimized = optimize(root, 100);
145
- expect(optimized).toBe(0);
137
+ test("does nothing on optimal depth 2 tree", () => {
138
+ const a = leaf(-2, -1, "a");
139
+ const b = leaf(-1, 0, "b");
140
+ const c = leaf(0, 1, "c");
141
+ const d = leaf(1, 2, "d");
146
142
 
147
- expect(root.parentNode).toBeNull();
143
+ const n0 = pair(a, b);
144
+ const n1 = pair(c, d);
148
145
 
149
- expect(root.left).toBe(n0);
150
- expect(root.right).toBe(n1);
146
+ const root = pair(n0, n1);
151
147
 
152
- expect(n0.left).toBe(a);
153
- expect(n0.right).toBe(b);
148
+ const optimized = optimize(root, 100);
149
+ expect(optimized).toBe(0);
154
150
 
155
- expect(n1.left).toBe(c);
156
- expect(n1.right).toBe(d);
151
+ expect(root.parentNode).toBeNull();
157
152
 
158
- expect(root).toBeValid();
159
- });
153
+ expect(root.left).toBe(n0);
154
+ expect(root.right).toBe(n1);
160
155
 
161
- test("produces a valid tree from left-leaning tree with 4 leaves", () => {
162
- const a = leaf(-2, -1, "a");
163
- const b = leaf(-1, 0, "b");
164
- const c = leaf(0, 1, "c");
165
- const d = leaf(1, 2, "d");
156
+ expect(n0.left).toBe(a);
157
+ expect(n0.right).toBe(b);
166
158
 
167
- const root = pair(
168
- pair(
169
- pair(c, d),
170
- b
171
- ),
172
- a
173
- );
159
+ expect(n1.left).toBe(c);
160
+ expect(n1.right).toBe(d);
174
161
 
175
- optimize(root, 100);
162
+ expect(root).toBeValid();
163
+ });
176
164
 
177
- expect(root).toBeValid();
165
+ test("produces a valid tree from left-leaning tree with 4 leaves", () => {
166
+ const a = leaf(-2, -1, "a");
167
+ const b = leaf(-1, 0, "b");
168
+ const c = leaf(0, 1, "c");
169
+ const d = leaf(1, 2, "d");
178
170
 
179
- expect(root).toContainNode(a);
180
- expect(root).toContainNode(b);
181
- expect(root).toContainNode(c);
182
- expect(root).toContainNode(d);
183
- });
171
+ const root = pair(
172
+ pair(
173
+ pair(c, d),
174
+ b
175
+ ),
176
+ a
177
+ );
184
178
 
185
- test("produces a valid tree from right-leaning tree with 4 leaves", () => {
186
- const a = leaf(-2, -1, "a");
187
- const b = leaf(-1, 0, "b");
188
- const c = leaf(0, 1, "c");
189
- const d = leaf(1, 2, "d");
179
+ optimize(root, 100);
190
180
 
191
- const root = pair(
192
- a,
193
- pair(
194
- b,
195
- pair(c, d)
196
- )
197
- );
181
+ expect(root).toBeValid();
198
182
 
199
- optimize(root, 100);
183
+ expect(root).toContainNode(a);
184
+ expect(root).toContainNode(b);
185
+ expect(root).toContainNode(c);
186
+ expect(root).toContainNode(d);
187
+ });
200
188
 
201
- expect(root).toBeValid();
189
+ test("produces a valid tree from right-leaning tree with 4 leaves", () => {
190
+ const a = leaf(-2, -1, "a");
191
+ const b = leaf(-1, 0, "b");
192
+ const c = leaf(0, 1, "c");
193
+ const d = leaf(1, 2, "d");
202
194
 
203
- expect(root).toContainNode(a);
204
- expect(root).toContainNode(b);
205
- expect(root).toContainNode(c);
206
- expect(root).toContainNode(d);
207
- });
195
+ const root = pair(
196
+ a,
197
+ pair(
198
+ b,
199
+ pair(c, d)
200
+ )
201
+ );
208
202
 
209
- test("100 node random tree optimization does not degrade quality", () => {
210
- const random = seededRandom(42);
203
+ optimize(root, 100);
211
204
 
212
- const nodes = [];
205
+ expect(root).toBeValid();
213
206
 
214
- for (let i = 0; i < 100; i++) {
215
- const x0 = random() * 100;
216
- const y0 = random() * 100;
217
- const z0 = random() * 100;
207
+ expect(root).toContainNode(a);
208
+ expect(root).toContainNode(b);
209
+ expect(root).toContainNode(c);
210
+ expect(root).toContainNode(d);
211
+ });
218
212
 
219
- const x1 = x0 + random() * 5;
220
- const y1 = y0 + random() * 5;
221
- const z1 = z0 + random() * 5;
213
+ test("100 node random tree optimization does not degrade quality", () => {
214
+ const random = seededRandom(42);
222
215
 
223
- nodes.push(new LeafNode(i, x0, y0, z0, x1, y1, z1));
224
- }
216
+ const nodes = [];
225
217
 
226
- while (nodes.length >= 2) {
227
- const left = nodes.pop();
228
- const right = nodes.pop();
229
- nodes.unshift(pair(left, right));
230
- }
218
+ for (let i = 0; i < 100; i++) {
219
+ const x0 = random() * 100;
220
+ const y0 = random() * 100;
221
+ const z0 = random() * 100;
222
+
223
+ const x1 = x0 + random() * 5;
224
+ const y1 = y0 + random() * 5;
225
+ const z1 = z0 + random() * 5;
231
226
 
232
- const root = nodes[0];
227
+ nodes.push(new LeafNode(i, x0, y0, z0, x1, y1, z1));
228
+ }
233
229
 
234
- const oldSAH = root.computeSAH();
230
+ while (nodes.length >= 2) {
231
+ const left = nodes.pop();
232
+ const right = nodes.pop();
233
+ nodes.unshift(pair(left, right));
234
+ }
235
235
 
236
- optimize(root, 100);
236
+ const root = nodes[0];
237
237
 
238
- expect(root).toBeValid();
238
+ const oldSAH = root.computeSAH();
239
239
 
240
- const newSAH = root.computeSAH();
240
+ optimize(root, 100);
241
241
 
242
- //at least not degraded
243
- expect(newSAH).toBeLessThanOrEqual(oldSAH);
244
- });
242
+ expect(root).toBeValid();
245
243
 
246
- test("case 0: 4 node tree optimization does not degrade quality", () => {
247
- const ll = new LeafNode("ll",
248
- 76.06244471671744,
249
- 7.73902752171125,
250
- 1.925105413576489,
251
- 94.49883157197291,
252
- 50.63123012084361,
253
- 76.75841101302467
254
- );
255
-
256
- const lr = new LeafNode("lr",
257
- 76.11310176957886,
258
- 58.65097077867176,
259
- 11.346076624795387,
260
- 97.55653706044541,
261
- 89.91247777413719,
262
- 90.73181902923352
263
- );
264
-
265
- const rl = new LeafNode("rl",
266
- 32.4771196630536,
267
- 0.9366270797727339,
268
- 1.378434756588831,
269
- 66.71670340545461,
270
- 99.32784918828929,
271
- 97.52435446605432
272
- );
273
-
274
- const rr = new LeafNode("rr",
275
- 1.124263022938976,
276
- 0.13232239543867763,
277
- 2.702786005283997,
278
- 31.51776058888572,
279
- 94.87720282424561,
280
- 101.03932220629758
281
- );
282
-
283
- const root = pair(pair(ll, lr), pair(rl, rr));
284
-
285
- expect(root).toBeValid();
286
-
287
- const oldSAH = root.computeSAH();
288
-
289
- optimize(root, 1000);
290
-
291
- expect(root).toBeValid();
292
-
293
- const newSAH = root.computeSAH();
294
-
295
- //at least not degraded
296
- expect(newSAH).toBeLessThanOrEqual(oldSAH);
297
- });
244
+ const newSAH = root.computeSAH();
245
+
246
+ //at least not degraded
247
+ expect(newSAH).toBeLessThanOrEqual(oldSAH);
248
+ });
249
+
250
+ test("case 0: 4 node tree optimization does not degrade quality", () => {
251
+ const ll = new LeafNode("ll",
252
+ 76.06244471671744,
253
+ 7.73902752171125,
254
+ 1.925105413576489,
255
+ 94.49883157197291,
256
+ 50.63123012084361,
257
+ 76.75841101302467
258
+ );
259
+
260
+ const lr = new LeafNode("lr",
261
+ 76.11310176957886,
262
+ 58.65097077867176,
263
+ 11.346076624795387,
264
+ 97.55653706044541,
265
+ 89.91247777413719,
266
+ 90.73181902923352
267
+ );
268
+
269
+ const rl = new LeafNode("rl",
270
+ 32.4771196630536,
271
+ 0.9366270797727339,
272
+ 1.378434756588831,
273
+ 66.71670340545461,
274
+ 99.32784918828929,
275
+ 97.52435446605432
276
+ );
277
+
278
+ const rr = new LeafNode("rr",
279
+ 1.124263022938976,
280
+ 0.13232239543867763,
281
+ 2.702786005283997,
282
+ 31.51776058888572,
283
+ 94.87720282424561,
284
+ 101.03932220629758
285
+ );
286
+
287
+ const root = pair(pair(ll, lr), pair(rl, rr));
288
+
289
+ expect(root).toBeValid();
290
+
291
+ const oldSAH = root.computeSAH();
292
+
293
+ optimize(root, 1000);
294
+
295
+ expect(root).toBeValid();
296
+
297
+ const newSAH = root.computeSAH();
298
+
299
+ //at least not degraded
300
+ expect(newSAH).toBeLessThanOrEqual(oldSAH);
301
+ });
302
+
303
+ })
@@ -16,6 +16,8 @@ class Line {
16
16
  }
17
17
  }
18
18
 
19
+ const DEFAULT_INDENT_SPACES = 4;
20
+
19
21
  /**
20
22
  * Useful for creating formatted snippets of code
21
23
  */
@@ -35,7 +37,7 @@ class LineBuilder {
35
37
  *
36
38
  * @type {number}
37
39
  */
38
- indentSpaces = 4;
40
+ indentSpaces = DEFAULT_INDENT_SPACES;
39
41
 
40
42
  /**
41
43
  *
@@ -82,8 +84,11 @@ class LineBuilder {
82
84
  * @returns {LineBuilder}
83
85
  */
84
86
  add(line_text) {
87
+
85
88
  const line = new Line(line_text, this.indentation);
89
+
86
90
  this.lines.push(line);
91
+
87
92
  return this;
88
93
  }
89
94
 
@@ -110,7 +115,7 @@ class LineBuilder {
110
115
  clear() {
111
116
  this.lines = [];
112
117
  this.indentation = 0;
113
- this.indentSpaces = 4;
118
+ this.indentSpaces = DEFAULT_INDENT_SPACES;
114
119
  }
115
120
 
116
121
  /**
@@ -119,14 +124,16 @@ class LineBuilder {
119
124
  */
120
125
  build() {
121
126
  const result = [];
122
- let i, j, l;
123
127
 
128
+ let i, j, l;
124
129
 
125
130
  const lines = this.lines;
131
+
126
132
  for (i = 0, l = lines.length; i < l; i++) {
127
133
  const line = lines[i];
128
134
 
129
135
  let indentString = '';
136
+
130
137
  for (j = 0; j < line.indentation * this.indentSpaces; j++) {
131
138
  indentString += ' ';
132
139
  }
@@ -149,6 +156,8 @@ class LineBuilder {
149
156
 
150
157
  const n = lines.length;
151
158
 
159
+ // TODO detect indent
160
+
152
161
  for (let i = 0; i < n; i++) {
153
162
 
154
163
  r.add(lines[i]);
@@ -0,0 +1,7 @@
1
+ import LineBuilder from "./LineBuilder.js";
2
+
3
+ test("Empty builder should produce empty string", () => {
4
+ const b = new LineBuilder();
5
+
6
+ expect(b.build()).toEqual("");
7
+ });