@woosh/meep-engine 2.48.23 → 2.49.1

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 (147) 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/binary/IndexedBinaryBVH.spec.js +7 -0
  11. package/src/core/bvh2/bvh3/EBBVHLeafProxy.js +3 -0
  12. package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.js +5 -4
  13. package/src/core/bvh2/transform/RotationOptimizer.spec.js +161 -155
  14. package/src/core/codegen/LineBuilder.js +12 -3
  15. package/src/core/codegen/LineBuilder.spec.js +7 -0
  16. package/src/core/collection/CuckooFilter.js +12 -12
  17. package/src/core/collection/HashMap.js +486 -237
  18. package/src/core/collection/HashMap.spec.js +110 -1
  19. package/src/core/collection/array/{typedArrayToDataType.js → typed/typedArrayToDataType.js} +1 -1
  20. package/src/core/collection/array/weightedRandomFromArray.spec.js +20 -0
  21. package/src/core/debug/matchers/AnyOf.js +1 -2
  22. package/src/core/geom/2d/aabb/AABB2.spec.js +1 -1
  23. package/src/core/geom/2d/aabb/aabb2_compute_center_from_multiple.js +19 -0
  24. package/src/core/geom/2d/quad-tree/qt_collect_by_circle.js +3 -3
  25. package/src/core/geom/2d/quad-tree/qt_query_data_nearest_to_point.js +7 -9
  26. package/src/core/geom/3d/aabb/aabb3_compute_plane_side.js +17 -15
  27. package/src/core/geom/3d/aabb/aabb3_compute_plane_side.spec.js +25 -0
  28. package/src/core/geom/3d/aabb/aabb3_detailed_volume_intersection.js +1 -1
  29. package/src/core/geom/3d/aabb/aabb3_from_v3_array.js +3 -0
  30. package/src/core/geom/3d/aabb/aabb3_from_v3_array.spec.js +32 -0
  31. package/src/core/geom/3d/aabb/aabb3_intersects_aabb3.spec.js +115 -0
  32. package/src/core/geom/3d/aabb/aabb3_raycast.js +6 -1
  33. package/src/core/geom/3d/aabb/serializeAABB3Encoded_v0.js +6 -6
  34. package/src/core/geom/3d/{CircleMath.js → compute_circle_bounding_box.js} +1 -1
  35. package/src/core/geom/3d/decompose_matrix_4_array.js +18 -19
  36. package/src/core/geom/3d/frustum/frustum3_computeNearestPointToPoint.js +1 -1
  37. package/src/{engine/graphics/ecs/mesh-v2 → core/geom/3d/matrix}/allocate_transform_m4.js +1 -1
  38. package/src/core/geom/3d/normal/hemioct/decode_hemioct_to_unit.js +26 -0
  39. package/src/core/geom/3d/normal/hemioct/encode_unit3_hemioct.js +0 -26
  40. package/src/core/geom/3d/normal/hemioct/unit_hemioct.spec.js +2 -1
  41. package/src/core/geom/3d/plane/computePlaneLineIntersection.js +51 -0
  42. package/src/core/geom/3d/plane/computePlanePlaneIntersection.js +77 -0
  43. package/src/core/geom/3d/plane/computePlaneRayIntersection.js +55 -0
  44. package/src/core/geom/3d/plane/plane3_computeLineSegmentIntersection.js +50 -0
  45. package/src/core/geom/3d/plane/planeRayIntersection.js +14 -0
  46. package/src/core/geom/3d/{tetrahedra/in_sphere_fast.js → sphere/in_sphere3d_fast.js} +1 -1
  47. package/src/core/geom/3d/{tetrahedra/in_sphere_robust.js → sphere/in_sphere3d_robust.js} +1 -1
  48. package/src/core/geom/3d/sphere/sphere_array_intersects_point.js +2 -2
  49. package/src/core/geom/3d/sphere/{sphereIntersectsPoint.js → sphere_intersects_point.js} +7 -4
  50. package/src/core/geom/3d/sphere/sphere_intersects_point.spec.js +134 -0
  51. package/src/core/geom/3d/sphere/sphere_intersects_ray.spec.js +49 -0
  52. package/src/core/geom/3d/sphere/sphere_radius_sqr_from_v3_array_transformed.js +11 -7
  53. package/src/core/geom/3d/tetrahedra/delaunay/{debug_validate_mesh.js → debug/debug_validate_mesh.js} +1 -1
  54. package/src/core/geom/3d/tetrahedra/delaunay/{push_boundary_with_validation.js → debug/push_boundary_with_validation.js} +1 -1
  55. package/src/core/geom/3d/tetrahedra/delaunay/{validate_cavity_boundary.js → debug/validate_cavity_boundary.js} +2 -2
  56. package/src/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_compute_cavity.js +2 -2
  57. package/src/core/geom/3d/triangle/computeTriangleRayIntersection.js +0 -164
  58. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentric.js +87 -0
  59. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentricEdge.js +81 -0
  60. package/src/core/geom/{rayTriangleIntersection.js → 3d/triangle/rayTriangleIntersection.js} +2 -2
  61. package/src/core/geom/ConicRay.js +160 -152
  62. package/src/core/geom/Matrix4.js +2 -0
  63. package/src/core/geom/Quaternion.js +19 -1
  64. package/src/core/geom/packing/max-rect/MaxRectangles.js +4 -214
  65. package/src/core/geom/packing/max-rect/cost/costByBestShortSide.js +11 -0
  66. package/src/core/geom/packing/max-rect/cost/costByRemainingArea.js +14 -0
  67. package/src/core/geom/packing/max-rect/cutArea.js +79 -0
  68. package/src/core/geom/packing/max-rect/findBestContainer.js +58 -0
  69. package/src/core/geom/packing/max-rect/packOneBox.js +49 -0
  70. package/src/core/geom/packing/miniball/Miniball.js +12 -12
  71. package/src/core/geom/packing/miniball/Quality.js +2 -2
  72. package/src/core/geom/packing/miniball/Subspan.js +13 -13
  73. package/src/core/geom/v3_dot.js +1 -1
  74. package/src/core/graph/layout/CircleLayout.js +1 -1
  75. package/src/core/graph/layout/{BoxLayouter.js → box/BoxLayouter.js} +6 -50
  76. package/src/core/graph/layout/box/applyCentralGravityAABB2.js +29 -0
  77. package/src/core/json/resolvePath.spec.js +14 -0
  78. package/src/core/land/reactive/{compiler/ReactiveCompiler.spec.js → compileReactiveExpression.spec.js} +17 -17
  79. package/src/core/math/random/MersenneTwister.spec.js +19 -0
  80. package/src/core/math/random/randomGaussian.spec.js +9 -0
  81. package/src/core/math/statistics/computeStatisticalMean.js +2 -2
  82. package/src/core/model/reactive/model/arithmetic/ReactiveAdd.js +1 -1
  83. package/src/core/model/reactive/model/arithmetic/ReactiveDivide.js +3 -1
  84. package/src/core/model/reactive/model/arithmetic/ReactiveMultiply.js +1 -1
  85. package/src/core/model/reactive/model/arithmetic/ReactiveNegate.js +3 -1
  86. package/src/core/model/reactive/model/arithmetic/ReactiveSubtract.js +1 -1
  87. package/src/core/model/reactive/model/comparative/ReactiveEquals.js +1 -1
  88. package/src/core/model/reactive/model/comparative/ReactiveGreaterThan.js +3 -1
  89. package/src/core/model/reactive/model/comparative/ReactiveGreaterThanOrEqual.js +3 -1
  90. package/src/core/model/reactive/model/comparative/ReactiveLessThan.js +3 -1
  91. package/src/core/model/reactive/model/comparative/ReactiveLessThanOrEqual.js +3 -1
  92. package/src/core/model/reactive/model/comparative/ReactiveNotEquals.js +1 -1
  93. package/src/core/model/reactive/model/logic/ReactiveAnd.js +1 -1
  94. package/src/core/model/reactive/model/logic/ReactiveNot.js +3 -1
  95. package/src/core/model/reactive/model/logic/ReactiveOr.js +1 -1
  96. package/src/core/primitives/numbers/computeHashFloat.spec.js +7 -0
  97. package/src/core/process/task/util/iteratorTask.js +3 -1
  98. package/src/engine/animation/curve/AnimationCurve.js +34 -5
  99. package/src/engine/animation/curve/AnimationCurve.spec.js +100 -0
  100. package/src/engine/asset/AssetTransformer.js +1 -0
  101. package/src/engine/computeStridedIntegerArrayHash.js +4 -2
  102. package/src/engine/ecs/components/Renderable.d.ts +1 -1
  103. package/src/{ecs → engine/ecs}/grid/pick.js +4 -4
  104. package/src/engine/ecs/parent/entity_node_compute_bounding_box.js +1 -1
  105. package/src/engine/ecs/storage/binary/collection/BinaryCollectionSerializer.js +1 -18
  106. package/src/engine/ecs/systems/MotionSystem.js +7 -1
  107. package/src/engine/ecs/systems/SynchronizePositionSystem.js +8 -2
  108. package/src/engine/ecs/transform/Transform.js +1 -1
  109. package/src/engine/graphics/camera/makeScreenScissorFrustum.js +3 -3
  110. package/src/engine/graphics/camera/testClippingPlaneComputation.js +13 -13
  111. package/src/engine/graphics/ecs/camera/Camera.js +1 -1
  112. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.js +1 -1
  113. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.js +9 -0
  114. package/src/engine/graphics/geometry/MikkT/MikkTSpace.js +1 -1
  115. package/src/engine/graphics/geometry/MikkT/STSpace.js +1 -1
  116. package/src/engine/graphics/geometry/bvh/buffered/BVHGeometryRaycaster.js +1 -1
  117. package/src/engine/graphics/material/optimization/MaterialOptimizationContext.js +1 -1
  118. package/src/engine/graphics/particles/particular/engine/MovingBoundingBox.js +1 -1
  119. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +1 -0
  120. package/src/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +1 -1
  121. package/src/engine/graphics/postprocess/threejs/postprocessing/TexturePass.js +2 -2
  122. package/src/engine/graphics/sh3/path_tracer/GeometryBVHBatched.js +2 -2
  123. package/src/engine/graphics/texture/sampler/Sampler2D.js +1 -1
  124. package/src/engine/graphics/texture/sampler/sampler2d_compute_texel_value_conversion_scale_to_uint8.js +1 -1
  125. package/src/engine/intelligence/behavior/Behavior.spec.js +15 -0
  126. package/src/engine/intelligence/mcts/MoveEdge.js +1 -1
  127. package/src/engine/reference/v1/ReferenceManager.js +3 -0
  128. package/src/engine/reference/v2/Reference.js +33 -37
  129. package/src/engine/sound/sopra/README.md +6 -0
  130. package/src/generation/automata/CaveGeneratorCellularAutomata.js +10 -7
  131. package/src/generation/automata/CaveGeneratorCellularAutomata.spec.js +12 -0
  132. package/src/generation/automata/CellularAutomata.js +5 -4
  133. package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.js +25 -9
  134. package/src/view/minimap/dom/MinimapCameraView.js +1 -1
  135. package/src/core/geom/Plane.js +0 -250
  136. package/src/core/land/reactive/ReactiveLexer.js +0 -158
  137. package/src/core/land/reactive/ReactiveLexer.ts +0 -181
  138. package/src/core/land/reactive/ReactiveListener.ts +0 -323
  139. package/src/core/land/reactive/ReactiveParser.js +0 -1573
  140. package/src/core/land/reactive/ReactiveParser.ts +0 -1776
  141. package/src/core/land/reactive/ReactiveVisitor.js +0 -1
  142. package/src/core/land/reactive/ReactiveVisitor.ts +0 -218
  143. package/src/core/land/reactive/compiler/ReactiveCompiler.js +0 -350
  144. package/src/core/land/reactive/compiler/ReactiveNearlyCompiler.js +0 -166
  145. package/src/core/land/reactive/compiler/ReactiveParser.js +0 -34
  146. package/src/core/land/reactive/nearley/ReactiveNearley.js +0 -187
  147. /package/src/{engine/graphics/ecs/mesh-v2 → core/geom/3d/vector}/allocate_v3.js +0 -0
@@ -1,4 +1,4 @@
1
- import { HashMap } from "./HashMap.js";
1
+ import { generate_next_linear_congruential_index, HashMap } from "./HashMap.js";
2
2
  import { passThrough, returnOne, strictEquals } from "../function/Functions.js";
3
3
 
4
4
  /**
@@ -16,6 +16,7 @@ function makeSample() {
16
16
  });
17
17
  }
18
18
 
19
+
19
20
  test('put and get same value', () => {
20
21
  const m = makeSample();
21
22
 
@@ -107,6 +108,44 @@ test("retrieval works as intended after hash map grows", () => {
107
108
 
108
109
  });
109
110
 
111
+ test("after deletion element is not found", () => {
112
+ const map = new HashMap({
113
+ keyHashFunction: passThrough,
114
+ keyEqualityFunction: strictEquals,
115
+ });
116
+
117
+ map.set(1, "a");
118
+
119
+ map.delete(1);
120
+
121
+ expect(map.size).toBe(0);
122
+ expect(map.get(1)).toBeUndefined();
123
+ });
124
+
125
+ test("deleting an element then inserting another one all with hash collisions", () => {
126
+ const map = new HashMap({
127
+ keyHashFunction: returnOne,
128
+ keyEqualityFunction: strictEquals,
129
+ });
130
+
131
+ map.set(1, "a");
132
+ map.set(7, "b");
133
+
134
+ map.delete(1);
135
+
136
+ expect(map.get(7)).toBe("b");
137
+ expect(map.get(1)).toBeUndefined();
138
+
139
+ map.set(13, "c");
140
+
141
+ expect(map.get(13)).toBe("c");
142
+
143
+ map.delete(13);
144
+
145
+ expect(map.get(7)).toBe("b");
146
+ expect(map.get(13)).toBeUndefined();
147
+ });
148
+
110
149
 
111
150
  test("key iterator", () => {
112
151
  const map = new HashMap({
@@ -129,3 +168,73 @@ test("value iterator", () => {
129
168
 
130
169
  expect(map.values().next().value).toBe("hello");
131
170
  });
171
+
172
+
173
+ test("clear works as expected", () => {
174
+ const map = new HashMap({
175
+ keyHashFunction: passThrough,
176
+ keyEqualityFunction: strictEquals
177
+ });
178
+
179
+ map.set(7, "hello");
180
+
181
+ map.clear();
182
+
183
+ expect(map.get(7)).toBe(undefined);
184
+ expect(map.size).toBe(0);
185
+ });
186
+
187
+ test("lcg 32", () => {
188
+ const generated = new Uint32Array(32);
189
+
190
+ let next = 0;
191
+ for (let i = 0; i < 32; i++) {
192
+
193
+ generated[i] = next;
194
+
195
+ next = generate_next_linear_congruential_index(next, 31);
196
+
197
+ }
198
+
199
+ generated.sort();
200
+
201
+ for (let i = 0; i < 32; i++) {
202
+ expect(generated[i]).toBe(i);
203
+ }
204
+ });
205
+
206
+
207
+ test.skip("performance - random fill 100,000", () => {
208
+ const map = new HashMap({
209
+ keyHashFunction: passThrough,
210
+ keyEqualityFunction: strictEquals
211
+ });
212
+
213
+ const map_warmup = new HashMap({
214
+ keyHashFunction: passThrough,
215
+ keyEqualityFunction: strictEquals
216
+ });
217
+
218
+ // warm up
219
+ for (let i = 0; i < 10000; i++) {
220
+ map_warmup.set(i, i);
221
+ map_warmup.get(i);
222
+ }
223
+
224
+ const t0 = performance.now();
225
+
226
+ for (let i = 0; i < 100000; i++) {
227
+ map.set(i, i);
228
+ }
229
+
230
+ const t1 = performance.now();
231
+
232
+ for (let i = 0; i < 100000; i++) {
233
+ map.get(i);
234
+ }
235
+
236
+ const t2 = performance.now();
237
+
238
+ console.log(`Fill: ${t1 - t0}ms`)
239
+ console.log(`Drain: ${t2 - t1}ms`)
240
+ });
@@ -1,4 +1,4 @@
1
- import { BinaryDataType } from "../../binary/type/BinaryDataType.js";
1
+ import { BinaryDataType } from "../../../binary/type/BinaryDataType.js";
2
2
 
3
3
  /**
4
4
  *
@@ -0,0 +1,20 @@
1
+ import { weightedRandomFromArray } from "./weightedRandomFromArray.js";
2
+ import { passThrough, returnOne, returnZero } from "../../function/Functions.js";
3
+
4
+ test("empty array", () => {
5
+ expect(weightedRandomFromArray([], returnZero, passThrough, null, 0))
6
+ .toBeUndefined();
7
+ });
8
+
9
+ test("single element array", () => {
10
+ expect(weightedRandomFromArray([1], returnZero, passThrough, null, 1))
11
+ .toBe(1);
12
+ });
13
+
14
+ test("two elements", () => {
15
+ expect(weightedRandomFromArray([1,3], returnZero, passThrough, null, 2))
16
+ .toBe(1);
17
+
18
+ expect(weightedRandomFromArray([1,3], returnOne, passThrough, null, 2))
19
+ .toBe(3);
20
+ });
@@ -20,8 +20,7 @@ export class AnyOf extends BaseMatcher {
20
20
 
21
21
  matches(item, mismatch_description) {
22
22
  for (const matcher of this.#matchers) {
23
- if (!matcher.matches(item, NullDescription.INSTANCE)) {
24
-
23
+ if (matcher.matches(item, NullDescription.INSTANCE)) {
25
24
  return true;
26
25
  }
27
26
  }
@@ -1,4 +1,4 @@
1
- import AABB2 from "./AABB2.d.ts";
1
+ import AABB2 from "./AABB2.js";
2
2
 
3
3
  test('copy', () => {
4
4
  const a = new AABB2(1, 2, 5, 11);
@@ -0,0 +1,19 @@
1
+ import Vector2 from "../../Vector2.js";
2
+
3
+ /**
4
+ *
5
+ * @param {Array.<AABB2>} boxes
6
+ * @returns {Vector2}
7
+ */
8
+ export function aabb2_compute_center_from_multiple(boxes) {
9
+ const numBoxes = boxes.length;
10
+
11
+ const center = new Vector2();
12
+ for (let i = 0; i < numBoxes; i++) {
13
+ const box = boxes[i];
14
+ center._add(box.midX(), box.midY());
15
+ }
16
+ center.multiplyScalar(1 / numBoxes);
17
+
18
+ return center;
19
+ }
@@ -1,4 +1,4 @@
1
- import { aabb2_signed_distance_sqr_to_point } from "../aabb/aabb2_signed_distance_sqr_to_point.js";
1
+ import { aabb2_distance_sqr_to_point } from "../aabb/aabb2_distance_sqr_to_point.js";
2
2
 
3
3
  /**
4
4
  *
@@ -33,7 +33,7 @@ export function qt_collect_by_circle(
33
33
 
34
34
  const node = node_stack[stack_pointer];
35
35
 
36
- const d2 = aabb2_signed_distance_sqr_to_point(node.x0, node.y0, node.x1, node.y1, x, y);
36
+ const d2 = aabb2_distance_sqr_to_point(node.x0, node.y0, node.x1, node.y1, x, y);
37
37
 
38
38
  if (d2 > r2) {
39
39
  // not a match
@@ -46,7 +46,7 @@ export function qt_collect_by_circle(
46
46
  for (let i = 0; i < data_count; i++) {
47
47
  const datum = data[i];
48
48
 
49
- const d2_to_datum = aabb2_signed_distance_sqr_to_point(datum.x0, datum.y0, datum.x1, datum.y1, x, y);
49
+ const d2_to_datum = aabb2_distance_sqr_to_point(datum.x0, datum.y0, datum.x1, datum.y1, x, y);
50
50
 
51
51
  if (d2_to_datum <= r2) {
52
52
  result[result_cursor++] = datum;
@@ -1,4 +1,3 @@
1
- import { max2 } from "../../../math/max2.js";
2
1
  import { aabb2_distance_sqr_to_point } from "../aabb/aabb2_distance_sqr_to_point.js";
3
2
 
4
3
  /**
@@ -17,20 +16,18 @@ const node_stack = [];
17
16
  */
18
17
  export function qt_query_data_nearest_to_point(tree, x, y, max_distance = Infinity) {
19
18
 
20
- let stack_pointer = 0;
19
+ let stack_pointer = 1;
21
20
 
22
- node_stack[stack_pointer] = tree;
23
- stack_pointer++;
21
+ node_stack[0] = tree;
24
22
 
25
23
  let best_leaf_data = undefined;
26
24
  let best_distance_sqr = max_distance * max_distance;
27
25
 
28
- while (stack_pointer > 0) {
26
+ while (stack_pointer-- > 0) {
29
27
 
30
- --stack_pointer;
31
28
  const node = node_stack[stack_pointer];
32
29
 
33
- const distance_sqr = max2(0, aabb2_distance_sqr_to_point(node.x0, node.y0, node.x1, node.y1, x, y));
30
+ const distance_sqr = aabb2_distance_sqr_to_point(node.x0, node.y0, node.x1, node.y1, x, y);
34
31
 
35
32
  if (distance_sqr >= best_distance_sqr) {
36
33
  // too far
@@ -38,11 +35,12 @@ export function qt_query_data_nearest_to_point(tree, x, y, max_distance = Infini
38
35
  }
39
36
 
40
37
  const data = node.data;
38
+ const data_count = data.length;
41
39
 
42
- for (let i = 0; i < data.length; i++) {
40
+ for (let i = 0; i < data_count; i++) {
43
41
  const datum = data[i];
44
42
 
45
- const distance_sqr = max2(0, aabb2_distance_sqr_to_point(datum.x0, datum.y0, datum.x1, datum.y1, x, y));
43
+ const distance_sqr = aabb2_distance_sqr_to_point(datum.x0, datum.y0, datum.x1, datum.y1, x, y);
46
44
 
47
45
  if (distance_sqr < best_distance_sqr) {
48
46
  best_leaf_data = datum;
@@ -1,4 +1,4 @@
1
- import { v3_distance_above_plane } from "../../v3_distance_above_plane.js";
1
+ import { v3_dot } from "../../v3_dot.js";
2
2
 
3
3
  /**
4
4
  * 2,0,or -2; 2: above, -2 : below, 0 : intersects plane
@@ -26,7 +26,6 @@ export function aabb3_compute_plane_side(
26
26
  _y1,
27
27
  _z1
28
28
  ) {
29
- let result = 0;
30
29
 
31
30
  let x0,
32
31
  y0,
@@ -60,23 +59,26 @@ export function aabb3_compute_plane_side(
60
59
  z1 = _z0;
61
60
  }
62
61
 
63
- // check the nearest corner
62
+ /*
63
+ planar tests are inlined for performance and to save on a few operation,
64
+ if you write it out fully it would be vec4 dot product and comparison to 0,
65
+ since we don't have 4th component for AABB corners,
66
+ we can use vec3 and just move planar offset to the right-hand side of the comparison operation
67
+ */
64
68
 
65
- if (v3_distance_above_plane(x0, y0, z0, plane_normal_x, plane_normal_y, plane_normal_z, plane_constant) >= 0) {
66
- // above the plane
67
- result += 1;
68
- } else {
69
- result -= 1;
70
- }
69
+ const neg_plane_constant = -plane_constant;
71
70
 
72
71
  // check the farthest corner
72
+ if (v3_dot(x1, y1, z1, plane_normal_x, plane_normal_y, plane_normal_z) < neg_plane_constant) {
73
+ // if furthest corner is below plane, the nearest one will be as well, no need to continue
74
+ return -2;
75
+ }
73
76
 
74
- if (v3_distance_above_plane(x1, y1, z1, plane_normal_x, plane_normal_y, plane_normal_z, plane_constant) >= 0) {
75
- // above the plane
76
- result += 1;
77
- } else {
78
- result -= 1;
77
+ // check the nearest corner
78
+ if (v3_dot(plane_normal_x, plane_normal_y, plane_normal_z, x0, y0, z0) >= neg_plane_constant) {
79
+ // above the plane, both corners are above the plane
80
+ return 2;
79
81
  }
80
82
 
81
- return result;
83
+ return 0;
82
84
  }
@@ -0,0 +1,25 @@
1
+ import { aabb3_compute_plane_side } from "./aabb3_compute_plane_side.js";
2
+
3
+ test("fully above plane", () => {
4
+ expect(aabb3_compute_plane_side(
5
+ 0, 1, 0, 0,
6
+ -1, 0.1, -1,
7
+ 1, 1, 1
8
+ )).toBe(2);
9
+ });
10
+
11
+ test("fully below plane", () => {
12
+ expect(aabb3_compute_plane_side(
13
+ 0, 1, 0, 0,
14
+ -1, -1, -1,
15
+ 1, -0.1, 1
16
+ )).toBe(-2);
17
+ });
18
+
19
+ test("intersects plane", () => {
20
+ expect(aabb3_compute_plane_side(
21
+ 0, 1, 0, 0,
22
+ -1, -1, -1,
23
+ 1, 1, 1
24
+ )).toBe(0);
25
+ });
@@ -1,12 +1,12 @@
1
1
  import { aabb3_build_corners } from "./aabb3_build_corners.js";
2
2
  import { aabb_build_frustum } from "./aabb3_build_frustum.js";
3
- import { plane3_computeLineSegmentIntersection } from "../../Plane.js";
4
3
  import { aabb3_corner_edge_mapping } from "./aabb3_corner_edge_mapping.js";
5
4
  import { aabb3_edge_corner_mapping } from "./aabb3_edge_corner_mapping.js";
6
5
  import { plane_computeConvex3PlaneIntersection } from "../plane/plane_computeConvex3PlaneIntersection.js";
7
6
  import { is_point_within_planes } from "../plane/is_point_within_planes.js";
8
7
  import { v3_distance_above_plane } from "../../v3_distance_above_plane.js";
9
8
  import { EPSILON } from "../../../math/EPSILON.js";
9
+ import { plane3_computeLineSegmentIntersection } from "../plane/plane3_computeLineSegmentIntersection.js";
10
10
 
11
11
  /**
12
12
  * Common piece of continuous memory for better cache coherence
@@ -1,5 +1,6 @@
1
1
  import { min2 } from "../../../math/min2.js";
2
2
  import { max2 } from "../../../math/max2.js";
3
+ import { assert } from "../../../assert.js";
3
4
 
4
5
  /**
5
6
  *
@@ -8,6 +9,8 @@ import { max2 } from "../../../math/max2.js";
8
9
  * @param {number} input_length length of the input array
9
10
  */
10
11
  export function aabb3_from_v3_array(result, input, input_length) {
12
+ assert.equal(input_length % 3, 0, `Input must be divisible by 3, instead was ${input_length}`)
13
+
11
14
  let x0 = Infinity;
12
15
  let y0 = Infinity;
13
16
  let z0 = Infinity;
@@ -0,0 +1,32 @@
1
+ import { aabb3_from_v3_array } from "./aabb3_from_v3_array.js";
2
+ import { AABB3 } from "./AABB3.js";
3
+
4
+ test("empty list", () => {
5
+ const box = new AABB3();
6
+
7
+ aabb3_from_v3_array(box, [], 0);
8
+
9
+ expect(box.x0).toEqual(Infinity);
10
+ expect(box.x1).toEqual(-Infinity);
11
+
12
+ expect(box.y0).toEqual(Infinity);
13
+ expect(box.y1).toEqual(-Infinity);
14
+
15
+ expect(box.z0).toEqual(Infinity);
16
+ expect(box.z1).toEqual(-Infinity);
17
+ });
18
+
19
+ test("1 point", () => {
20
+ const box = new AABB3();
21
+
22
+ aabb3_from_v3_array(box, [1, 3, -5], 3);
23
+
24
+ expect(box.x0).toEqual(1);
25
+ expect(box.x1).toEqual(1);
26
+
27
+ expect(box.y0).toEqual(3);
28
+ expect(box.y1).toEqual(3);
29
+
30
+ expect(box.z0).toEqual(-5);
31
+ expect(box.z1).toEqual(-5);
32
+ });
@@ -0,0 +1,115 @@
1
+ import { aabb3_intersects_aabb3 } from "./aabb3_intersects_aabb3.js";
2
+
3
+ test("full containment", () => {
4
+
5
+ expect(aabb3_intersects_aabb3(
6
+ 0, 0, 0, 3, 3, 3,
7
+ 1, 1, 1, 2, 2, 2
8
+ )).toBe(true);
9
+
10
+ expect(aabb3_intersects_aabb3(
11
+ -3, -3, -3, 0, 0, 0,
12
+ -2, -2, -2, -1, -1, -1
13
+ )).toBe(true);
14
+
15
+ });
16
+
17
+ test("complete separation", () => {
18
+
19
+ // X
20
+ expect(aabb3_intersects_aabb3(
21
+ -1, -1, -1, 1, 1, 1,
22
+ 2, 1, 1, 3, 2, 2
23
+ )).toBe(false);
24
+
25
+ expect(aabb3_intersects_aabb3(
26
+ -1, -1, -1, 1, 1, 1,
27
+ -3, 1, 1, -2, 2, 2
28
+ )).toBe(false);
29
+
30
+ // Y
31
+ expect(aabb3_intersects_aabb3(
32
+ -1, -1, -1, 1, 1, 1,
33
+ 1, 2, 1, 2, 3, 2
34
+ )).toBe(false);
35
+
36
+ expect(aabb3_intersects_aabb3(
37
+ -1, -1, -1, 1, 1, 1,
38
+ 1, -3, 1, 2, -2, 2
39
+ )).toBe(false);
40
+
41
+ // Z
42
+ expect(aabb3_intersects_aabb3(
43
+ -1, -1, -1, 1, 1, 1,
44
+ 1, 1, 2, 2, 2, 3
45
+ )).toBe(false);
46
+
47
+ expect(aabb3_intersects_aabb3(
48
+ -1, -1, -1, 1, 1, 1,
49
+ 1, 1, -3, 2, 2, -2
50
+ )).toBe(false);
51
+
52
+ // XY
53
+ expect(aabb3_intersects_aabb3(
54
+ -1, -1, -1, 1, 1, 1,
55
+ 2, 2, 1, 3, 3, 2
56
+ )).toBe(false);
57
+
58
+ expect(aabb3_intersects_aabb3(
59
+ -1, -1, -1, 1, 1, 1,
60
+ -3, 2, 1, -2, 3, 2
61
+ )).toBe(false);
62
+
63
+ expect(aabb3_intersects_aabb3(
64
+ -1, -1, -1, 1, 1, 1,
65
+ 2, -3, 1, 3, -2, 2
66
+ )).toBe(false);
67
+
68
+ expect(aabb3_intersects_aabb3(
69
+ -1, -1, -1, 1, 1, 1,
70
+ -3, -3, 1, -2, -2, 2
71
+ )).toBe(false);
72
+
73
+ // YZ
74
+ expect(aabb3_intersects_aabb3(
75
+ -1, -1, -1, 1, 1, 1,
76
+ 1, 2, 2, 2, 3, 3
77
+ )).toBe(false);
78
+
79
+ expect(aabb3_intersects_aabb3(
80
+ -1, -1, -1, 1, 1, 1,
81
+ 1, -3, 2, 2, -2, 3
82
+ )).toBe(false);
83
+
84
+ expect(aabb3_intersects_aabb3(
85
+ -1, -1, -1, 1, 1, 1,
86
+ 1, 2, -3, 2, 3, 2
87
+ )).toBe(false);
88
+
89
+ expect(aabb3_intersects_aabb3(
90
+ -1, -1, -1, 1, 1, 1,
91
+ 1, -3, -3, 2, -2, 2
92
+ )).toBe(false);
93
+
94
+ // ZX
95
+ expect(aabb3_intersects_aabb3(
96
+ -1, -1, -1, 1, 1, 1,
97
+ 2, 2, 1, 3, 3, 2
98
+ )).toBe(false);
99
+
100
+ expect(aabb3_intersects_aabb3(
101
+ -1, -1, -1, 1, 1, 1,
102
+ 2, -3, 2, 3, -2, 2
103
+ )).toBe(false);
104
+
105
+ expect(aabb3_intersects_aabb3(
106
+ -1, -1, -1, 1, 1, 1,
107
+ -3, 2, 1, -2, 3, 2
108
+ )).toBe(false);
109
+
110
+ expect(aabb3_intersects_aabb3(
111
+ -1, -1, -1, 1, 1, 1,
112
+ -3, -3, 2, -2, -2, 2
113
+ )).toBe(false);
114
+
115
+ });
@@ -27,7 +27,12 @@ import { max2 } from "../../../math/max2.js";
27
27
  * @see https://gdbooks.gitbooks.io/3dcollisions/content/Chapter3/raycast_aabb.html
28
28
  * @see https://blog.johnnovak.net/2016/10/22/the-nim-ray-tracer-project-part-4-calculating-box-normals/
29
29
  */
30
- export function aabb3_raycast(result, result_offset, x0, y0, z0, x1, y1, z1, origin_x, origin_y, origin_z, direction_x, direction_y, direction_z) {
30
+ export function aabb3_raycast(
31
+ result, result_offset,
32
+ x0, y0, z0, x1, y1, z1,
33
+ origin_x, origin_y, origin_z,
34
+ direction_x, direction_y, direction_z
35
+ ) {
31
36
 
32
37
  // first find intersection
33
38
  const dir_inv_x = 1 / direction_x;
@@ -44,32 +44,32 @@ export function serializeAABB3Encoded_v0(buffer, box, x0, y0, z0, x1, y1, z1) {
44
44
  const zD = z1 - z0;
45
45
 
46
46
  if ((header & 1) === 0) {
47
- const _x0 = (((box.x0 - x0) / xD) * 65535) | 0;
47
+ const _x0 = Math.floor(((box.x0 - x0) / xD) * 65535);
48
48
  buffer.writeUint16(_x0);
49
49
  }
50
50
 
51
51
  if ((header & 2) === 0) {
52
- const _x1 = (((box.x1 - x0) / xD) * 65535) | 0;
52
+ const _x1 = Math.ceil(((box.x1 - x0) / xD) * 65535);
53
53
  buffer.writeUint16(_x1);
54
54
  }
55
55
 
56
56
  if ((header & 4) === 0) {
57
- const _y0 = (((box.y0 - y0) / yD) * 65535) | 0;
57
+ const _y0 = Math.floor(((box.y0 - y0) / yD) * 65535);
58
58
  buffer.writeUint16(_y0);
59
59
  }
60
60
 
61
61
  if ((header & 8) === 0) {
62
- const _y1 = (((box.y1 - y0) / yD) * 65535) | 0;
62
+ const _y1 = Math.ceil(((box.y1 - y0) / yD) * 65535);
63
63
  buffer.writeUint16(_y1);
64
64
  }
65
65
 
66
66
  if ((header & 16) === 0) {
67
- const _z0 = (((box.z0 - z0) / zD) * 65535) | 0;
67
+ const _z0 = Math.floor(((box.z0 - z0) / zD) * 65535);
68
68
  buffer.writeUint16(_z0);
69
69
  }
70
70
 
71
71
  if ((header & 32) === 0) {
72
- const _z1 = (((box.z1 - z0) / zD) * 65535) | 0;
72
+ const _z1 = Math.ceil(((box.z1 - z0) / zD) * 65535);
73
73
  buffer.writeUint16(_z1);
74
74
  }
75
75
  }
@@ -12,7 +12,7 @@ import { v3_angle_between } from "../v3_angle_between.js";
12
12
  * @param {number} normalZ orientation of the circle
13
13
  * @param {number} radius
14
14
  */
15
- export function computeCircleBoundingBox(
15
+ export function compute_circle_bounding_box(
16
16
  result,
17
17
  centerX, centerY, centerZ,
18
18
  normalX, normalY, normalZ,
@@ -2,34 +2,35 @@ const hypot = Math.hypot;
2
2
 
3
3
  /**
4
4
  *
5
- * @param {number[]} m
5
+ * @param {number[]} mat4
6
6
  * @param {Vector3} position
7
7
  * @param {Quaternion} rotation
8
8
  * @param {Vector3} scale
9
9
  */
10
- export function decompose_matrix_4_array(m, position, rotation, scale) {
11
- const m11 = m[0];
12
- const m12 = m[1];
13
- const m13 = m[2];
10
+ export function decompose_matrix_4_array(mat4, position, rotation, scale) {
11
+ const m11 = mat4[0];
12
+ const m12 = mat4[1];
13
+ const m13 = mat4[2];
14
14
 
15
15
  const scale_x = hypot(m11, m12, m13);
16
16
 
17
- const m21 = m[4];
18
- const m22 = m[5];
19
- const m23 = m[6];
17
+ const m21 = mat4[4];
18
+ const m22 = mat4[5];
19
+ const m23 = mat4[6];
20
20
 
21
21
  const scale_y = hypot(m21, m22, m23);
22
22
 
23
- const m31 = m[8];
24
- const m32 = m[9];
25
- const m33 = m[10];
23
+ const m31 = mat4[8];
24
+ const m32 = mat4[9];
25
+ const m33 = mat4[10];
26
26
 
27
27
  const scale_z = hypot(m31, m32, m33);
28
28
 
29
29
  // extract rotation matrix
30
- const is1 = 1 / scale_x;
31
- const is2 = 1 / scale_y;
32
- const is3 = 1 / scale_z;
30
+ // take care of potential division by 0 when scale is 0. Result is inexact, but we get don't break the system at least
31
+ const is1 = scale_x !== 0 ? 1 / scale_x : 1e7;
32
+ const is2 = scale_y !== 0 ? 1 / scale_y : 1e7;
33
+ const is3 = scale_z !== 0 ? 1 / scale_z : 1e7;
33
34
 
34
35
  const sm11 = m11 * is1;
35
36
  const sm12 = m12 * is1;
@@ -43,14 +44,12 @@ export function decompose_matrix_4_array(m, position, rotation, scale) {
43
44
  const sm32 = m32 * is3;
44
45
  const sm33 = m33 * is3;
45
46
 
46
- // TODO take care of cases where scale is 0
47
-
48
47
  // write out results
49
48
 
50
49
  position.set(
51
- m[12],
52
- m[13],
53
- m[14]
50
+ mat4[12],
51
+ mat4[13],
52
+ mat4[14]
54
53
  );
55
54
 
56
55
  scale.set(
@@ -1,4 +1,3 @@
1
- import { computePlanePlaneIntersection } from "../../Plane.js";
2
1
  import Vector3 from "../../Vector3.js";
3
2
  import { plane3_projectPoint } from "../plane/plane3_projectPoint.js";
4
3
  import { ray_computeNearestPointToPoint } from "../ray/ray_computeNearestPointToPoint.js";
@@ -6,6 +5,7 @@ import { v3_distance_above_plane } from "../../v3_distance_above_plane.js";
6
5
  import {
7
6
  plane_three_computeConvex3PlaneIntersection
8
7
  } from "../plane/plane_three_compute_convex3_plane_intersection.js";
8
+ import { computePlanePlaneIntersection } from "../plane/computePlanePlaneIntersection.js";
9
9
 
10
10
  /**
11
11
  *
@@ -1,4 +1,4 @@
1
- import { MATRIX_4_IDENTITY } from "../../../../core/geom/3d/matrix/MATRIX_4_IDENTITY.js";
1
+ import { MATRIX_4_IDENTITY } from "./MATRIX_4_IDENTITY.js";
2
2
 
3
3
  /**
4
4
  * Larger bucket sizes provide better cache locality