@woosh/meep-engine 2.42.7 → 2.43.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 (139) hide show
  1. package/core/binary/BitSet.js +4 -4
  2. package/core/binary/ctz32.js +40 -0
  3. package/core/collection/ObservedMap.js +61 -57
  4. package/core/collection/heap/FastBinaryHeap.js +7 -1
  5. package/core/collection/heap/Uint32Heap.js +19 -0
  6. package/core/collection/map/AsyncLoadingCache.js +3 -1
  7. package/core/geom/2d/compute_polygon_area_2d.js +32 -0
  8. package/core/geom/2d/compute_polygon_area_2d.spec.js +10 -0
  9. package/core/geom/2d/compute_triangle_area_2d.js +15 -0
  10. package/core/geom/2d/compute_triangle_area_2d.spec.js +9 -0
  11. package/core/geom/2d/convex-hull/convex_hull_jarvis_2d.js +64 -0
  12. package/core/geom/2d/convex-hull/convex_hull_jarvis_2d.spec.js +33 -0
  13. package/core/geom/2d/convex-hull/convex_hull_monotone_2d.js +82 -0
  14. package/core/geom/2d/convex-hull/fixed_convex_hull_humus.js +135 -0
  15. package/core/geom/2d/convex-hull/fixed_convex_hull_relaxation.js +282 -0
  16. package/core/geom/2d/convex-hull/orientation3.js +444 -0
  17. package/core/geom/2d/convex-hull/orientation3_array.js +22 -0
  18. package/core/geom/2d/convex-hull/orientation3_v2.js +12 -0
  19. package/core/geom/2d/intersect_ray_2d.js +56 -0
  20. package/core/geom/2d/quad-tree/QuadTreeNode.js +0 -81
  21. package/core/geom/2d/quad-tree/qt_match_data_by_circle.js +70 -0
  22. package/core/geom/3d/matrix/m4_multiply_alphatensor.js +131 -0
  23. package/core/geom/3d/plane/orient3d_fast.js +2 -6
  24. package/core/geom/3d/tetrahedra/README.md +7 -0
  25. package/core/geom/3d/tetrahedra/compute_bounding_simplex_3d.js +3 -1
  26. package/core/geom/3d/tetrahedra/delaunay/Cavity.js +48 -0
  27. package/core/geom/3d/tetrahedra/{compute_delaunay_tetrahedral_mesh.js → delaunay/compute_delaunay_tetrahedral_mesh.js} +15 -7
  28. package/core/geom/3d/tetrahedra/{compute_delaunay_tetrahedral_mesh.spec.js → delaunay/compute_delaunay_tetrahedral_mesh.spec.js} +0 -0
  29. package/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_compute_cavity.js +73 -0
  30. package/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_walk_toward_cavity.js +48 -0
  31. package/core/geom/3d/tetrahedra/hxt/a.js +524 -0
  32. package/core/geom/3d/tetrahedra/hxt/hxt.js +140 -0
  33. package/core/geom/3d/tetrahedra/hxt/hxt.wasm +0 -0
  34. package/core/geom/3d/tetrahedra/point_in_tetrahedron_circumsphere.js +35 -20
  35. package/core/geom/3d/tetrahedra/prototypeTetrahedraBuilder.js +98 -0
  36. package/core/geom/3d/tetrahedra/tetrahedra_collection.js +60 -131
  37. package/core/geom/packing/{MaxRectangles.js → max-rect/MaxRectangles.js} +28 -124
  38. package/core/geom/packing/max-rect/removeRedundantBoxes.js +69 -0
  39. package/core/geom/packing/max-rect/removeRedundantBoxesArray.js +40 -0
  40. package/core/geom/v3_distance_above_plane.js +1 -1
  41. package/core/graph/layout/BoxLayouter.js +2 -88
  42. package/core/graph/layout/CircleLayout.js +2 -1
  43. package/core/graph/layout/box/forceIntoBox.js +45 -0
  44. package/core/graph/layout/box/pullBoxTowardsPoint.js +20 -0
  45. package/core/graph/layout/box/resolveAABB2Overlap.js +22 -0
  46. package/core/math/bessel_3.js +11 -0
  47. package/core/math/bessel_i0.js +26 -0
  48. package/core/process/executor/ConcurrentExecutor.spec.js +2 -1
  49. package/core/process/task/util/actionTask.js +19 -0
  50. package/core/process/task/util/countTask.js +62 -0
  51. package/core/process/task/util/delayTask.js +45 -0
  52. package/core/process/task/util/emptyTask.js +19 -0
  53. package/core/process/task/util/failingTask.js +17 -0
  54. package/core/process/task/util/futureTask.js +48 -0
  55. package/core/process/task/util/promiseTask.js +42 -0
  56. package/core/process/task/util/randomCountTask.js +64 -0
  57. package/core/process/task/util/wrapTaskIgnoreFailure.js +47 -0
  58. package/engine/Engine.js +8 -8
  59. package/engine/EngineBootstrapper.js +1 -1
  60. package/engine/asset/AssetManager.js +197 -53
  61. package/engine/asset/AssetRequest.js +32 -0
  62. package/engine/asset/loaders/ArrayBufferLoader.js +62 -50
  63. package/engine/asset/loaders/image/png/PNG.js +15 -1
  64. package/engine/asset/loaders/image/png/PNGReader.js +3 -2
  65. package/engine/ecs/foliage/ecs/InstancedMeshUtils.js +2 -1
  66. package/engine/ecs/storage/BinaryBufferDeSerializer.js +1 -1
  67. package/engine/ecs/storage/JSONDeSerializer.js +2 -1
  68. package/engine/ecs/terrain/ecs/splat/SplatMapOptimizer.js +2 -1
  69. package/engine/ecs/terrain/ecs/splat/SplatMapping.js +1 -1
  70. package/engine/graphics/camera/makeScreenScissorFrustum.js +1 -1
  71. package/engine/graphics/camera/testClippingPlaneComputation.js +4 -45
  72. package/engine/graphics/ecs/camera/FrustumProjector.js +6 -0
  73. package/engine/graphics/ecs/decal/v2/FPDecalSystem.js +5 -0
  74. package/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +23 -4
  75. package/engine/graphics/ecs/highlight/plugin/OutlineRenderPlugin.js +1 -1
  76. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +11 -0
  77. package/engine/graphics/geometry/FULL_SCREEN_TRIANGLE_GEOMETRY.js +1 -2
  78. package/engine/graphics/impostors/octahedral/ImpostorBaker.js +5 -2
  79. package/engine/graphics/impostors/octahedral/ImpostorDescription.js +18 -0
  80. package/engine/graphics/impostors/octahedral/bake/prepare_bake_material.js +15 -0
  81. package/engine/graphics/impostors/octahedral/prototypeBaker.js +66 -79
  82. package/engine/graphics/impostors/octahedral/shader/ImpostorShaderWireframeV0.js +134 -0
  83. package/engine/graphics/impostors/octahedral/util/build_cutout_from_atlas_by_alpha.js +128 -0
  84. package/engine/graphics/impostors/octahedral/util/build_geometry_from_cutout_shape.js +32 -0
  85. package/engine/graphics/impostors/octahedral/util/load_mesh_for_bake.js +31 -0
  86. package/engine/graphics/impostors/octahedral/util/makeImpostorAtlasPreview.js +107 -0
  87. package/engine/graphics/material/manager/ManagedMaterial.js +4 -0
  88. package/engine/graphics/material/manager/MaterialManager.js +1 -0
  89. package/engine/graphics/material/optimization/MaterialOptimizationContext.js +7 -3
  90. package/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.js +2 -2
  91. package/engine/graphics/render/forward_plus/plugin/ForwardPlusRenderingPlugin.js +0 -19
  92. package/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +2 -2
  93. package/engine/graphics/render/visibility/hiz/buildCanvasViewFromTexture.js +83 -27
  94. package/engine/graphics/shadows/ShadowMapRenderer.js +11 -4
  95. package/engine/graphics/texture/atlas/AbstractTextureAtlas.js +2 -1
  96. package/engine/graphics/texture/atlas/CachingTextureAtlas.js +208 -38
  97. package/engine/graphics/texture/atlas/TextureAtlas.js +31 -24
  98. package/engine/graphics/texture/atlas/gpu/WebGLTextureAtlas.js +1 -1
  99. package/engine/graphics/texture/sampler/filter/box.js +16 -0
  100. package/engine/graphics/texture/sampler/filter/cubic2.js +32 -0
  101. package/engine/graphics/texture/sampler/filter/gaussian.js +16 -0
  102. package/engine/graphics/texture/sampler/filter/kaiser_1.js +19 -0
  103. package/engine/graphics/texture/sampler/filter/kaiser_bessel_window.js +19 -0
  104. package/engine/graphics/texture/sampler/filter/mitchell.js +55 -0
  105. package/engine/graphics/texture/sampler/filter/sampler2d_scale_down_generic.js +109 -0
  106. package/engine/graphics/texture/sampler/filter/triangle.js +19 -0
  107. package/engine/graphics/texture/sampler/prototypeSamplerFiltering.js +187 -86
  108. package/engine/graphics/texture/sampler/sampler2_d_scale_down_lanczos.js +77 -25
  109. package/engine/graphics/texture/sampler/search/make_edge_condition_channel_threshold.js +34 -0
  110. package/engine/graphics/texture/sampler/search/sampler2d_find_pixels.js +24 -0
  111. package/engine/graphics/texture/sprite/prototypeSpriteCutoutGeometry.js +212 -0
  112. package/engine/knowledge/database/StaticKnowledgeDataTable.js +1 -1
  113. package/engine/navigation/grid/AStar.js +1 -1
  114. package/engine/plugin/EnginePluginManager.js +28 -27
  115. package/engine/plugin/PluginReferenceContext.js +9 -0
  116. package/engine/scene/Scene.js +1 -1
  117. package/engine/scene/SerializedScene.js +1 -1
  118. package/engine/scene/transitionToScene.js +3 -1
  119. package/generation/example/main.js +1 -1
  120. package/generation/grid/generation/GridTaskApplyActionToCells.js +1 -1
  121. package/generation/grid/generation/GridTaskDensityMarkerDistribution.js +1 -1
  122. package/generation/grid/generation/GridTaskExecuteRuleTimes.js +1 -1
  123. package/generation/grid/generation/NoopGridTaskGenerator.js +1 -1
  124. package/generation/grid/generation/discrete/GridTaskCellularAutomata.js +2 -1
  125. package/generation/grid/generation/discrete/GridTaskConnectRooms.js +1 -1
  126. package/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.js +3 -2
  127. package/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.js +1 -1
  128. package/generation/grid/generation/grid/GridTaskAddNodesFixed.js +1 -1
  129. package/generation/grid/generation/road/GridTaskGenerateRoads.js +3 -2
  130. package/generation/grid/generation/util/buildDistanceMapToObjective.js +1 -1
  131. package/generation/markers/GridActionRuleSet.js +2 -1
  132. package/generation/placement/GridCellActionTransformNearbyMarkers.js +2 -4
  133. package/generation/theme/ThemeEngine.js +4 -1
  134. package/package.json +1 -1
  135. package/view/asset/AssetLoaderStatusView.js +5 -5
  136. package/view/minimap/gl/MinimapTerrainGL.js +1 -2
  137. package/view/renderModel.js +1 -1
  138. package/view/tooltip/TooltipView.js +5 -5
  139. package/core/process/task/TaskUtils.js +0 -352
@@ -0,0 +1,22 @@
1
+ import { orientation3 } from "./orientation3.js";
2
+
3
+ /**
4
+ *
5
+ * @param {number[]} points
6
+ * @param {number} a
7
+ * @param {number} b
8
+ * @param {number} c
9
+ * @returns {number}
10
+ */
11
+ export function orientation3_array(points, a, b, c) {
12
+ const ax = points[a * 2];
13
+ const ay = points[a * 2 + 1];
14
+
15
+ const bx = points[b * 2];
16
+ const by = points[b * 2 + 1];
17
+
18
+ const cx = points[c * 2];
19
+ const cy = points[c * 2 + 1];
20
+
21
+ return orientation3(ax, ay, bx, by, cx, cy);
22
+ }
@@ -0,0 +1,12 @@
1
+ import { orientation3 } from "./orientation3.js";
2
+
3
+ /**
4
+ *
5
+ * @param {number[]} a
6
+ * @param {number[]} b
7
+ * @param {number[]} c
8
+ * @returns {number}
9
+ */
10
+ export function orientation3_v2(a, b, c) {
11
+ return orientation3(a[0], a[1], b[0], b[1], c[0], c[1]);
12
+ }
@@ -0,0 +1,56 @@
1
+ import { fabsf } from "../../math/fabsf.js";
2
+
3
+ /**
4
+ *
5
+ * @param {number} ux
6
+ * @param {number} uy
7
+ * @param {number} vx
8
+ * @param {number} vy
9
+ * @returns {number}
10
+ */
11
+ function perp(ux, uy, vx, vy) {
12
+ return (ux * vy - uy * vx);
13
+ }
14
+
15
+ /**
16
+ * NOTE: that direction must not be normalized for correct results and instead derived from line length
17
+ * @param {number[]|Float32Array|Float64Array} out
18
+ * @param {number} out_offset
19
+ * @param {number} origin_a_x
20
+ * @param {number} origin_a_y
21
+ * @param {number} direction_a_x
22
+ * @param {number} direction_a_y
23
+ * @param {number} origin_b_x
24
+ * @param {number} origin_b_y
25
+ * @param {number} direction_b_x
26
+ * @param {number} direction_b_y
27
+ * @returns {boolean} false if lines are coplanar or intersect on the wrong side
28
+ */
29
+ export function intersect_ray_2d(
30
+ out, out_offset,
31
+ origin_a_x, origin_a_y, direction_a_x, direction_a_y,
32
+ origin_b_x, origin_b_y, direction_b_x, direction_b_y
33
+ ) {
34
+ const d = perp(direction_a_x, direction_a_y, direction_b_x, direction_b_y);
35
+ if (fabsf(d) < 0.000000000001) // Parallel lines
36
+ return false;
37
+
38
+ const t = perp(direction_b_x, direction_b_y, origin_a_x - origin_b_x, origin_a_y - origin_b_y) / d;
39
+
40
+ if (t < 0.5) // Intersects on the wrong side
41
+ return false;
42
+
43
+ const point_x = origin_a_x + t * direction_a_x;
44
+ const point_y = origin_a_y + t * direction_a_y;
45
+
46
+
47
+ // if (Number.isNaN(point_x)) {
48
+ // debugger;
49
+ // }
50
+
51
+
52
+ out[out_offset] = point_x;
53
+ out[out_offset + 1] = point_y;
54
+
55
+ return true;
56
+ }
@@ -2,7 +2,6 @@ import { assert } from "../../../assert.js";
2
2
  import { max2 } from "../../../math/max2.js";
3
3
  import { min2 } from "../../../math/min2.js";
4
4
  import AABB2 from "../../AABB2.js";
5
- import { aabb2_sqrDistanceToPoint } from "../AABB2Math.js";
6
5
  import { QuadTreeDatum } from "./QuadTreeDatum.js";
7
6
 
8
7
 
@@ -486,25 +485,6 @@ export class QuadTreeNode extends AABB2 {
486
485
  }
487
486
  }
488
487
 
489
- /**
490
- *
491
- * @param {QuadTreeDatum<D>[]} result
492
- * @param {number} x
493
- * @param {number} y
494
- * @param {number} radius
495
- * @returns {number} number of intersecting objects added to the result
496
- */
497
- requestDatumIntersectionsCircle(result, x, y, radius) {
498
- //TODO optimize closures out to avoid GC
499
- let count = 0;
500
-
501
- this.traverseCircleIntersections(x, y, radius, datum => {
502
- return result[count++] = datum;
503
- });
504
-
505
- return count;
506
- }
507
-
508
488
  /**
509
489
  *
510
490
  * @param {QuadTreeDatum<D>[]} result
@@ -595,65 +575,4 @@ export class QuadTreeNode extends AABB2 {
595
575
  }
596
576
  }
597
577
 
598
- /**
599
- *
600
- * @param {number} x
601
- * @param {number} y
602
- * @param {number} radius
603
- * @param {function(QuadTreeDatum)} visitor
604
- * @param {*} [thisArg]
605
- */
606
- traverseCircleIntersections(x, y, radius, visitor, thisArg) {
607
- assert.isNumber(x, 'x');
608
- assert.isNumber(y, 'y');
609
- assert.isNumber(radius, 'radius');
610
-
611
- const radius2 = radius * radius;
612
-
613
- const data = this.data;
614
- const dataCount = data.length;
615
-
616
- for (let i = 0; i < dataCount; i++) {
617
- const datum = data[i];
618
-
619
- const d2 = aabb2_sqrDistanceToPoint(datum.x0, datum.y0, datum.x1, datum.y1, x, y);
620
-
621
- if (d2 < radius2) {
622
- const continueTraversal = visitor.call(thisArg, datum);
623
-
624
- if (continueTraversal === false) {
625
- return;
626
- }
627
- }
628
- }
629
-
630
- if (this.isSplit()) {
631
-
632
- const x0 = this.x0;
633
- const x1 = this.x1;
634
-
635
- const y0 = this.y0;
636
- const y1 = this.y1;
637
-
638
- const hx = (x0 + x1) / 2;
639
- const hy = (y0 + y1) / 2;
640
-
641
- if (aabb2_sqrDistanceToPoint(x0, y0, hx, hy, x, y) < radius2) {
642
- this.topLeft.traverseCircleIntersections(x, y, radius, visitor, thisArg);
643
- }
644
-
645
- if (aabb2_sqrDistanceToPoint(x0, hy, hx, y1, x, y) < radius2) {
646
- this.bottomLeft.traverseCircleIntersections(x, y, radius, visitor, thisArg);
647
- }
648
-
649
- if (aabb2_sqrDistanceToPoint(hx, y0, x1, hy, x, y) < radius2) {
650
- this.topRight.traverseCircleIntersections(x, y, radius, visitor, thisArg);
651
- }
652
-
653
- if (aabb2_sqrDistanceToPoint(hx, hy, x1, y1, x, y) < radius2) {
654
- this.bottomRight.traverseCircleIntersections(x, y, radius, visitor, thisArg);
655
- }
656
-
657
- }
658
- }
659
578
  }
@@ -0,0 +1,70 @@
1
+ import { aabb2_sqrDistanceToPoint } from "../AABB2Math.js";
2
+
3
+ /**
4
+ *
5
+ * @type {QuadTreeNode[]}
6
+ */
7
+ const node_stack = [];
8
+
9
+ /**
10
+ * @template T
11
+ * @param {QuadTreeDatum<T>[]} result
12
+ * @param {number} result_offset
13
+ * @param {QuadTreeNode<T>} tree
14
+ * @param {number} x
15
+ * @param {number} y
16
+ * @param {number} radius
17
+ * @param {function(data:T):boolean} [predicate]
18
+ * @param {*} [predicateContext]
19
+ * @returns {number}
20
+ */
21
+ export function qt_match_data_by_circle(
22
+ result, result_offset,
23
+ tree,
24
+ x, y, radius,
25
+ predicate, predicateContext
26
+ ) {
27
+ let result_cursor = result_offset;
28
+
29
+ let stack_pointer = 0;
30
+
31
+ const r2 = radius * radius;
32
+
33
+ node_stack[stack_pointer] = tree;
34
+ stack_pointer++;
35
+
36
+ while (stack_pointer > 0) {
37
+
38
+ --stack_pointer;
39
+ const node = node_stack[stack_pointer];
40
+
41
+ const d2 = aabb2_sqrDistanceToPoint(node.x0, node.y0, node.x1, node.y1, x, y);
42
+
43
+ if (d2 > r2) {
44
+ // not a match
45
+ continue;
46
+ }
47
+
48
+ const data = node.data;
49
+ const data_count = data.length;
50
+
51
+ for (let i = 0; i < data_count; i++) {
52
+ const datum = data[i];
53
+
54
+ const d2_to_datum = aabb2_sqrDistanceToPoint(datum.x0, datum.y0, datum.x1, datum.y1, x, y);
55
+
56
+ if (d2_to_datum <= r2 && predicate.call(predicateContext, datum.data)) {
57
+ result[result_cursor++] = datum;
58
+ }
59
+ }
60
+
61
+ if (node.isSplit()) {
62
+ node_stack[stack_pointer++] = node.topLeft;
63
+ node_stack[stack_pointer++] = node.bottomLeft;
64
+ node_stack[stack_pointer++] = node.topRight;
65
+ node_stack[stack_pointer++] = node.bottomRight;
66
+ }
67
+ }
68
+
69
+ return result_cursor - result_offset;
70
+ }
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Performs 4x4 matrix multiplication using algorithm discovered by AlphaTensor
3
+ * @see AlphaTensor2022 by Fawzi etAl
4
+ * @param {number[]} out
5
+ * @param {number[]} a
6
+ * @param {number[]} b
7
+ */
8
+ export function m4_multiply_alphatensor(out, a, b) {
9
+ // read out matricies
10
+ const a11 = a[0];
11
+ const a12 = a[1];
12
+ const a13 = a[2];
13
+ const a14 = a[3];
14
+ const a21 = a[4];
15
+ const a22 = a[5];
16
+ const a23 = a[6];
17
+ const a24 = a[7];
18
+ const a31 = a[8];
19
+ const a32 = a[9];
20
+ const a33 = a[10];
21
+ const a34 = a[11];
22
+ const a41 = a[12];
23
+ const a42 = a[13];
24
+ const a43 = a[14];
25
+ const a44 = a[15];
26
+
27
+ const b11 = b[0];
28
+ const b12 = b[1];
29
+ const b13 = b[2];
30
+ const b14 = b[3];
31
+ const b21 = b[4];
32
+ const b22 = b[5];
33
+ const b23 = b[6];
34
+ const b24 = b[7];
35
+ const b31 = b[8];
36
+ const b32 = b[9];
37
+ const b33 = b[10];
38
+ const b34 = b[11];
39
+ const b41 = b[12];
40
+ const b42 = b[13];
41
+ const b43 = b[14];
42
+ const b44 = b[15];
43
+
44
+ // apply multiplication algorithm
45
+ const h1 = (a11 + a31) * (b11 + b31)
46
+ const h2 = (a11 - a13 + a31) * (b11 - b13 + b31)
47
+ const h3 = -a13 * (b11 - b13 + b31 - b33)
48
+ const h4 = -a33 * -b33
49
+ const h5 = -a31 * -b13
50
+ const h6 = (a11 - a13 + a31 - a33) * -b31
51
+ const h7 = (-a21 + a22 - a23 - a24) * (-b21 + b22 - b23 - b24)
52
+ const h8 = (-a21 + a22 - a23 - a24 - a41 + a42) * (-b21 + b22 - b23 - b24 - b41 + b42)
53
+ const h9 = (a11 - a13) * (b11 - b13)
54
+ const h10 = (-a21 + a22 - a41 + a42) * (-b21 + b22 - b41 + b42)
55
+ const h11 = (a41 - a42) * (-b23 - b24)
56
+ const h12 = (-a21 + a22 - a23 - a24 - a41 + a42 - a43 - a44) * (b41 - b42)
57
+ const h13 = (-a23 - a24) * (-b21 + b22 - b23 - b24 - b41 + b42 - b43 - b44)
58
+ const h14 = (a11 - a12 + a21 - a22) * (-b12 - b14)
59
+ const h15 = (-a12 - a14) * -b21
60
+ const h16 = (a12 + a14 - a21 + a22 + a23 + a24) * (b12 + b14 - b21 + b22 + b23 + b24)
61
+ const h17 = (a12 + a14 - a21 + a22 + a23 + a24 + a32 + a41 - a42) * (b12 + b14 - b21 + b22 + b23 + b24 + b32 + b41 - b42)
62
+ const h18 = (a12 - a21 + a22 + a32 + a41 - a42) * (b12 - b21 + b22 + b32 + b41 - b42)
63
+ const h19 = (a14 + a23 + a24) * (b12 + b14 - b21 + b22 + b23 + b24 + b32 + b34 + b41 - b42 - b43 - b44)
64
+ const h20 = (a12 + a14 - a21 + a22 + a23 + a24 + a32 + a34 + a41 - a42 - a43 - a44) * (b32 + b41 - b42)
65
+ const h21 = (a32 + a41 - a42) * (b14 + b23 + b24)
66
+ const h22 = (a12 + a14 + a22 + a24) * (b12 + b14 + b22 + b24)
67
+ const h23 = (a12 + a14 + a22 + a24 + a32 - a42) * (b12 + b14 + b22 + b24 + b32 - b42)
68
+ const h24 = (a14 + a24) * (b12 + b14 + b22 + b24 + b32 + b34 - b42 - b44)
69
+ const h25 = (a12 + a14 + a22 + a24 + a32 + a34 - a42 - a44) * (b32 - b42)
70
+ const h26 = (a32 - a42) * (b14 + b24)
71
+ const h27 = (a34 - a44) * (b34 - b44)
72
+ const h28 = (a34 - a43 - a44) * (b34 - b43 - b44)
73
+ const h29 = (a14 + a34) * -b43
74
+ const h30 = (a13 + a14 + a23 + a24 + a33 + a34 - a43 - a44) * (b14 + b34)
75
+ const h31 = (a11 - a12 - a13 - a14 + a21 - a22 - a23 - a24 + a31 - a32 - a33 - a34 - a41 + a42 + a43 + a44) * b14
76
+ const h32 = -a43 * (b13 + b14 + b23 + b24 + b33 + b34 - b43 - b44)
77
+ const h33 = a14 * (-b21 + b41)
78
+ const h34 = (a14 - a32) * (-b21 + b41 - b43)
79
+ const h35 = (a13 + a14 + a23 + a24 - a31 + a32 + a33 + a34 + a41 - a42 - a43 - a44) * (b14 - b32)
80
+ const h36 = (-a31 + a32 + a33 + a34 + a41 - a42 - a43 - a44) * b32
81
+ const h37 = (-a12 - a32) * -b23
82
+ const h38 = (a32 + a34) * (b41 - b43)
83
+ const h39 = (-a13 - a14 - a23 - a24) * (b32 + b34)
84
+ const h40 = a32 * (-b21 + b23 + b41 - b43)
85
+ const h41 = -a21 * (b11 - b12 + b21 - b22)
86
+ const h42 = (-a21 + a41) * (b11 - b12 - b13 - b14 + b21 - b22 - b23 - b24 + b31 - b32 - b33 - b34 - b41 + b42 + b43 + b44)
87
+ const h43 = (-a21 + a41 - a43) * (b13 + b14 + b23 + b24 - b31 + b32 + b33 + b34 + b41 - b42 - b43 - b44)
88
+ const h44 = (a12 + a22 + a32 - a42) * (b12 + b22 + b32 - b42)
89
+ const h45 = (-a21 + a23 + a41 - a43) * (-b31 + b32 + b33 + b34 + b41 - b42 - b43 - b44)
90
+ const h46 = (-a31 + a32 + a41 - a42) * (-b12 - b32)
91
+ const h47 = (a41 - a43) * (-b13 - b14 - b23 - b24)
92
+ const h48 = (-a43 - a44) * (-b43 - b44)
93
+ const h49 = -a23 * (-b31 + b32 + b41 - b42)
94
+ const c11 = h1 - h2 - h5 + h9 + h15 + h33
95
+ const c12 = -h15 - h16 + h17 - h18 - h21 + h22 - h23 + h26 - h33 - h41 + h44 + h49
96
+ const c13 = h2 + h5 + h6 - h9 - h29 - h33 + h34 + h38
97
+ const c14 = -h16 + h17 - h20 - h21 + h22 - h23 + h25 + h26 - h29 - h32 - h33 + h34 + h38 - h41 + h42 + h43
98
+ const c21 = -h7 + h8 - h10 + h11 - h14 + h15 + h16 - h17 + h18 + h21 - h31 + h33 - h35 - h36
99
+ const c22 = h7 - h8 + h10 - h11 - h15 - h16 + h17 - h18 - h21 + h22 - h23 + h26 - h33 + h44
100
+ const c23 = -h7 + h8 + h11 + h12 - h16 + h17 - h20 - h21 - h29 - h33 + h34 + h36 + h38 + h46
101
+ const c24 = -h7 + h8 + h11 + h12 - h16 + h17 - h20 - h21 + h22 - h23 + h25 + h26 - h29 - h33 + h34 + h38
102
+ const c31 = h1 - h2 + h3 - h5 + h33 - h34 + h37 - h40
103
+ const c32 = h17 - h18 - h19 - h21 - h23 + h24 + h26 - h33 + h34 - h37 + h40 - h43 + h44 + h45 - h47 + h49
104
+ const c33 = h4 + h5 - h29 - h33 + h34 + h40
105
+ const c34 = -h21 + h26 - h27 + h28 - h29 - h32 - h33 + h34 + h40 - h47
106
+ const c41 = h8 - h10 + h11 - h13 + h17 - h18 - h19 - h21 + h31 - h33 + h34 + h35 + h36 - h37 - h39 + h40
107
+ const c42 = -h8 + h10 - h11 + h13 - h17 + h18 + h19 + h21 + h23 - h24 - h26 + h33 - h34 + h37 - h40 - h44
108
+ const c43 = h11 + h21 - h28 + h29 + h30 + h33 - h34 - h35 - h36 + h39 - h40 + h48
109
+ const c44 = h11 + h21 - h26 + h27 - h28 + h29 + h33 - h34 - h40 + h48
110
+
111
+ // write out results
112
+ out[0] = c11;
113
+ out[1] = c12;
114
+ out[2] = c13;
115
+ out[3] = c14;
116
+
117
+ out[4] = c21;
118
+ out[5] = c22;
119
+ out[6] = c23;
120
+ out[7] = c24;
121
+
122
+ out[8] = c31;
123
+ out[9] = c32;
124
+ out[10] = c33;
125
+ out[11] = c34;
126
+
127
+ out[12] = c41;
128
+ out[13] = c42;
129
+ out[14] = c43;
130
+ out[15] = c44;
131
+ }
@@ -20,17 +20,13 @@
20
20
  export function orient3d_fast(points, a, b, c, d) {
21
21
  const a3 = a * 3;
22
22
  const d3 = d * 3;
23
+ const b3 = b * 3;
24
+ const c3 = c * 3;
23
25
 
24
26
  const d_x = points[d3];
25
27
 
26
28
  const adx = points[a3] - d_x;
27
-
28
- const b3 = b * 3;
29
-
30
29
  const bdx = points[b3] - d_x;
31
-
32
- const c3 = c * 3;
33
-
34
30
  const cdx = points[c3] - d_x;
35
31
 
36
32
  const d_y = points[d3 + 1];
@@ -0,0 +1,7 @@
1
+ collection of tools for working with tetrahedra (3d simplex)
2
+
3
+ The main feature is tetrahedrasation (triangulation in 3d space)
4
+
5
+ References
6
+ ---
7
+ [Wikipedia - Delaunay triangulation](https://en.wikipedia.org/wiki/Delaunay_triangulation)
@@ -19,6 +19,8 @@ const SIMPLEX_PROJECTION_AXES = new Float32Array([
19
19
 
20
20
  /**
21
21
  * Compute bounding tetrahedron (3d simplex) for a given set of input points
22
+ * The algorithm is pretty basic, it projects each point onto 4 planes and pushes planes away from origin to the furthest projected point
23
+ * then, we take intersection points between those planes to get our bounding tetrahedron
22
24
  *
23
25
  * @see https://github.com/bryanmcnett/aabo/blob/master/aabo.cpp
24
26
  * @author Alexander Goldring (c) 2021
@@ -149,7 +151,7 @@ export function compute_bounding_simplex_3d(
149
151
  min_c -= padding;
150
152
  min_d -= padding;
151
153
 
152
- // lets compute intersection points for each tri-plane combination to find simplex corners
154
+ // let's compute intersection points for each tri-plane combination to find simplex corners
153
155
  plane_computeConvex3PlaneIntersection(
154
156
  result, result_offset,
155
157
  SIMPLEX_PROJECTION_AXES[0], SIMPLEX_PROJECTION_AXES[1], SIMPLEX_PROJECTION_AXES[2], -min_a,
@@ -0,0 +1,48 @@
1
+ export class Cavity {
2
+ constructor() {
3
+ /**
4
+ *
5
+ * @type {number[]}
6
+ */
7
+ this.indices = [];
8
+
9
+ /**
10
+ *
11
+ * @type {number}
12
+ */
13
+ this.size = 0;
14
+ }
15
+
16
+ update() {
17
+ // compute in/out state for each side of each tetra
18
+ }
19
+
20
+ /**
21
+ *
22
+ * @param {number} i
23
+ */
24
+ push(i) {
25
+ this.indices[this.size++] = i;
26
+ }
27
+
28
+ /**
29
+ *
30
+ * @param {number} i
31
+ * @returns {boolean}
32
+ */
33
+ includes(i) {
34
+ const n = this.size;
35
+
36
+ for (let j = 0; j < n; j++) {
37
+ if (this.indices[j] === i) {
38
+ return true;
39
+ }
40
+ }
41
+
42
+ return false;
43
+ }
44
+
45
+ reset() {
46
+ this.size = 0;
47
+ }
48
+ }
@@ -1,19 +1,16 @@
1
1
  //
2
2
 
3
- import { compute_bounding_simplex_3d } from "./compute_bounding_simplex_3d.js";
4
- import { TetrahedraCollection } from "./tetrahedra_collection.js";
3
+ import { compute_bounding_simplex_3d } from "../compute_bounding_simplex_3d.js";
4
+ import { TetrahedralMesh } from "../tetrahedra_collection.js";
5
5
 
6
6
  /**
7
7
  * @see https://en.wikipedia.org/wiki/Bowyer%E2%80%93Watson_algorithm
8
8
  * @see [1] "One machine, one minute, three billion tetrahedra" by Célestin Marot et al
9
9
  * @param {number[]} input serialized set of 3d points (x,y,z)
10
10
  * @param {number} n number of points in the input
11
+ * @returns {TetrahedralMesh}
11
12
  */
12
13
  export function compute_delaunay_tetrahedral_mesh(input, n) {
13
- if (n < 4) {
14
- // no mesh can be created, too few points
15
- return;
16
- }
17
14
 
18
15
  /**
19
16
  * According to [1] number of tetrahedra is around 6 times greater than number of input vertices, we use that fact to pre-allocate memory
@@ -24,7 +21,14 @@ export function compute_delaunay_tetrahedral_mesh(input, n) {
24
21
  * The +7 is for the initial "super" tetrahedron and 6 tetras for intermediate triangulation
25
22
  */
26
23
  const tetrahedron_count_upper_bound = Math.ceil((n * n - 3 * n - 2) / 2) + 7;
27
- const tetrahedrons = new TetrahedraCollection(tetrahedron_count_upper_bound);
24
+
25
+ const tetrahedrons = new TetrahedralMesh(tetrahedron_count_upper_bound);
26
+
27
+ if (n < 4) {
28
+ // no mesh can be created, too few points
29
+ return tetrahedrons;
30
+ }
31
+
28
32
  // TODO apply spatial sort to point, to get better cache locality
29
33
 
30
34
  // compute bounds over the input
@@ -46,5 +50,9 @@ export function compute_delaunay_tetrahedral_mesh(input, n) {
46
50
 
47
51
  // remove tetras formed by with the super bounding volume
48
52
  tetrahedrons.removeTetrasConnectedToPoints(points, n, n + 3);
53
+
54
+
55
+ return tetrahedrons;
49
56
  }
50
57
 
58
+
@@ -0,0 +1,73 @@
1
+ import { assert } from "../../../../assert.js";
2
+ import { point_in_tetrahedron_circumsphere } from "../point_in_tetrahedron_circumsphere.js";
3
+ import { INVALID_NEIGHBOUR } from "../tetrahedra_collection.js";
4
+
5
+ /**
6
+ *
7
+ * @param {TetrahedralMesh} mesh
8
+ * @param {Cavity} cavity
9
+ * @param {number[]|Float32Array} points
10
+ * @param {number} containing_tetra tetrahedron that contains point
11
+ * @param {number} point_index point that forms the cavity
12
+ */
13
+ export function tetrahedral_mesh_compute_cavity(mesh, cavity, points, containing_tetra, point_index) {
14
+ assert.isNonNegativeInteger(containing_tetra, 'containing_tetra');
15
+
16
+ cavity.reset();
17
+
18
+ /**
19
+ *
20
+ * @type {number[]}
21
+ */
22
+ const open_set = [
23
+ containing_tetra
24
+ ];
25
+
26
+ /**
27
+ *
28
+ * @type {number[]}
29
+ */
30
+ const closed_set = [];
31
+
32
+ // 2. find the Delaunay "cavity", a set of tetrahedrons who's circumsphere overlarlaps the point
33
+ // perform breadth-first expansion on the containing tetra to identify the cavity
34
+ while (open_set.length > 0) {
35
+
36
+ const tetra = open_set.pop();
37
+ cavity.push(tetra);
38
+ closed_set.push(tetra);
39
+
40
+ // get neighbours
41
+ for (let i = 0; i < 4; i++) {
42
+
43
+ const neighbour_encoded = mesh.getNeighbour(tetra, i);
44
+ const neighbour_tetra_index = neighbour_encoded >>> 2;
45
+
46
+ if (
47
+ (neighbour_encoded === INVALID_NEIGHBOUR) // no neighbour
48
+ || closed_set.includes(neighbour_tetra_index) // already visited
49
+ || open_set.includes(neighbour_tetra_index) // already in open set
50
+ ) {
51
+
52
+ continue;
53
+ }
54
+
55
+ const a = mesh.getCornerIndex(neighbour_tetra_index, 0);
56
+ const b = mesh.getCornerIndex(neighbour_tetra_index, 1);
57
+ const c = mesh.getCornerIndex(neighbour_tetra_index, 2);
58
+ const d = mesh.getCornerIndex(neighbour_tetra_index, 3);
59
+
60
+ // check neighbour
61
+ const is_in_sphere = point_in_tetrahedron_circumsphere(points, a, b, c, d, containing_tetra);
62
+
63
+ if (is_in_sphere) {
64
+ open_set.push(neighbour_tetra_index);
65
+ } else {
66
+ // move directly to closed set
67
+ closed_set.push(neighbour_tetra_index);
68
+ }
69
+
70
+
71
+ }
72
+ }
73
+ }
@@ -0,0 +1,48 @@
1
+ import { orient3d_fast } from "../../plane/orient3d_fast.js";
2
+
3
+ /**
4
+ * Walk from a given tetrahedron in the mesh towards tetrahedron that contains input point
5
+ * This is an essential method for incrementally finding the next tetrahedron for cavity computation
6
+ *
7
+ * @see https://git.immc.ucl.ac.be/hextreme/hxt_seqdel/-/blob/master/src/hxt_tetrahedra.c#L330
8
+ * @see p3 "One machine, one minute, three billion tetrahedra" by Célestin Marot, Jeanne Pellerin, Jean-François Remacle
9
+ * @param {TetrahedralMesh} mesh
10
+ * @param {number[]} points
11
+ * @param {number} current_tet
12
+ * @param {number} current_vertex
13
+ * @returns {number}
14
+ */
15
+ function tetrahedral_mesh_walk_toward_cavity(mesh, points, current_tet, current_vertex) {
16
+
17
+ let entering_face = 4;
18
+
19
+ let curTet = current_tet;
20
+
21
+ while (true) {
22
+
23
+ let i;
24
+ for (i = 0; i < 4; i++) {
25
+
26
+ // we walk whenever the volume is positive
27
+ const a_i = (i + 1) & 3;
28
+ const b_i = (i & 2) ^ 3;
29
+ const c_i = (i + 3) & 2;
30
+
31
+ const a_index = mesh.getCornerIndex(curTet, a_i);
32
+ const b_index = mesh.getCornerIndex(curTet, b_i);
33
+ const c_index = mesh.getCornerIndex(curTet, c_i);
34
+
35
+ if (i !== entering_face && orient3d_fast(points, a_index, b_index, c_index, current_vertex) < 0.0) {
36
+ const neighbour = mesh.getNeighbour(curTet, i);
37
+ curTet = neighbour >> 2;
38
+ entering_face = neighbour & 3;
39
+ break;
40
+ }
41
+ }
42
+
43
+ if (i === 4) {
44
+ return curTet;
45
+ }
46
+ }
47
+
48
+ }