@woosh/meep-engine 2.138.20 → 2.139.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 (491) hide show
  1. package/package.json +1 -1
  2. package/src/core/collection/PairUint32Map.d.ts +100 -0
  3. package/src/core/collection/PairUint32Map.d.ts.map +1 -0
  4. package/src/core/collection/PairUint32Map.js +321 -0
  5. package/src/core/collection/Uint32Map.d.ts +119 -0
  6. package/src/core/collection/Uint32Map.d.ts.map +1 -0
  7. package/src/core/collection/Uint32Map.js +345 -0
  8. package/src/core/collection/array/array_shuffle.d.ts +10 -3
  9. package/src/core/collection/array/array_shuffle.d.ts.map +1 -1
  10. package/src/core/collection/array/array_shuffle.js +27 -22
  11. package/src/core/collection/heap/FibonacciHeap.d.ts +195 -0
  12. package/src/core/collection/heap/FibonacciHeap.d.ts.map +1 -0
  13. package/src/core/collection/heap/FibonacciHeap.js +586 -0
  14. package/src/core/collection/heap/Uint32Heap.js +1 -1
  15. package/src/core/collection/heap/Uint32Heap4.d.ts +169 -0
  16. package/src/core/collection/heap/Uint32Heap4.d.ts.map +1 -0
  17. package/src/core/collection/heap/Uint32Heap4.js +490 -0
  18. package/src/core/geom/3d/line/line3_closest_points_segment_segment.d.ts +27 -0
  19. package/src/core/geom/3d/line/line3_closest_points_segment_segment.d.ts.map +1 -0
  20. package/src/core/geom/3d/line/line3_closest_points_segment_segment.js +88 -0
  21. package/src/core/geom/3d/shape/BoxShape3D.d.ts +61 -0
  22. package/src/core/geom/3d/shape/BoxShape3D.d.ts.map +1 -0
  23. package/src/core/geom/3d/shape/BoxShape3D.js +158 -0
  24. package/src/core/geom/3d/shape/CapsuleShape3D.d.ts +11 -0
  25. package/src/core/geom/3d/shape/CapsuleShape3D.d.ts.map +1 -1
  26. package/src/core/geom/3d/shape/CapsuleShape3D.js +12 -0
  27. package/src/core/geom/3d/shape/UnitCubeShape3D.d.ts +37 -9
  28. package/src/core/geom/3d/shape/UnitCubeShape3D.d.ts.map +1 -1
  29. package/src/core/geom/3d/shape/UnitCubeShape3D.js +45 -98
  30. package/src/core/geom/3d/shape/UnitSphereShape3D.d.ts +10 -0
  31. package/src/core/geom/3d/shape/UnitSphereShape3D.d.ts.map +1 -1
  32. package/src/core/geom/3d/shape/UnitSphereShape3D.js +11 -0
  33. package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.d.ts +61 -0
  34. package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.d.ts.map +1 -0
  35. package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.js +148 -0
  36. package/src/core/geom/3d/tetrahedra/compute_tetrahedral_mesh_from_surface.d.ts +39 -0
  37. package/src/core/geom/3d/tetrahedra/compute_tetrahedral_mesh_from_surface.d.ts.map +1 -0
  38. package/src/core/geom/3d/tetrahedra/compute_tetrahedral_mesh_from_surface.js +147 -0
  39. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_quality.d.ts +15 -0
  40. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_quality.d.ts.map +1 -0
  41. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_quality.js +22 -0
  42. package/src/core/geom/3d/tetrahedra/prototype_tetrahedrize_mesh.d.ts +2 -0
  43. package/src/core/geom/3d/tetrahedra/prototype_tetrahedrize_mesh.d.ts.map +1 -0
  44. package/src/core/geom/3d/tetrahedra/prototype_tetrahedrize_mesh.js +673 -0
  45. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.d.ts +26 -0
  46. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.d.ts.map +1 -0
  47. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.js +222 -0
  48. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_find_tets_around_edge.d.ts +34 -0
  49. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_find_tets_around_edge.d.ts.map +1 -0
  50. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_find_tets_around_edge.js +146 -0
  51. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.d.ts +36 -0
  52. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.d.ts.map +1 -0
  53. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.js +232 -0
  54. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.d.ts +33 -0
  55. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.d.ts.map +1 -0
  56. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.js +255 -0
  57. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.d.ts +68 -0
  58. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.d.ts.map +1 -0
  59. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.js +365 -0
  60. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.d.ts +31 -0
  61. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.d.ts.map +1 -0
  62. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.js +112 -0
  63. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.d.ts +22 -0
  64. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.d.ts.map +1 -0
  65. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.js +55 -0
  66. package/src/core/geom/3d/tetrahedra/tetrahedron_compute_quality.d.ts +32 -0
  67. package/src/core/geom/3d/tetrahedra/tetrahedron_compute_quality.d.ts.map +1 -0
  68. package/src/core/geom/3d/tetrahedra/tetrahedron_compute_quality.js +66 -0
  69. package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.d.ts +22 -0
  70. package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.d.ts.map +1 -1
  71. package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.js +49 -0
  72. package/src/core/geom/3d/topology/struct/binary/BinaryTopology.d.ts +134 -0
  73. package/src/core/geom/3d/topology/struct/binary/BinaryTopology.d.ts.map +1 -1
  74. package/src/core/geom/3d/topology/struct/binary/BinaryTopology.js +276 -3
  75. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts +17 -0
  76. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts.map +1 -0
  77. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.js +135 -0
  78. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compact.d.ts +14 -0
  79. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compact.d.ts.map +1 -0
  80. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compact.js +177 -0
  81. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_decouple.d.ts.map +1 -1
  82. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_decouple.js +20 -4
  83. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
  84. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +5 -3
  85. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.d.ts.map +1 -1
  86. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.js +9 -0
  87. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_get_or_create.d.ts.map +1 -1
  88. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_get_or_create.js +21 -45
  89. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill.d.ts.map +1 -1
  90. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill.js +7 -1
  91. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts +8 -6
  92. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts.map +1 -1
  93. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.js +8 -6
  94. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_kill_short_edges.d.ts +22 -0
  95. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_kill_short_edges.d.ts.map +1 -0
  96. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_kill_short_edges.js +73 -0
  97. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.d.ts.map +1 -1
  98. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.js +51 -1
  99. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.d.ts +10 -0
  100. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.d.ts.map +1 -0
  101. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.js +42 -0
  102. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.d.ts +28 -0
  103. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.d.ts.map +1 -0
  104. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.js +227 -0
  105. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_walk_boundary_loops.d.ts +13 -0
  106. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_walk_boundary_loops.d.ts.map +1 -0
  107. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_walk_boundary_loops.js +108 -0
  108. package/src/core/geom/3d/topology/struct/binary/query/bt_query_edge_is_boundary.d.ts +11 -0
  109. package/src/core/geom/3d/topology/struct/binary/query/bt_query_edge_is_boundary.d.ts.map +1 -0
  110. package/src/core/geom/3d/topology/struct/binary/query/bt_query_edge_is_boundary.js +20 -0
  111. package/src/core/geom/3d/triangle/triangle_mesh_compute_signed_volume.d.ts +20 -0
  112. package/src/core/geom/3d/triangle/triangle_mesh_compute_signed_volume.d.ts.map +1 -0
  113. package/src/core/geom/3d/triangle/triangle_mesh_compute_signed_volume.js +38 -0
  114. package/src/core/graph/csr/CSRGraph.d.ts +168 -0
  115. package/src/core/graph/csr/CSRGraph.d.ts.map +1 -0
  116. package/src/core/graph/csr/CSRGraph.js +319 -0
  117. package/src/core/graph/metis/cluster_mesh_metis.d.ts +12 -0
  118. package/src/core/graph/metis/cluster_mesh_metis.d.ts.map +1 -1
  119. package/src/core/graph/metis/cluster_mesh_metis.js +12 -0
  120. package/src/core/graph/metis/metis.d.ts +19 -0
  121. package/src/core/graph/metis/metis.d.ts.map +1 -1
  122. package/src/core/graph/metis/metis.js +20 -0
  123. package/src/core/graph/metis/metis_cluster_bs.d.ts +11 -0
  124. package/src/core/graph/metis/metis_cluster_bs.d.ts.map +1 -1
  125. package/src/core/graph/metis/metis_cluster_bs.js +11 -0
  126. package/src/core/graph/metis/metis_options.d.ts +17 -2
  127. package/src/core/graph/metis/metis_options.d.ts.map +1 -1
  128. package/src/core/graph/metis/metis_options.js +17 -2
  129. package/src/core/graph/metis/native/MetisGraph.d.ts +144 -0
  130. package/src/core/graph/metis/native/MetisGraph.d.ts.map +1 -0
  131. package/src/core/graph/metis/native/MetisGraph.js +212 -0
  132. package/src/core/graph/metis/native/bisection/BisectionScratch.d.ts +72 -0
  133. package/src/core/graph/metis/native/bisection/BisectionScratch.d.ts.map +1 -0
  134. package/src/core/graph/metis/native/bisection/BisectionScratch.js +101 -0
  135. package/src/core/graph/metis/native/bisection/bisect_graph.d.ts +37 -0
  136. package/src/core/graph/metis/native/bisection/bisect_graph.d.ts.map +1 -0
  137. package/src/core/graph/metis/native/bisection/bisect_graph.js +100 -0
  138. package/src/core/graph/metis/native/bisection/compute_2way_params.d.ts +15 -0
  139. package/src/core/graph/metis/native/bisection/compute_2way_params.d.ts.map +1 -0
  140. package/src/core/graph/metis/native/bisection/compute_2way_params.js +84 -0
  141. package/src/core/graph/metis/native/bisection/fm_2way.d.ts +30 -0
  142. package/src/core/graph/metis/native/bisection/fm_2way.d.ts.map +1 -0
  143. package/src/core/graph/metis/native/bisection/fm_2way.js +290 -0
  144. package/src/core/graph/metis/native/bisection/grow_bisection.d.ts +23 -0
  145. package/src/core/graph/metis/native/bisection/grow_bisection.d.ts.map +1 -0
  146. package/src/core/graph/metis/native/bisection/grow_bisection.js +137 -0
  147. package/src/core/graph/metis/native/bisection/split_graph_two_way.d.ts +28 -0
  148. package/src/core/graph/metis/native/bisection/split_graph_two_way.d.ts.map +1 -0
  149. package/src/core/graph/metis/native/bisection/split_graph_two_way.js +119 -0
  150. package/src/core/graph/metis/native/coarsen/coarsen_graph.d.ts +20 -0
  151. package/src/core/graph/metis/native/coarsen/coarsen_graph.d.ts.map +1 -0
  152. package/src/core/graph/metis/native/coarsen/coarsen_graph.js +94 -0
  153. package/src/core/graph/metis/native/coarsen/create_coarse_graph.d.ts +24 -0
  154. package/src/core/graph/metis/native/coarsen/create_coarse_graph.d.ts.map +1 -0
  155. package/src/core/graph/metis/native/coarsen/create_coarse_graph.js +158 -0
  156. package/src/core/graph/metis/native/coarsen/match_shem.d.ts +41 -0
  157. package/src/core/graph/metis/native/coarsen/match_shem.d.ts.map +1 -0
  158. package/src/core/graph/metis/native/coarsen/match_shem.js +175 -0
  159. package/src/core/graph/metis/native/initial/initial_kway_bfs.d.ts +24 -0
  160. package/src/core/graph/metis/native/initial/initial_kway_bfs.d.ts.map +1 -0
  161. package/src/core/graph/metis/native/initial/initial_kway_bfs.js +122 -0
  162. package/src/core/graph/metis/native/initial/initial_kway_recursive_bisection.d.ts +29 -0
  163. package/src/core/graph/metis/native/initial/initial_kway_recursive_bisection.d.ts.map +1 -0
  164. package/src/core/graph/metis/native/initial/initial_kway_recursive_bisection.js +170 -0
  165. package/src/core/graph/metis/native/metis_partition_kway.d.ts +41 -0
  166. package/src/core/graph/metis/native/metis_partition_kway.d.ts.map +1 -0
  167. package/src/core/graph/metis/native/metis_partition_kway.js +126 -0
  168. package/src/core/graph/metis/native/refine/IndexedFloatMaxHeap.d.ts +62 -0
  169. package/src/core/graph/metis/native/refine/IndexedFloatMaxHeap.d.ts.map +1 -0
  170. package/src/core/graph/metis/native/refine/IndexedFloatMaxHeap.js +261 -0
  171. package/src/core/graph/metis/native/refine/RefinementScratch.d.ts +45 -0
  172. package/src/core/graph/metis/native/refine/RefinementScratch.d.ts.map +1 -0
  173. package/src/core/graph/metis/native/refine/RefinementScratch.js +53 -0
  174. package/src/core/graph/metis/native/refine/compute_kway_params.d.ts +18 -0
  175. package/src/core/graph/metis/native/refine/compute_kway_params.d.ts.map +1 -0
  176. package/src/core/graph/metis/native/refine/compute_kway_params.js +138 -0
  177. package/src/core/graph/metis/native/refine/fm_kway.d.ts +63 -0
  178. package/src/core/graph/metis/native/refine/fm_kway.d.ts.map +1 -0
  179. package/src/core/graph/metis/native/refine/fm_kway.js +462 -0
  180. package/src/core/graph/metis/native/refine/project_kway.d.ts +22 -0
  181. package/src/core/graph/metis/native/refine/project_kway.d.ts.map +1 -0
  182. package/src/core/graph/metis/native/refine/project_kway.js +43 -0
  183. package/src/core/graph/metis/native/refine/refine_kway.d.ts +34 -0
  184. package/src/core/graph/metis/native/refine/refine_kway.d.ts.map +1 -0
  185. package/src/core/graph/metis/native/refine/refine_kway.js +43 -0
  186. package/src/core/math/linalg/eigen/matrix_householder_in_place.d.ts +2 -2
  187. package/src/core/math/linalg/eigen/matrix_householder_in_place.js +2 -2
  188. package/src/core/math/linalg/eigen/matrix_qr_in_place.d.ts +6 -4
  189. package/src/core/math/linalg/eigen/matrix_qr_in_place.d.ts.map +1 -1
  190. package/src/core/math/linalg/eigen/matrix_qr_in_place.js +69 -23
  191. package/src/engine/EngineHarness.d.ts +3 -1
  192. package/src/engine/EngineHarness.d.ts.map +1 -1
  193. package/src/engine/EngineHarness.js +3 -0
  194. package/src/engine/control/first-person/DESIGN.md +30 -6
  195. package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +563 -0
  196. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts +102 -9
  197. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts.map +1 -1
  198. package/src/engine/control/first-person/FirstPersonPlayerController.js +38 -3
  199. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts +533 -4
  200. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts.map +1 -1
  201. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.js +315 -6
  202. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts +220 -22
  203. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
  204. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +858 -241
  205. package/src/engine/control/first-person/TODO.md +127 -0
  206. package/src/engine/control/first-person/abilities/Ability.d.ts +101 -0
  207. package/src/engine/control/first-person/abilities/Ability.d.ts.map +1 -0
  208. package/src/engine/control/first-person/abilities/Ability.js +119 -0
  209. package/src/engine/control/first-person/abilities/AbilitySet.d.ts +86 -0
  210. package/src/engine/control/first-person/abilities/AbilitySet.d.ts.map +1 -0
  211. package/src/engine/control/first-person/abilities/AbilitySet.js +185 -0
  212. package/src/engine/control/first-person/abilities/LedgeGrab.d.ts +62 -0
  213. package/src/engine/control/first-person/abilities/LedgeGrab.d.ts.map +1 -0
  214. package/src/engine/control/first-person/abilities/LedgeGrab.js +199 -0
  215. package/src/engine/control/first-person/abilities/Mantle.d.ts +45 -0
  216. package/src/engine/control/first-person/abilities/Mantle.d.ts.map +1 -0
  217. package/src/engine/control/first-person/abilities/Mantle.js +188 -0
  218. package/src/engine/control/first-person/abilities/Slide.d.ts +33 -0
  219. package/src/engine/control/first-person/abilities/Slide.d.ts.map +1 -0
  220. package/src/engine/control/first-person/abilities/Slide.js +158 -0
  221. package/src/engine/control/first-person/abilities/WallJump.d.ts +45 -0
  222. package/src/engine/control/first-person/abilities/WallJump.d.ts.map +1 -0
  223. package/src/engine/control/first-person/abilities/WallJump.js +131 -0
  224. package/src/engine/control/first-person/abilities/WallRun.d.ts +44 -0
  225. package/src/engine/control/first-person/abilities/WallRun.d.ts.map +1 -0
  226. package/src/engine/control/first-person/abilities/WallRun.js +180 -0
  227. package/src/engine/control/first-person/composer/EyeOffsetStack.d.ts +49 -0
  228. package/src/engine/control/first-person/composer/EyeOffsetStack.d.ts.map +1 -0
  229. package/src/engine/control/first-person/composer/EyeOffsetStack.js +60 -0
  230. package/src/engine/control/first-person/mastery/BreathRhythmEvaluator.d.ts +100 -0
  231. package/src/engine/control/first-person/mastery/BreathRhythmEvaluator.d.ts.map +1 -0
  232. package/src/engine/control/first-person/mastery/BreathRhythmEvaluator.js +133 -0
  233. package/src/engine/control/first-person/mastery/DecisionPoint.d.ts +10 -0
  234. package/src/engine/control/first-person/mastery/DecisionPoint.d.ts.map +1 -0
  235. package/src/engine/control/first-person/mastery/DecisionPoint.js +30 -0
  236. package/src/engine/control/first-person/mastery/FootAsymmetryTurnEvaluator.d.ts +61 -0
  237. package/src/engine/control/first-person/mastery/FootAsymmetryTurnEvaluator.d.ts.map +1 -0
  238. package/src/engine/control/first-person/mastery/FootAsymmetryTurnEvaluator.js +109 -0
  239. package/src/engine/control/first-person/mastery/MasteryEvaluator.d.ts +40 -0
  240. package/src/engine/control/first-person/mastery/MasteryEvaluator.d.ts.map +1 -0
  241. package/src/engine/control/first-person/mastery/MasteryEvaluator.js +45 -0
  242. package/src/engine/control/first-person/mastery/MasteryScore.d.ts +68 -0
  243. package/src/engine/control/first-person/mastery/MasteryScore.d.ts.map +1 -0
  244. package/src/engine/control/first-person/mastery/MasteryScore.js +100 -0
  245. package/src/engine/control/first-person/mastery/MasterySet.d.ts +60 -0
  246. package/src/engine/control/first-person/mastery/MasterySet.d.ts.map +1 -0
  247. package/src/engine/control/first-person/mastery/MasterySet.js +86 -0
  248. package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.d.ts +58 -0
  249. package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.d.ts.map +1 -0
  250. package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.js +83 -0
  251. package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.d.ts +69 -0
  252. package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.d.ts.map +1 -0
  253. package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.js +109 -0
  254. package/src/engine/control/first-person/math/Spring.d.ts +56 -0
  255. package/src/engine/control/first-person/math/Spring.d.ts.map +1 -0
  256. package/src/engine/control/first-person/math/Spring.js +71 -0
  257. package/src/engine/control/first-person/math/computeLRCBreathRate.d.ts +26 -0
  258. package/src/engine/control/first-person/math/computeLRCBreathRate.d.ts.map +1 -0
  259. package/src/engine/control/first-person/math/computeLRCBreathRate.js +41 -0
  260. package/src/engine/control/first-person/math/computeMassRatios.d.ts +35 -0
  261. package/src/engine/control/first-person/math/computeMassRatios.d.ts.map +1 -0
  262. package/src/engine/control/first-person/math/computeMassRatios.js +44 -0
  263. package/src/engine/control/first-person/pose/FirstPersonPose.d.ts +31 -1
  264. package/src/engine/control/first-person/pose/FirstPersonPose.d.ts.map +1 -1
  265. package/src/engine/control/first-person/pose/FirstPersonPose.js +49 -3
  266. package/src/engine/control/first-person/pose/FirstPersonPosture.d.ts +7 -0
  267. package/src/engine/control/first-person/pose/FirstPersonPosture.d.ts.map +1 -0
  268. package/src/engine/control/first-person/pose/FirstPersonPosture.js +27 -0
  269. package/src/engine/control/first-person/prototype_first_person_controller.js +550 -119
  270. package/src/engine/control/first-person/sensors/FirstPersonSensors.d.ts +58 -0
  271. package/src/engine/control/first-person/sensors/FirstPersonSensors.d.ts.map +1 -0
  272. package/src/engine/control/first-person/sensors/FirstPersonSensors.js +77 -0
  273. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts +80 -0
  274. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts.map +1 -0
  275. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.js +196 -0
  276. package/src/engine/control/first-person/test/buildTestPlayer.d.ts +20 -0
  277. package/src/engine/control/first-person/test/buildTestPlayer.d.ts.map +1 -0
  278. package/src/engine/control/first-person/test/buildTestPlayer.js +28 -0
  279. package/src/engine/graphics/camera/testClippingPlaneComputation.js +0 -2
  280. package/src/engine/graphics/ecs/light/Light.d.ts.map +1 -1
  281. package/src/engine/graphics/ecs/light/Light.js +27 -0
  282. package/src/engine/graphics/ecs/light/LightSystem.js +1 -1
  283. package/src/engine/graphics/ecs/path/PathDisplaySystem.d.ts.map +1 -1
  284. package/src/engine/graphics/ecs/path/testPathDisplaySystem.js +0 -2
  285. package/src/engine/graphics/ecs/path/tube/prototypeAnimatedPathMask.js +0 -2
  286. package/src/engine/graphics/render/buffer/buffers/prototypeNormalFrameBuffer.js +0 -2
  287. package/src/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +0 -2
  288. package/src/engine/graphics/render/visibility/hiz/prototypeHiZ.js +0 -2
  289. package/src/engine/navigation/grid/find_path_on_grid_astar.d.ts.map +1 -1
  290. package/src/engine/navigation/grid/find_path_on_grid_astar.js +11 -2
  291. package/src/engine/navigation/mesh/bt_mesh_face_find_path.d.ts.map +1 -1
  292. package/src/engine/navigation/mesh/bt_mesh_face_find_path.js +11 -1
  293. package/src/engine/physics/PLAN.md +236 -0
  294. package/src/engine/physics/body/BodyStorage.d.ts +187 -0
  295. package/src/engine/physics/body/BodyStorage.d.ts.map +1 -0
  296. package/src/engine/physics/body/BodyStorage.js +427 -0
  297. package/src/engine/physics/broadphase/PairList.d.ts +62 -0
  298. package/src/engine/physics/broadphase/PairList.d.ts.map +1 -0
  299. package/src/engine/physics/broadphase/PairList.js +97 -0
  300. package/src/engine/physics/broadphase/aabb_transform_oriented.d.ts +30 -0
  301. package/src/engine/physics/broadphase/aabb_transform_oriented.d.ts.map +1 -0
  302. package/src/engine/physics/broadphase/aabb_transform_oriented.js +93 -0
  303. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts +16 -0
  304. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts.map +1 -0
  305. package/src/engine/physics/broadphase/compute_fat_world_aabb.js +61 -0
  306. package/src/engine/physics/broadphase/generate_pairs.d.ts +38 -0
  307. package/src/engine/physics/broadphase/generate_pairs.d.ts.map +1 -0
  308. package/src/engine/physics/broadphase/generate_pairs.js +101 -0
  309. package/src/engine/physics/contact/ManifoldStore.d.ts +226 -0
  310. package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -0
  311. package/src/engine/physics/contact/ManifoldStore.js +499 -0
  312. package/src/engine/physics/ecs/BodyKind.d.ts +23 -0
  313. package/src/engine/physics/ecs/BodyKind.d.ts.map +1 -0
  314. package/src/engine/physics/ecs/BodyKind.js +24 -0
  315. package/src/engine/physics/ecs/Collider.d.ts +98 -0
  316. package/src/engine/physics/ecs/Collider.d.ts.map +1 -0
  317. package/src/engine/physics/ecs/Collider.js +136 -0
  318. package/src/engine/physics/ecs/ColliderFlags.d.ts +14 -0
  319. package/src/engine/physics/ecs/ColliderFlags.d.ts.map +1 -0
  320. package/src/engine/physics/ecs/ColliderFlags.js +15 -0
  321. package/src/engine/physics/ecs/ColliderObserverSystem.d.ts +58 -0
  322. package/src/engine/physics/ecs/ColliderObserverSystem.d.ts.map +1 -0
  323. package/src/engine/physics/ecs/ColliderObserverSystem.js +103 -0
  324. package/src/engine/physics/ecs/ColliderSerializationAdapter.d.ts +25 -0
  325. package/src/engine/physics/ecs/ColliderSerializationAdapter.d.ts.map +1 -0
  326. package/src/engine/physics/ecs/ColliderSerializationAdapter.js +37 -0
  327. package/src/engine/physics/ecs/PhysicsEvents.d.ts +15 -0
  328. package/src/engine/physics/ecs/PhysicsEvents.d.ts.map +1 -0
  329. package/src/engine/physics/ecs/PhysicsEvents.js +16 -0
  330. package/src/engine/physics/ecs/PhysicsSystem.d.ts +520 -0
  331. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -0
  332. package/src/engine/physics/ecs/PhysicsSystem.js +1159 -0
  333. package/src/engine/physics/ecs/RigidBody.d.ts +197 -0
  334. package/src/engine/physics/ecs/RigidBody.d.ts.map +1 -0
  335. package/src/engine/physics/ecs/RigidBody.js +240 -0
  336. package/src/engine/physics/ecs/RigidBodyFlags.d.ts +21 -0
  337. package/src/engine/physics/ecs/RigidBodyFlags.d.ts.map +1 -0
  338. package/src/engine/physics/ecs/RigidBodyFlags.js +22 -0
  339. package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts +28 -0
  340. package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts.map +1 -0
  341. package/src/engine/physics/ecs/RigidBodySerializationAdapter.js +81 -0
  342. package/src/engine/physics/ecs/SleepState.d.ts +11 -0
  343. package/src/engine/physics/ecs/SleepState.d.ts.map +1 -0
  344. package/src/engine/physics/ecs/SleepState.js +12 -0
  345. package/src/engine/physics/events/ContactEventBuffer.d.ts +46 -0
  346. package/src/engine/physics/events/ContactEventBuffer.d.ts.map +1 -0
  347. package/src/engine/physics/events/ContactEventBuffer.js +83 -0
  348. package/src/engine/physics/events/diff_manifolds.d.ts +25 -0
  349. package/src/engine/physics/events/diff_manifolds.d.ts.map +1 -0
  350. package/src/engine/physics/events/diff_manifolds.js +50 -0
  351. package/src/engine/physics/fluid/FluidField.d.ts +294 -16
  352. package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
  353. package/src/engine/physics/fluid/FluidField.js +510 -66
  354. package/src/engine/physics/fluid/FluidSimulator.d.ts +188 -5
  355. package/src/engine/physics/fluid/FluidSimulator.d.ts.map +1 -1
  356. package/src/engine/physics/fluid/FluidSimulator.js +455 -95
  357. package/src/engine/physics/fluid/SliceVisualiser.d.ts +29 -6
  358. package/src/engine/physics/fluid/SliceVisualiser.d.ts.map +1 -1
  359. package/src/engine/physics/fluid/SliceVisualiser.js +190 -165
  360. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts +154 -0
  361. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts.map +1 -0
  362. package/src/engine/physics/fluid/ecs/FluidComponent.js +238 -0
  363. package/src/engine/physics/fluid/ecs/FluidEffectorsComponent.d.ts +45 -0
  364. package/src/engine/physics/fluid/ecs/FluidEffectorsComponent.d.ts.map +1 -0
  365. package/src/engine/physics/fluid/ecs/FluidEffectorsComponent.js +89 -0
  366. package/src/engine/physics/fluid/ecs/FluidSystem.d.ts +107 -0
  367. package/src/engine/physics/fluid/ecs/FluidSystem.d.ts.map +1 -0
  368. package/src/engine/physics/fluid/ecs/FluidSystem.js +278 -0
  369. package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts +62 -1
  370. package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts.map +1 -1
  371. package/src/engine/physics/fluid/effector/AbstractFluidEffector.js +81 -6
  372. package/src/engine/physics/fluid/effector/GlobalFluidEffector.d.ts +17 -4
  373. package/src/engine/physics/fluid/effector/GlobalFluidEffector.d.ts.map +1 -1
  374. package/src/engine/physics/fluid/effector/GlobalFluidEffector.js +105 -12
  375. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.d.ts +43 -0
  376. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.d.ts.map +1 -0
  377. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.js +210 -0
  378. package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts +62 -1
  379. package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts.map +1 -1
  380. package/src/engine/physics/fluid/effector/WakeFluidEffector.js +302 -8
  381. package/src/engine/physics/fluid/prototype.js +102 -91
  382. package/src/engine/physics/fluid/solver/optimal_sor_omega.d.ts +33 -0
  383. package/src/engine/physics/fluid/solver/optimal_sor_omega.d.ts.map +1 -0
  384. package/src/engine/physics/fluid/solver/optimal_sor_omega.js +41 -0
  385. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts +20 -5
  386. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts.map +1 -1
  387. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.js +60 -38
  388. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts +25 -4
  389. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts.map +1 -1
  390. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.js +93 -73
  391. package/src/engine/physics/fluid/solver/v3_grid_apply_scalar_advection.d.ts +23 -0
  392. package/src/engine/physics/fluid/solver/v3_grid_apply_scalar_advection.d.ts.map +1 -0
  393. package/src/engine/physics/fluid/solver/v3_grid_apply_scalar_advection.js +60 -0
  394. package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.d.ts +23 -0
  395. package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.d.ts.map +1 -0
  396. package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.js +68 -0
  397. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts +30 -0
  398. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts.map +1 -0
  399. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.js +66 -0
  400. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_uniform.d.ts +26 -0
  401. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_uniform.d.ts.map +1 -0
  402. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_uniform.js +113 -0
  403. package/src/engine/physics/fluid/solver/v3_grid_shift_in_place.d.ts +30 -0
  404. package/src/engine/physics/fluid/solver/v3_grid_shift_in_place.d.ts.map +1 -0
  405. package/src/engine/physics/fluid/solver/v3_grid_shift_in_place.js +107 -0
  406. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts +49 -0
  407. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts.map +1 -0
  408. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.js +126 -0
  409. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts +93 -0
  410. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts.map +1 -0
  411. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.js +424 -0
  412. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.d.ts +20 -0
  413. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.d.ts.map +1 -0
  414. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.js +83 -0
  415. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts +26 -0
  416. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts.map +1 -0
  417. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +70 -0
  418. package/src/engine/physics/gjk/expanding_polytope_algorithm.d.ts.map +1 -1
  419. package/src/engine/physics/gjk/expanding_polytope_algorithm.js +8 -10
  420. package/src/engine/physics/inertia/world_inverse_inertia.d.ts +29 -0
  421. package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -0
  422. package/src/engine/physics/inertia/world_inverse_inertia.js +79 -0
  423. package/src/engine/physics/integration/integrate_position.d.ts +16 -0
  424. package/src/engine/physics/integration/integrate_position.d.ts.map +1 -0
  425. package/src/engine/physics/integration/integrate_position.js +48 -0
  426. package/src/engine/physics/integration/integrate_velocity.d.ts +25 -0
  427. package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -0
  428. package/src/engine/physics/integration/integrate_velocity.js +79 -0
  429. package/src/engine/physics/integration/quat_integrate.d.ts +27 -0
  430. package/src/engine/physics/integration/quat_integrate.d.ts.map +1 -0
  431. package/src/engine/physics/integration/quat_integrate.js +62 -0
  432. package/src/engine/physics/island/IslandBuilder.d.ts +167 -0
  433. package/src/engine/physics/island/IslandBuilder.d.ts.map +1 -0
  434. package/src/engine/physics/island/IslandBuilder.js +411 -0
  435. package/src/engine/physics/island/union_find.d.ts +51 -0
  436. package/src/engine/physics/island/union_find.d.ts.map +1 -0
  437. package/src/engine/physics/island/union_find.js +76 -0
  438. package/src/engine/physics/narrowphase/PosedShape.d.ts +59 -0
  439. package/src/engine/physics/narrowphase/PosedShape.d.ts.map +1 -0
  440. package/src/engine/physics/narrowphase/PosedShape.js +110 -0
  441. package/src/engine/physics/narrowphase/box_box_manifold.d.ts +32 -0
  442. package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -0
  443. package/src/engine/physics/narrowphase/box_box_manifold.js +543 -0
  444. package/src/engine/physics/narrowphase/capsule_contacts.d.ts +122 -0
  445. package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -0
  446. package/src/engine/physics/narrowphase/capsule_contacts.js +508 -0
  447. package/src/engine/physics/narrowphase/narrowphase_step.d.ts +11 -0
  448. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -0
  449. package/src/engine/physics/narrowphase/narrowphase_step.js +382 -0
  450. package/src/engine/physics/narrowphase/sphere_box_contact.d.ts +38 -0
  451. package/src/engine/physics/narrowphase/sphere_box_contact.d.ts.map +1 -0
  452. package/src/engine/physics/narrowphase/sphere_box_contact.js +130 -0
  453. package/src/engine/physics/narrowphase/sphere_sphere_contact.d.ts +26 -0
  454. package/src/engine/physics/narrowphase/sphere_sphere_contact.d.ts.map +1 -0
  455. package/src/engine/physics/narrowphase/sphere_sphere_contact.js +51 -0
  456. package/src/engine/physics/queries/PhysicsSurfacePoint.d.ts +83 -0
  457. package/src/engine/physics/queries/PhysicsSurfacePoint.d.ts.map +1 -0
  458. package/src/engine/physics/queries/PhysicsSurfacePoint.js +100 -0
  459. package/src/engine/physics/queries/raycast.d.ts +20 -0
  460. package/src/engine/physics/queries/raycast.d.ts.map +1 -0
  461. package/src/engine/physics/queries/raycast.js +249 -0
  462. package/src/engine/physics/solver/friction_cone.d.ts +16 -0
  463. package/src/engine/physics/solver/friction_cone.d.ts.map +1 -0
  464. package/src/engine/physics/solver/friction_cone.js +37 -0
  465. package/src/engine/physics/solver/solve_contacts.d.ts +36 -0
  466. package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -0
  467. package/src/engine/physics/solver/solve_contacts.js +598 -0
  468. package/src/core/geom/3d/topology/struct/binary/io/edge/OrderedEdge.d.ts +0 -34
  469. package/src/core/geom/3d/topology/struct/binary/io/edge/OrderedEdge.d.ts.map +0 -1
  470. package/src/core/geom/3d/topology/struct/binary/io/edge/OrderedEdge.js +0 -66
  471. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_calc_edges.d.ts +0 -2
  472. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_calc_edges.d.ts.map +0 -1
  473. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_calc_edges.js +0 -54
  474. package/src/core/geom/3d/topology/struct/binary/io/edge/get_or_create_edge_map.d.ts +0 -2
  475. package/src/core/geom/3d/topology/struct/binary/io/edge/get_or_create_edge_map.d.ts.map +0 -1
  476. package/src/core/geom/3d/topology/struct/binary/io/edge/get_or_create_edge_map.js +0 -26
  477. package/src/engine/ecs/components/Motion.d.ts +0 -21
  478. package/src/engine/ecs/components/Motion.d.ts.map +0 -1
  479. package/src/engine/ecs/components/Motion.js +0 -27
  480. package/src/engine/ecs/components/MotionSerializationAdapter.d.ts +0 -20
  481. package/src/engine/ecs/components/MotionSerializationAdapter.d.ts.map +0 -1
  482. package/src/engine/ecs/components/MotionSerializationAdapter.js +0 -26
  483. package/src/engine/ecs/systems/MotionSystem.d.ts +0 -9
  484. package/src/engine/ecs/systems/MotionSystem.d.ts.map +0 -1
  485. package/src/engine/ecs/systems/MotionSystem.js +0 -29
  486. package/src/engine/physics/fluid/Fluid.d.ts +0 -26
  487. package/src/engine/physics/fluid/Fluid.d.ts.map +0 -1
  488. package/src/engine/physics/fluid/Fluid.js +0 -221
  489. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_reverse.d.ts +0 -7
  490. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_reverse.d.ts.map +0 -1
  491. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_reverse.js +0 -8
@@ -0,0 +1,222 @@
1
+ import { assert } from "../../../assert.js";
2
+ import { BVH, NULL_NODE } from "../../../bvh2/bvh3/BVH.js";
3
+ import { bvh_query_user_data_ray } from "../../../bvh2/bvh3/query/bvh_query_user_data_ray.js";
4
+ import { SurfacePoint3 } from "../SurfacePoint3.js";
5
+ import { computeTriangleRayIntersection } from "../triangle/computeTriangleRayIntersection.js";
6
+
7
+ // Three irrational, mutually unrelated ray directions used for majority-vote
8
+ // inside/outside classification. A single ray is fragile: when it grazes a
9
+ // triangle edge or vertex shared between several faces, Möller-Trumbore's
10
+ // strict inequalities can count 0 or 2 hits instead of 1, flipping parity
11
+ // and wrongly classifying a tet. Three independent rays defang this — at
12
+ // least two must agree, and the geometric chance of two independent
13
+ // irrational rays both grazing shared features is vanishingly small for
14
+ // real-world meshes (Suzanne, sphere, torus, bunny, …).
15
+ //
16
+ // Each row must be roughly unit-length so the AABB-vs-ray slab test in the
17
+ // BVH query doesn't degenerate. Hand-picked rather than randomised so the
18
+ // algorithm is fully deterministic.
19
+ const RAY_DIRECTIONS = [
20
+ 0.97123, 0.18927, 0.14431,
21
+ 0.34219, 0.91283, -0.22971,
22
+ -0.51237, 0.27894, 0.81235,
23
+ ];
24
+ const RAY_COUNT = RAY_DIRECTIONS.length / 3;
25
+
26
+ /**
27
+ * Build a BVH over the surface triangles. Each leaf's user_data is the
28
+ * source face ID.
29
+ *
30
+ * @param {BVH} bvh
31
+ * @param {BinaryTopology} surface
32
+ */
33
+ function build_surface_bvh(bvh, surface) {
34
+ bvh.release_all();
35
+
36
+ const face_count = surface.faces.size;
37
+ const v = [0, 0, 0];
38
+
39
+ for (let f = 0; f < face_count; f++) {
40
+ if (!surface.faces.is_allocated(f)) continue;
41
+
42
+ const l0 = surface.face_read_loop(f);
43
+ const l1 = surface.loop_read_next(l0);
44
+ const l2 = surface.loop_read_next(l1);
45
+
46
+ const v0 = surface.loop_read_vertex(l0);
47
+ const v1 = surface.loop_read_vertex(l1);
48
+ const v2 = surface.loop_read_vertex(l2);
49
+
50
+ surface.vertex_read_coordinate(v, 0, v0);
51
+ let minx = v[0], miny = v[1], minz = v[2];
52
+ let maxx = v[0], maxy = v[1], maxz = v[2];
53
+
54
+ surface.vertex_read_coordinate(v, 0, v1);
55
+ if (v[0] < minx) minx = v[0]; else if (v[0] > maxx) maxx = v[0];
56
+ if (v[1] < miny) miny = v[1]; else if (v[1] > maxy) maxy = v[1];
57
+ if (v[2] < minz) minz = v[2]; else if (v[2] > maxz) maxz = v[2];
58
+
59
+ surface.vertex_read_coordinate(v, 0, v2);
60
+ if (v[0] < minx) minx = v[0]; else if (v[0] > maxx) maxx = v[0];
61
+ if (v[1] < miny) miny = v[1]; else if (v[1] > maxy) maxy = v[1];
62
+ if (v[2] < minz) minz = v[2]; else if (v[2] > maxz) maxz = v[2];
63
+
64
+ const node = bvh.allocate_node();
65
+ bvh.node_set_user_data(node, f);
66
+ bvh.node_set_aabb_primitive(node, minx, miny, minz, maxx, maxy, maxz);
67
+ bvh.insert_leaf(node);
68
+ }
69
+ }
70
+
71
+ const ray_hit = new SurfacePoint3();
72
+ const ray_candidates = [];
73
+ const va = [0, 0, 0];
74
+ const vb = [0, 0, 0];
75
+ const vc = [0, 0, 0];
76
+
77
+ /**
78
+ * Cast a single ray and return the parity of triangle-intersection count
79
+ * (true ⇔ odd ⇔ inside, under the assumption of a closed surface).
80
+ */
81
+ function single_ray_parity_inside(bvh, root, surface, ox, oy, oz, dx, dy, dz) {
82
+ const candidate_count = bvh_query_user_data_ray(
83
+ bvh, root,
84
+ ray_candidates, 0,
85
+ ox, oy, oz,
86
+ dx, dy, dz
87
+ );
88
+
89
+ let hits = 0;
90
+ for (let i = 0; i < candidate_count; i++) {
91
+ const f = ray_candidates[i];
92
+ const l0 = surface.face_read_loop(f);
93
+ const l1 = surface.loop_read_next(l0);
94
+ const l2 = surface.loop_read_next(l1);
95
+
96
+ surface.vertex_read_coordinate(va, 0, surface.loop_read_vertex(l0));
97
+ surface.vertex_read_coordinate(vb, 0, surface.loop_read_vertex(l1));
98
+ surface.vertex_read_coordinate(vc, 0, surface.loop_read_vertex(l2));
99
+
100
+ const hit = computeTriangleRayIntersection(
101
+ ray_hit,
102
+ ox, oy, oz,
103
+ dx, dy, dz,
104
+ va[0], va[1], va[2],
105
+ vb[0], vb[1], vb[2],
106
+ vc[0], vc[1], vc[2]
107
+ );
108
+
109
+ if (hit) hits++;
110
+ }
111
+
112
+ return (hits & 1) === 1;
113
+ }
114
+
115
+ /**
116
+ * Classify a point as inside or outside the surface using a majority vote
117
+ * across `RAY_COUNT` independent parity ray-casts. Robust against the
118
+ * edge/vertex grazing pathologies that defeat single-ray parity.
119
+ *
120
+ * @param {BVH} bvh
121
+ * @param {BinaryTopology} surface
122
+ * @param {number} ox
123
+ * @param {number} oy
124
+ * @param {number} oz
125
+ * @returns {boolean}
126
+ */
127
+ function point_is_inside_surface(bvh, surface, ox, oy, oz) {
128
+ const root = bvh.root;
129
+ if (root === NULL_NODE) {
130
+ return false;
131
+ }
132
+
133
+ let inside_votes = 0;
134
+
135
+ for (let r = 0; r < RAY_COUNT; r++) {
136
+ const dx = RAY_DIRECTIONS[r * 3];
137
+ const dy = RAY_DIRECTIONS[r * 3 + 1];
138
+ const dz = RAY_DIRECTIONS[r * 3 + 2];
139
+
140
+ if (single_ray_parity_inside(bvh, root, surface, ox, oy, oz, dx, dy, dz)) {
141
+ inside_votes++;
142
+ }
143
+ }
144
+
145
+ // Strict majority (more than half).
146
+ return inside_votes * 2 > RAY_COUNT;
147
+ }
148
+
149
+ /**
150
+ * Carve a Delaunay tetrahedralization so only the tets inside the input
151
+ * surface remain. Operates on a TetrahedralMesh whose vertex IDs are aligned
152
+ * with the surface's vertex IDs — both index into the same flat positions
153
+ * array used by `compute_delaunay_tetrahedral_mesh`.
154
+ *
155
+ * Algorithm: build a BVH over the surface triangles, then for every tet,
156
+ * classify its centroid as inside or outside via parity ray-casting against
157
+ * the BVH. Exterior tets are disconnected and deleted.
158
+ *
159
+ * Pure ray-cast classification is intentional. A flood-fill optimisation over
160
+ * tet adjacency would be cheaper but is unsafe when the Delaunay's diagonals
161
+ * differ from the surface's (always the case for coarse meshes like a cube,
162
+ * common for finer meshes): leaked surface triangles let the fill cross from
163
+ * interior to exterior unchecked, deleting tets that should be kept.
164
+ *
165
+ * @param {TetrahedralMesh} tet_mesh mutated in place
166
+ * @param {ArrayLike<number>|Float32Array} positions same flat (x,y,z) array used in the Delaunay pass
167
+ * @param {BinaryTopology} surface watertight surface mesh defining inside/outside
168
+ * @returns {{deleted: number, kept: number}}
169
+ */
170
+ export function tetrahedral_mesh_carve_outside_surface(tet_mesh, positions, surface) {
171
+ assert.defined(tet_mesh, 'tet_mesh');
172
+ assert.equal(tet_mesh.isTetrahedralMesh, true, 'tet_mesh.isTetrahedralMesh !== true');
173
+ assert.defined(surface, 'surface');
174
+ assert.equal(surface.isBinaryTopology, true, 'surface.isBinaryTopology !== true');
175
+
176
+ const surface_bvh = new BVH();
177
+ build_surface_bvh(surface_bvh, surface);
178
+
179
+ const live_tets = tet_mesh.getLive();
180
+ const live_count = live_tets.length;
181
+
182
+ let deleted = 0;
183
+ let kept = 0;
184
+
185
+ // Classify each tet by its centroid. The centroid is guaranteed strictly
186
+ // interior to the tet, so the parity ray-cast against the surface gives
187
+ // an unambiguous answer (never on the surface itself).
188
+ //
189
+ // Face-centroid multi-sampling was considered but rejected: face
190
+ // centroids of large boundary tets land EXACTLY on a surface triangle,
191
+ // making the parity test ambiguous (the ray-triangle test reports a hit
192
+ // or a miss depending on rounding), which corrupted coarse-mesh results
193
+ // (e.g. a unit cube tetrahedralized into ~5 tets lost ~17 % of its
194
+ // volume). The current single-point classifier converges correctly for
195
+ // both coarse convex meshes (cube, sphere) and complex non-convex ones
196
+ // (Suzanne, torus) at the cost of a few-percent discretization gap that
197
+ // shrinks with resolution.
198
+ for (let i = 0; i < live_count; i++) {
199
+ const tet = live_tets[i];
200
+
201
+ let cx = 0, cy = 0, cz = 0;
202
+ for (let j = 0; j < 4; j++) {
203
+ const v3 = tet_mesh.getVertexIndex(tet, j) * 3;
204
+ cx += positions[v3];
205
+ cy += positions[v3 + 1];
206
+ cz += positions[v3 + 2];
207
+ }
208
+ cx *= 0.25;
209
+ cy *= 0.25;
210
+ cz *= 0.25;
211
+
212
+ if (point_is_inside_surface(surface_bvh, surface, cx, cy, cz)) {
213
+ kept++;
214
+ } else {
215
+ tet_mesh.disconnect(tet);
216
+ tet_mesh.delete(tet);
217
+ deleted++;
218
+ }
219
+ }
220
+
221
+ return { deleted, kept };
222
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Collect every tet sharing the edge (v_a, v_b), starting from a tet that's
3
+ * already known to contain the edge. Walks the ring of tets around the edge
4
+ * by following face-neighbours through the two faces of each tet that
5
+ * contain both endpoints.
6
+ *
7
+ * Output is written to `result[result_offset..result_offset + count - 1]`
8
+ * in walk order; the starting tet is first. For an INTERIOR edge (every
9
+ * face neighbour exists) the walk forms a closed cycle visiting each
10
+ * incident tet once; the function returns the count and `out_closed[0]`
11
+ * is set to 1. For a BOUNDARY edge (one or both walk directions hit
12
+ * INVALID_NEIGHBOUR) the walk continues from `start_tet` in the OTHER
13
+ * direction; the function still returns every tet it visited, but
14
+ * `out_closed[0]` is set to 0 so callers that need a proper ring (e.g.
15
+ * the 3-2 flip, which is only valid on closed rings) can reject the input.
16
+ *
17
+ * Cost: O(ring_size), one or two neighbour-hops per tet — much cheaper than
18
+ * scanning the whole mesh, which is why callers should prefer this over
19
+ * {@link tetrahedral_mesh_find_tets_attached_to_vertex} when they already
20
+ * have a starting tet.
21
+ *
22
+ * @param {number[]} result
23
+ * @param {number} result_offset
24
+ * @param {TetrahedralMesh} mesh
25
+ * @param {number} start_tet — must contain both v_a and v_b
26
+ * @param {number} v_a
27
+ * @param {number} v_b
28
+ * @param {number[]} out_closed — 1-element array; set to 1 if the walk
29
+ * closed (interior edge), 0 if either direction hit a boundary face.
30
+ * Callers that need a closed-ring guarantee must inspect this.
31
+ * @returns {number} number of tets written (always ≥ 1 — the start_tet)
32
+ */
33
+ export function tetrahedral_mesh_find_tets_around_edge(result: number[], result_offset: number, mesh: TetrahedralMesh, start_tet: number, v_a: number, v_b: number, out_closed: number[]): number;
34
+ //# sourceMappingURL=tetrahedral_mesh_find_tets_around_edge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tetrahedral_mesh_find_tets_around_edge.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/tetrahedra/tetrahedral_mesh_find_tets_around_edge.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,+DAXW,MAAM,EAAE,iBACR,MAAM,oCAEN,MAAM,OACN,MAAM,OACN,MAAM,cACN,MAAM,EAAE,GAGN,MAAM,CA+DlB"}
@@ -0,0 +1,146 @@
1
+ import { assert } from "../../../assert.js";
2
+ import { INVALID_NEIGHBOUR } from "./TetrahedralMesh.js";
3
+
4
+ /**
5
+ * Collect every tet sharing the edge (v_a, v_b), starting from a tet that's
6
+ * already known to contain the edge. Walks the ring of tets around the edge
7
+ * by following face-neighbours through the two faces of each tet that
8
+ * contain both endpoints.
9
+ *
10
+ * Output is written to `result[result_offset..result_offset + count - 1]`
11
+ * in walk order; the starting tet is first. For an INTERIOR edge (every
12
+ * face neighbour exists) the walk forms a closed cycle visiting each
13
+ * incident tet once; the function returns the count and `out_closed[0]`
14
+ * is set to 1. For a BOUNDARY edge (one or both walk directions hit
15
+ * INVALID_NEIGHBOUR) the walk continues from `start_tet` in the OTHER
16
+ * direction; the function still returns every tet it visited, but
17
+ * `out_closed[0]` is set to 0 so callers that need a proper ring (e.g.
18
+ * the 3-2 flip, which is only valid on closed rings) can reject the input.
19
+ *
20
+ * Cost: O(ring_size), one or two neighbour-hops per tet — much cheaper than
21
+ * scanning the whole mesh, which is why callers should prefer this over
22
+ * {@link tetrahedral_mesh_find_tets_attached_to_vertex} when they already
23
+ * have a starting tet.
24
+ *
25
+ * @param {number[]} result
26
+ * @param {number} result_offset
27
+ * @param {TetrahedralMesh} mesh
28
+ * @param {number} start_tet — must contain both v_a and v_b
29
+ * @param {number} v_a
30
+ * @param {number} v_b
31
+ * @param {number[]} out_closed — 1-element array; set to 1 if the walk
32
+ * closed (interior edge), 0 if either direction hit a boundary face.
33
+ * Callers that need a closed-ring guarantee must inspect this.
34
+ * @returns {number} number of tets written (always ≥ 1 — the start_tet)
35
+ */
36
+ export function tetrahedral_mesh_find_tets_around_edge(
37
+ result, result_offset,
38
+ mesh, start_tet, v_a, v_b,
39
+ out_closed
40
+ ) {
41
+ assert.defined(result, 'result');
42
+ assert.defined(mesh, 'mesh');
43
+ assert.isNonNegativeInteger(start_tet, 'start_tet');
44
+ assert.isNonNegativeInteger(v_a, 'v_a');
45
+ assert.isNonNegativeInteger(v_b, 'v_b');
46
+ assert.notEqual(v_a, v_b, 'v_a and v_b must be distinct');
47
+ assert.defined(out_closed, 'out_closed');
48
+
49
+ // Find slots of v_a and v_b in the starting tet.
50
+ let slot_a_start = -1;
51
+ let slot_b_start = -1;
52
+ for (let i = 0; i < 4; i++) {
53
+ const v = mesh.getVertexIndex(start_tet, i);
54
+ if (v === v_a) slot_a_start = i;
55
+ else if (v === v_b) slot_b_start = i;
56
+ }
57
+ if (slot_a_start < 0 || slot_b_start < 0) {
58
+ throw new Error(`start_tet ${start_tet} does not contain both vertices ${v_a} and ${v_b}`);
59
+ }
60
+
61
+ // The 2 "other" slots in start_tet are the slots of the 2 vertices that
62
+ // are NOT on the edge. The faces OPPOSITE these 2 slots both contain
63
+ // the edge (v_a, v_b); each leads to a different ring neighbour.
64
+ let first_step_slot = -1;
65
+ let second_step_slot = -1;
66
+ for (let i = 0; i < 4; i++) {
67
+ if (i === slot_a_start || i === slot_b_start) continue;
68
+ if (first_step_slot < 0) first_step_slot = i;
69
+ else second_step_slot = i;
70
+ }
71
+
72
+ let cursor = result_offset;
73
+ result[cursor++] = start_tet;
74
+
75
+ // Walk forward via first_step_slot.
76
+ const forward = walk(
77
+ mesh, v_a, v_b, start_tet, first_step_slot, result, /* state */ { cursor }
78
+ );
79
+ cursor = forward.cursor;
80
+
81
+ if (forward.closed) {
82
+ // Ring closed with one walk — visited every incident tet.
83
+ out_closed[0] = 1;
84
+ return cursor - result_offset;
85
+ }
86
+
87
+ // Forward walk hit a boundary face. The ring is open on at least one
88
+ // side; walk backward from start_tet via the OTHER step slot too.
89
+ const backward = walk(
90
+ mesh, v_a, v_b, start_tet, second_step_slot, result, { cursor }
91
+ );
92
+ cursor = backward.cursor;
93
+
94
+ // Two walks were needed → the edge is on the boundary, ring is open.
95
+ out_closed[0] = 0;
96
+ return cursor - result_offset;
97
+ }
98
+
99
+ /**
100
+ * Walk the ring of tets sharing edge (v_a, v_b), starting at `from_tet` and
101
+ * leaving through `from_slot`. Appends visited tets (not including
102
+ * `from_tet`) to `result` at `state.cursor`, updating the cursor. Returns
103
+ * `{ cursor, closed }` — `closed` is true if the walk returned to
104
+ * `from_tet` (interior edge), false if it hit a boundary face.
105
+ */
106
+ function walk(mesh, v_a, v_b, from_tet, from_slot, result, state) {
107
+ let curr_tet = from_tet;
108
+ let exit_slot = from_slot;
109
+
110
+ while (true) {
111
+ const enc = mesh.getNeighbour(curr_tet, exit_slot);
112
+ if (enc === INVALID_NEIGHBOUR) {
113
+ return { cursor: state.cursor, closed: false };
114
+ }
115
+
116
+ const next_tet = enc >>> 2;
117
+ if (next_tet === from_tet) {
118
+ return { cursor: state.cursor, closed: true };
119
+ }
120
+
121
+ result[state.cursor++] = next_tet;
122
+
123
+ // Find slots of v_a, v_b in next_tet, and the back-slot (the face
124
+ // we just walked through). The next "exit" is the only remaining
125
+ // slot — i.e., {0,1,2,3} \ {slot_a, slot_b, back_slot}.
126
+ let slot_a_next = -1;
127
+ let slot_b_next = -1;
128
+ for (let i = 0; i < 4; i++) {
129
+ const v = mesh.getVertexIndex(next_tet, i);
130
+ if (v === v_a) slot_a_next = i;
131
+ else if (v === v_b) slot_b_next = i;
132
+ }
133
+ const back_slot = enc & 3;
134
+
135
+ let next_exit = -1;
136
+ for (let i = 0; i < 4; i++) {
137
+ if (i !== slot_a_next && i !== slot_b_next && i !== back_slot) {
138
+ next_exit = i;
139
+ break;
140
+ }
141
+ }
142
+
143
+ curr_tet = next_tet;
144
+ exit_slot = next_exit;
145
+ }
146
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Perform a 2-3 flip on two tetrahedra that share a face.
3
+ *
4
+ * Input two tets t1, t2 sharing a triangle face. The flip removes that face
5
+ * and replaces it with a new edge connecting the two "apex" vertices (the
6
+ * vertex of each tet that's NOT on the shared face). The shared bipyramid is
7
+ * re-tetrahedralised into three new tets, each containing the new edge plus
8
+ * one edge of the original shared face.
9
+ *
10
+ * Counts go from (2 tets, 5 vertices total, 1 internal face) to (3 tets, 5
11
+ * vertices, 3 internal faces). No vertex IDs change; the operation is purely
12
+ * topological — it doesn't touch the points array.
13
+ *
14
+ * Geometric validity (positive volume of each new tet under any specific
15
+ * embedding) is the caller's responsibility. The flip preserves orientation
16
+ * — if t1 was positively wound the new tets are too — but the new edge
17
+ * (d, e) must actually lie inside the convex region formed by the original
18
+ * two tets for the result to be a valid embedding. Outside Delaunay /
19
+ * constraint-recovery contexts this is the caller's domain knowledge.
20
+ *
21
+ * Implementation notes:
22
+ * - t1's storage slot is reused for one of the new tets ("T_alpha")
23
+ * - t2's slot for another ("T_beta")
24
+ * - one fresh slot is allocated for the third ("T_gamma")
25
+ * - all four external neighbour back-pointers around each of t1 and t2
26
+ * are rewritten to point at the right new tet/slot
27
+ *
28
+ * @param {TetrahedralMesh} mesh
29
+ * @param {number} t1
30
+ * @param {number} t2 must share a face with t1
31
+ * @param {Uint32Array|number[]} out output storage; out[0..2] receive the 3
32
+ * new tet IDs. Caller provides — the function performs no allocation.
33
+ * Must have length ≥ 3.
34
+ */
35
+ export function tetrahedral_mesh_flip_23(mesh: TetrahedralMesh, t1: number, t2: number, out: Uint32Array | number[]): void;
36
+ //# sourceMappingURL=tetrahedral_mesh_flip_23.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tetrahedral_mesh_flip_23.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.js"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,oEANW,MAAM,MACN,MAAM,OACN,WAAW,GAAC,MAAM,EAAE,QAmK9B"}
@@ -0,0 +1,232 @@
1
+ import { assert } from "../../../assert.js";
2
+ import { INVALID_NEIGHBOUR } from "./TetrahedralMesh.js";
3
+
4
+ /**
5
+ * For a tet stored as (v0, v1, v2, v3), the vertices of the face opposite
6
+ * vertex i, in counter-clockwise order viewed from outside the tet (i.e. the
7
+ * standard outward-facing winding for a positively-oriented tet whose signed
8
+ * volume is positive under the engine's `compute_tetrahedron_volume`).
9
+ *
10
+ * Derived from the volume formula vol = (1/6)·det[v0-v3, v1-v3, v2-v3]:
11
+ * - Face opposite v3 is the canonical case (v0, v1, v2).
12
+ * - Other faces follow by even-permutation parity to keep the implied tet
13
+ * (face, opposite_vertex) positively wound.
14
+ */
15
+ const FACE_VERTICES_BY_OPPOSITE = [
16
+ [1, 3, 2], // opposite v0
17
+ [0, 2, 3], // opposite v1
18
+ [0, 3, 1], // opposite v2
19
+ [0, 1, 2], // opposite v3
20
+ ];
21
+
22
+ /**
23
+ * Perform a 2-3 flip on two tetrahedra that share a face.
24
+ *
25
+ * Input two tets t1, t2 sharing a triangle face. The flip removes that face
26
+ * and replaces it with a new edge connecting the two "apex" vertices (the
27
+ * vertex of each tet that's NOT on the shared face). The shared bipyramid is
28
+ * re-tetrahedralised into three new tets, each containing the new edge plus
29
+ * one edge of the original shared face.
30
+ *
31
+ * Counts go from (2 tets, 5 vertices total, 1 internal face) to (3 tets, 5
32
+ * vertices, 3 internal faces). No vertex IDs change; the operation is purely
33
+ * topological — it doesn't touch the points array.
34
+ *
35
+ * Geometric validity (positive volume of each new tet under any specific
36
+ * embedding) is the caller's responsibility. The flip preserves orientation
37
+ * — if t1 was positively wound the new tets are too — but the new edge
38
+ * (d, e) must actually lie inside the convex region formed by the original
39
+ * two tets for the result to be a valid embedding. Outside Delaunay /
40
+ * constraint-recovery contexts this is the caller's domain knowledge.
41
+ *
42
+ * Implementation notes:
43
+ * - t1's storage slot is reused for one of the new tets ("T_alpha")
44
+ * - t2's slot for another ("T_beta")
45
+ * - one fresh slot is allocated for the third ("T_gamma")
46
+ * - all four external neighbour back-pointers around each of t1 and t2
47
+ * are rewritten to point at the right new tet/slot
48
+ *
49
+ * @param {TetrahedralMesh} mesh
50
+ * @param {number} t1
51
+ * @param {number} t2 must share a face with t1
52
+ * @param {Uint32Array|number[]} out output storage; out[0..2] receive the 3
53
+ * new tet IDs. Caller provides — the function performs no allocation.
54
+ * Must have length ≥ 3.
55
+ */
56
+ export function tetrahedral_mesh_flip_23(mesh, t1, t2, out) {
57
+ assert.defined(mesh, 'mesh');
58
+ assert.equal(mesh.isTetrahedralMesh, true, 'mesh.isTetrahedralMesh !== true');
59
+ assert.isNonNegativeInteger(t1, 't1');
60
+ assert.isNonNegativeInteger(t2, 't2');
61
+ assert.notEqual(t1, t2, 't1 must not equal t2');
62
+ assert.defined(out, 'out');
63
+
64
+ // -----------------------------------------------------------------
65
+ // Step 1: locate the shared face.
66
+ // -----------------------------------------------------------------
67
+ let shared_i1 = -1;
68
+ let shared_i2 = -1;
69
+ for (let i = 0; i < 4; i++) {
70
+ const enc = mesh.getNeighbour(t1, i);
71
+ if (enc === INVALID_NEIGHBOUR) continue;
72
+ if ((enc >>> 2) === t2) {
73
+ shared_i1 = i;
74
+ shared_i2 = enc & 3;
75
+ break;
76
+ }
77
+ }
78
+ if (shared_i1 < 0) {
79
+ throw new Error(`tets ${t1} and ${t2} do not share a face`);
80
+ }
81
+
82
+ // -----------------------------------------------------------------
83
+ // Step 2: identify the 5 distinct vertices.
84
+ // d = apex of t1 (opposite the shared face)
85
+ // e = apex of t2
86
+ // (p, q, r) = shared face vertices, in CCW order seen from outside t1
87
+ // (i.e. the standard "outward face" ordering)
88
+ // -----------------------------------------------------------------
89
+ const d = mesh.getVertexIndex(t1, shared_i1);
90
+ const e = mesh.getVertexIndex(t2, shared_i2);
91
+
92
+ const face_t1 = FACE_VERTICES_BY_OPPOSITE[shared_i1];
93
+ const pos_p_in_t1 = face_t1[0];
94
+ const pos_q_in_t1 = face_t1[1];
95
+ const pos_r_in_t1 = face_t1[2];
96
+
97
+ const p = mesh.getVertexIndex(t1, pos_p_in_t1);
98
+ const q = mesh.getVertexIndex(t1, pos_q_in_t1);
99
+ const r = mesh.getVertexIndex(t1, pos_r_in_t1);
100
+
101
+ // Find where p, q, r live in t2's vertex array. Needed to look up which
102
+ // of t2's external neighbours sits opposite each of p, q, r.
103
+ let pos_p_in_t2 = -1, pos_q_in_t2 = -1, pos_r_in_t2 = -1;
104
+ for (let i = 0; i < 4; i++) {
105
+ const v = mesh.getVertexIndex(t2, i);
106
+ if (v === p) pos_p_in_t2 = i;
107
+ else if (v === q) pos_q_in_t2 = i;
108
+ else if (v === r) pos_r_in_t2 = i;
109
+ }
110
+ if (pos_p_in_t2 < 0 || pos_q_in_t2 < 0 || pos_r_in_t2 < 0) {
111
+ throw new Error(
112
+ `tets ${t1} and ${t2} are recorded as neighbours but their shared face vertices don't match — mesh integrity broken`
113
+ );
114
+ }
115
+
116
+ // -----------------------------------------------------------------
117
+ // Step 3: snapshot external neighbours BEFORE we start writing.
118
+ // t1's faces opposite p, q, r are external (the face opposite d is t2).
119
+ // Same for t2.
120
+ // -----------------------------------------------------------------
121
+ const ext_p_t1 = mesh.getNeighbour(t1, pos_p_in_t1);
122
+ const ext_q_t1 = mesh.getNeighbour(t1, pos_q_in_t1);
123
+ const ext_r_t1 = mesh.getNeighbour(t1, pos_r_in_t1);
124
+ const ext_p_t2 = mesh.getNeighbour(t2, pos_p_in_t2);
125
+ const ext_q_t2 = mesh.getNeighbour(t2, pos_q_in_t2);
126
+ const ext_r_t2 = mesh.getNeighbour(t2, pos_r_in_t2);
127
+
128
+ // -----------------------------------------------------------------
129
+ // Step 4: allocate the third slot. Reuse t1 → T_alpha, t2 → T_beta.
130
+ // -----------------------------------------------------------------
131
+ const T_alpha = t1;
132
+ const T_beta = t2;
133
+ const T_gamma = mesh.allocate();
134
+
135
+ // -----------------------------------------------------------------
136
+ // Step 5: write vertices in canonical positive-volume order.
137
+ // T_alpha = (r, q, d, e) — covers edge (q, r), missing p
138
+ // T_beta = (p, r, d, e) — covers edge (r, p), missing q
139
+ // T_gamma = (q, p, d, e) — covers edge (p, q), missing r
140
+ // Each ordering was derived (and verified) to keep the new tet's signed
141
+ // volume the same sign as the original t1/t2 under the engine's
142
+ // convention.
143
+ // -----------------------------------------------------------------
144
+ mesh.setVertexIndex(T_alpha, 0, r);
145
+ mesh.setVertexIndex(T_alpha, 1, q);
146
+ mesh.setVertexIndex(T_alpha, 2, d);
147
+ mesh.setVertexIndex(T_alpha, 3, e);
148
+
149
+ mesh.setVertexIndex(T_beta, 0, p);
150
+ mesh.setVertexIndex(T_beta, 1, r);
151
+ mesh.setVertexIndex(T_beta, 2, d);
152
+ mesh.setVertexIndex(T_beta, 3, e);
153
+
154
+ mesh.setVertexIndex(T_gamma, 0, q);
155
+ mesh.setVertexIndex(T_gamma, 1, p);
156
+ mesh.setVertexIndex(T_gamma, 2, d);
157
+ mesh.setVertexIndex(T_gamma, 3, e);
158
+
159
+ // -----------------------------------------------------------------
160
+ // Step 6: internal neighbour links between the three new tets.
161
+ //
162
+ // Walking each new tet's faces:
163
+ // T_alpha = (r, q, d, e):
164
+ // slot 0 (opp r) face {q,d,e} — shared with T_gamma's slot 1 (opp p)
165
+ // slot 1 (opp q) face {r,d,e} — shared with T_beta's slot 0 (opp p)
166
+ // slot 2 (opp d) face {r,q,e} — external, was opposite p in t2
167
+ // slot 3 (opp e) face {r,q,d} — external, was opposite p in t1
168
+ //
169
+ // T_beta = (p, r, d, e):
170
+ // slot 0 (opp p) face {r,d,e} — shared with T_alpha's slot 1 (opp q)
171
+ // slot 1 (opp r) face {p,d,e} — shared with T_gamma's slot 0 (opp q)
172
+ // slot 2 (opp d) face {p,r,e} — external, was opposite q in t2
173
+ // slot 3 (opp e) face {p,r,d} — external, was opposite q in t1
174
+ //
175
+ // T_gamma = (q, p, d, e):
176
+ // slot 0 (opp q) face {p,d,e} — shared with T_beta's slot 1 (opp r)
177
+ // slot 1 (opp p) face {q,d,e} — shared with T_alpha's slot 0 (opp r)
178
+ // slot 2 (opp d) face {q,p,e} — external, was opposite r in t2
179
+ // slot 3 (opp e) face {q,p,d} — external, was opposite r in t1
180
+ // -----------------------------------------------------------------
181
+ mesh.setNeighbour(T_alpha, 0, (T_gamma << 2) | 1);
182
+ mesh.setNeighbour(T_alpha, 1, (T_beta << 2) | 0);
183
+ mesh.setNeighbour(T_beta, 0, (T_alpha << 2) | 1);
184
+ mesh.setNeighbour(T_beta, 1, (T_gamma << 2) | 0);
185
+ mesh.setNeighbour(T_gamma, 0, (T_beta << 2) | 1);
186
+ mesh.setNeighbour(T_gamma, 1, (T_alpha << 2) | 0);
187
+
188
+ // -----------------------------------------------------------------
189
+ // Step 7: external neighbour links. The new tet inherits the SAME
190
+ // encoded value the old tet held — the neighbour tet ID and its
191
+ // back-slot don't change. Only the new tet's own slot needs the value.
192
+ // -----------------------------------------------------------------
193
+ mesh.setNeighbour(T_alpha, 2, ext_p_t2);
194
+ mesh.setNeighbour(T_alpha, 3, ext_p_t1);
195
+ mesh.setNeighbour(T_beta, 2, ext_q_t2);
196
+ mesh.setNeighbour(T_beta, 3, ext_q_t1);
197
+ mesh.setNeighbour(T_gamma, 2, ext_r_t2);
198
+ mesh.setNeighbour(T_gamma, 3, ext_r_t1);
199
+
200
+ // -----------------------------------------------------------------
201
+ // Step 8: rewrite the external neighbours' back-pointers. Each one
202
+ // currently points at t1 or t2; now they should point at the
203
+ // corresponding new tet and slot.
204
+ // -----------------------------------------------------------------
205
+ rewrite_back_pointer(mesh, ext_p_t2, T_alpha, 2);
206
+ rewrite_back_pointer(mesh, ext_p_t1, T_alpha, 3);
207
+ rewrite_back_pointer(mesh, ext_q_t2, T_beta, 2);
208
+ rewrite_back_pointer(mesh, ext_q_t1, T_beta, 3);
209
+ rewrite_back_pointer(mesh, ext_r_t2, T_gamma, 2);
210
+ rewrite_back_pointer(mesh, ext_r_t1, T_gamma, 3);
211
+
212
+ out[0] = T_alpha;
213
+ out[1] = T_beta;
214
+ out[2] = T_gamma;
215
+ }
216
+
217
+ /**
218
+ * Given an encoded neighbour reference (as stored in a tet's neighbour slot)
219
+ * that used to point at some old tet, rewrite the OTHER end of that link so
220
+ * it points at `new_tet` at `new_slot` instead. The low 2 bits of the
221
+ * encoded value tell us the slot in the external tet that holds the
222
+ * back-pointer.
223
+ *
224
+ * No-op if the encoded reference is INVALID_NEIGHBOUR (the old tet had no
225
+ * neighbour on that face).
226
+ */
227
+ function rewrite_back_pointer(mesh, encoded, new_tet, new_slot) {
228
+ if (encoded === INVALID_NEIGHBOUR) return;
229
+ const ext_tet = encoded >>> 2;
230
+ const back_slot = encoded & 3;
231
+ mesh.setNeighbour(ext_tet, back_slot, (new_tet << 2) | new_slot);
232
+ }