@woosh/meep-engine 2.138.19 → 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.
- package/package.json +2 -1
- package/src/core/collection/PairUint32Map.d.ts +100 -0
- package/src/core/collection/PairUint32Map.d.ts.map +1 -0
- package/src/core/collection/PairUint32Map.js +321 -0
- package/src/core/collection/Uint32Map.d.ts +119 -0
- package/src/core/collection/Uint32Map.d.ts.map +1 -0
- package/src/core/collection/Uint32Map.js +345 -0
- package/src/core/collection/array/array_shuffle.d.ts +10 -3
- package/src/core/collection/array/array_shuffle.d.ts.map +1 -1
- package/src/core/collection/array/array_shuffle.js +27 -22
- package/src/core/collection/heap/FibonacciHeap.d.ts +195 -0
- package/src/core/collection/heap/FibonacciHeap.d.ts.map +1 -0
- package/src/core/collection/heap/FibonacciHeap.js +586 -0
- package/src/core/collection/heap/Uint32Heap.js +1 -1
- package/src/core/collection/heap/Uint32Heap4.d.ts +169 -0
- package/src/core/collection/heap/Uint32Heap4.d.ts.map +1 -0
- package/src/core/collection/heap/Uint32Heap4.js +490 -0
- package/src/core/geom/3d/line/line3_closest_points_segment_segment.d.ts +27 -0
- package/src/core/geom/3d/line/line3_closest_points_segment_segment.d.ts.map +1 -0
- package/src/core/geom/3d/line/line3_closest_points_segment_segment.js +88 -0
- package/src/core/geom/3d/shape/BoxShape3D.d.ts +61 -0
- package/src/core/geom/3d/shape/BoxShape3D.d.ts.map +1 -0
- package/src/core/geom/3d/shape/BoxShape3D.js +158 -0
- package/src/core/geom/3d/shape/CapsuleShape3D.d.ts +11 -0
- package/src/core/geom/3d/shape/CapsuleShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/CapsuleShape3D.js +12 -0
- package/src/core/geom/3d/shape/UnitCubeShape3D.d.ts +37 -9
- package/src/core/geom/3d/shape/UnitCubeShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/UnitCubeShape3D.js +45 -98
- package/src/core/geom/3d/shape/UnitSphereShape3D.d.ts +10 -0
- package/src/core/geom/3d/shape/UnitSphereShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/UnitSphereShape3D.js +11 -0
- package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.d.ts +61 -0
- package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.d.ts.map +1 -0
- package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.js +148 -0
- package/src/core/geom/3d/tetrahedra/compute_tetrahedral_mesh_from_surface.d.ts +39 -0
- package/src/core/geom/3d/tetrahedra/compute_tetrahedral_mesh_from_surface.d.ts.map +1 -0
- package/src/core/geom/3d/tetrahedra/compute_tetrahedral_mesh_from_surface.js +147 -0
- package/src/core/geom/3d/tetrahedra/compute_tetrahedron_quality.d.ts +15 -0
- package/src/core/geom/3d/tetrahedra/compute_tetrahedron_quality.d.ts.map +1 -0
- package/src/core/geom/3d/tetrahedra/compute_tetrahedron_quality.js +22 -0
- package/src/core/geom/3d/tetrahedra/prototype_tetrahedrize_mesh.d.ts +2 -0
- package/src/core/geom/3d/tetrahedra/prototype_tetrahedrize_mesh.d.ts.map +1 -0
- package/src/core/geom/3d/tetrahedra/prototype_tetrahedrize_mesh.js +673 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.d.ts +26 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.d.ts.map +1 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.js +222 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_find_tets_around_edge.d.ts +34 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_find_tets_around_edge.d.ts.map +1 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_find_tets_around_edge.js +146 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.d.ts +36 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.d.ts.map +1 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.js +232 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.d.ts +33 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.d.ts.map +1 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.js +255 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.d.ts +68 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.d.ts.map +1 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.js +365 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.d.ts +31 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.d.ts.map +1 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.js +112 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.d.ts +22 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.d.ts.map +1 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.js +55 -0
- package/src/core/geom/3d/tetrahedra/tetrahedron_compute_quality.d.ts +32 -0
- package/src/core/geom/3d/tetrahedra/tetrahedron_compute_quality.d.ts.map +1 -0
- package/src/core/geom/3d/tetrahedra/tetrahedron_compute_quality.js +66 -0
- package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.d.ts +22 -0
- package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.js +49 -0
- package/src/core/geom/3d/topology/struct/binary/BinaryTopology.d.ts +134 -0
- package/src/core/geom/3d/topology/struct/binary/BinaryTopology.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/BinaryTopology.js +276 -3
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts +17 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.js +135 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compact.d.ts +14 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compact.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compact.js +177 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_decouple.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_decouple.js +20 -4
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +5 -3
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.js +9 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_get_or_create.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_get_or_create.js +21 -45
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill.js +7 -1
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts +8 -6
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.js +8 -6
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_kill_short_edges.d.ts +22 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_kill_short_edges.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_kill_short_edges.js +73 -0
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.js +51 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.d.ts +10 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.js +42 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.d.ts +28 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.js +227 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_walk_boundary_loops.d.ts +13 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_walk_boundary_loops.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_walk_boundary_loops.js +108 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_query_edge_is_boundary.d.ts +11 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_query_edge_is_boundary.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_query_edge_is_boundary.js +20 -0
- package/src/core/geom/3d/triangle/triangle_mesh_compute_signed_volume.d.ts +20 -0
- package/src/core/geom/3d/triangle/triangle_mesh_compute_signed_volume.d.ts.map +1 -0
- package/src/core/geom/3d/triangle/triangle_mesh_compute_signed_volume.js +38 -0
- package/src/core/graph/csr/CSRGraph.d.ts +168 -0
- package/src/core/graph/csr/CSRGraph.d.ts.map +1 -0
- package/src/core/graph/csr/CSRGraph.js +319 -0
- package/src/core/graph/metis/cluster_mesh_metis.d.ts +12 -0
- package/src/core/graph/metis/cluster_mesh_metis.d.ts.map +1 -1
- package/src/core/graph/metis/cluster_mesh_metis.js +12 -0
- package/src/core/graph/metis/metis.d.ts +19 -0
- package/src/core/graph/metis/metis.d.ts.map +1 -1
- package/src/core/graph/metis/metis.js +20 -0
- package/src/core/graph/metis/metis_cluster_bs.d.ts +11 -0
- package/src/core/graph/metis/metis_cluster_bs.d.ts.map +1 -1
- package/src/core/graph/metis/metis_cluster_bs.js +11 -0
- package/src/core/graph/metis/metis_options.d.ts +17 -2
- package/src/core/graph/metis/metis_options.d.ts.map +1 -1
- package/src/core/graph/metis/metis_options.js +17 -2
- package/src/core/graph/metis/native/MetisGraph.d.ts +144 -0
- package/src/core/graph/metis/native/MetisGraph.d.ts.map +1 -0
- package/src/core/graph/metis/native/MetisGraph.js +212 -0
- package/src/core/graph/metis/native/bisection/BisectionScratch.d.ts +72 -0
- package/src/core/graph/metis/native/bisection/BisectionScratch.d.ts.map +1 -0
- package/src/core/graph/metis/native/bisection/BisectionScratch.js +101 -0
- package/src/core/graph/metis/native/bisection/bisect_graph.d.ts +37 -0
- package/src/core/graph/metis/native/bisection/bisect_graph.d.ts.map +1 -0
- package/src/core/graph/metis/native/bisection/bisect_graph.js +100 -0
- package/src/core/graph/metis/native/bisection/compute_2way_params.d.ts +15 -0
- package/src/core/graph/metis/native/bisection/compute_2way_params.d.ts.map +1 -0
- package/src/core/graph/metis/native/bisection/compute_2way_params.js +84 -0
- package/src/core/graph/metis/native/bisection/fm_2way.d.ts +30 -0
- package/src/core/graph/metis/native/bisection/fm_2way.d.ts.map +1 -0
- package/src/core/graph/metis/native/bisection/fm_2way.js +290 -0
- package/src/core/graph/metis/native/bisection/grow_bisection.d.ts +23 -0
- package/src/core/graph/metis/native/bisection/grow_bisection.d.ts.map +1 -0
- package/src/core/graph/metis/native/bisection/grow_bisection.js +137 -0
- package/src/core/graph/metis/native/bisection/split_graph_two_way.d.ts +28 -0
- package/src/core/graph/metis/native/bisection/split_graph_two_way.d.ts.map +1 -0
- package/src/core/graph/metis/native/bisection/split_graph_two_way.js +119 -0
- package/src/core/graph/metis/native/coarsen/coarsen_graph.d.ts +20 -0
- package/src/core/graph/metis/native/coarsen/coarsen_graph.d.ts.map +1 -0
- package/src/core/graph/metis/native/coarsen/coarsen_graph.js +94 -0
- package/src/core/graph/metis/native/coarsen/create_coarse_graph.d.ts +24 -0
- package/src/core/graph/metis/native/coarsen/create_coarse_graph.d.ts.map +1 -0
- package/src/core/graph/metis/native/coarsen/create_coarse_graph.js +158 -0
- package/src/core/graph/metis/native/coarsen/match_shem.d.ts +41 -0
- package/src/core/graph/metis/native/coarsen/match_shem.d.ts.map +1 -0
- package/src/core/graph/metis/native/coarsen/match_shem.js +175 -0
- package/src/core/graph/metis/native/initial/initial_kway_bfs.d.ts +24 -0
- package/src/core/graph/metis/native/initial/initial_kway_bfs.d.ts.map +1 -0
- package/src/core/graph/metis/native/initial/initial_kway_bfs.js +122 -0
- package/src/core/graph/metis/native/initial/initial_kway_recursive_bisection.d.ts +29 -0
- package/src/core/graph/metis/native/initial/initial_kway_recursive_bisection.d.ts.map +1 -0
- package/src/core/graph/metis/native/initial/initial_kway_recursive_bisection.js +170 -0
- package/src/core/graph/metis/native/metis_partition_kway.d.ts +41 -0
- package/src/core/graph/metis/native/metis_partition_kway.d.ts.map +1 -0
- package/src/core/graph/metis/native/metis_partition_kway.js +126 -0
- package/src/core/graph/metis/native/refine/IndexedFloatMaxHeap.d.ts +62 -0
- package/src/core/graph/metis/native/refine/IndexedFloatMaxHeap.d.ts.map +1 -0
- package/src/core/graph/metis/native/refine/IndexedFloatMaxHeap.js +261 -0
- package/src/core/graph/metis/native/refine/RefinementScratch.d.ts +45 -0
- package/src/core/graph/metis/native/refine/RefinementScratch.d.ts.map +1 -0
- package/src/core/graph/metis/native/refine/RefinementScratch.js +53 -0
- package/src/core/graph/metis/native/refine/compute_kway_params.d.ts +18 -0
- package/src/core/graph/metis/native/refine/compute_kway_params.d.ts.map +1 -0
- package/src/core/graph/metis/native/refine/compute_kway_params.js +138 -0
- package/src/core/graph/metis/native/refine/fm_kway.d.ts +63 -0
- package/src/core/graph/metis/native/refine/fm_kway.d.ts.map +1 -0
- package/src/core/graph/metis/native/refine/fm_kway.js +462 -0
- package/src/core/graph/metis/native/refine/project_kway.d.ts +22 -0
- package/src/core/graph/metis/native/refine/project_kway.d.ts.map +1 -0
- package/src/core/graph/metis/native/refine/project_kway.js +43 -0
- package/src/core/graph/metis/native/refine/refine_kway.d.ts +34 -0
- package/src/core/graph/metis/native/refine/refine_kway.d.ts.map +1 -0
- package/src/core/graph/metis/native/refine/refine_kway.js +43 -0
- package/src/core/math/linalg/eigen/matrix_householder_in_place.d.ts +2 -2
- package/src/core/math/linalg/eigen/matrix_householder_in_place.js +2 -2
- package/src/core/math/linalg/eigen/matrix_qr_in_place.d.ts +6 -4
- package/src/core/math/linalg/eigen/matrix_qr_in_place.d.ts.map +1 -1
- package/src/core/math/linalg/eigen/matrix_qr_in_place.js +69 -23
- package/src/engine/EngineHarness.d.ts +3 -1
- package/src/engine/EngineHarness.d.ts.map +1 -1
- package/src/engine/EngineHarness.js +6 -4
- package/src/engine/control/first-person/DESIGN.md +30 -6
- package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +563 -0
- package/src/engine/control/first-person/FirstPersonPlayerController.d.ts +102 -9
- package/src/engine/control/first-person/FirstPersonPlayerController.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerController.js +38 -3
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts +533 -4
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.js +315 -6
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts +220 -22
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +858 -241
- package/src/engine/control/first-person/TODO.md +127 -0
- package/src/engine/control/first-person/abilities/Ability.d.ts +101 -0
- package/src/engine/control/first-person/abilities/Ability.d.ts.map +1 -0
- package/src/engine/control/first-person/abilities/Ability.js +119 -0
- package/src/engine/control/first-person/abilities/AbilitySet.d.ts +86 -0
- package/src/engine/control/first-person/abilities/AbilitySet.d.ts.map +1 -0
- package/src/engine/control/first-person/abilities/AbilitySet.js +185 -0
- package/src/engine/control/first-person/abilities/LedgeGrab.d.ts +62 -0
- package/src/engine/control/first-person/abilities/LedgeGrab.d.ts.map +1 -0
- package/src/engine/control/first-person/abilities/LedgeGrab.js +199 -0
- package/src/engine/control/first-person/abilities/Mantle.d.ts +45 -0
- package/src/engine/control/first-person/abilities/Mantle.d.ts.map +1 -0
- package/src/engine/control/first-person/abilities/Mantle.js +188 -0
- package/src/engine/control/first-person/abilities/Slide.d.ts +33 -0
- package/src/engine/control/first-person/abilities/Slide.d.ts.map +1 -0
- package/src/engine/control/first-person/abilities/Slide.js +158 -0
- package/src/engine/control/first-person/abilities/WallJump.d.ts +45 -0
- package/src/engine/control/first-person/abilities/WallJump.d.ts.map +1 -0
- package/src/engine/control/first-person/abilities/WallJump.js +131 -0
- package/src/engine/control/first-person/abilities/WallRun.d.ts +44 -0
- package/src/engine/control/first-person/abilities/WallRun.d.ts.map +1 -0
- package/src/engine/control/first-person/abilities/WallRun.js +180 -0
- package/src/engine/control/first-person/composer/EyeOffsetStack.d.ts +49 -0
- package/src/engine/control/first-person/composer/EyeOffsetStack.d.ts.map +1 -0
- package/src/engine/control/first-person/composer/EyeOffsetStack.js +60 -0
- package/src/engine/control/first-person/mastery/BreathRhythmEvaluator.d.ts +100 -0
- package/src/engine/control/first-person/mastery/BreathRhythmEvaluator.d.ts.map +1 -0
- package/src/engine/control/first-person/mastery/BreathRhythmEvaluator.js +133 -0
- package/src/engine/control/first-person/mastery/DecisionPoint.d.ts +10 -0
- package/src/engine/control/first-person/mastery/DecisionPoint.d.ts.map +1 -0
- package/src/engine/control/first-person/mastery/DecisionPoint.js +30 -0
- package/src/engine/control/first-person/mastery/FootAsymmetryTurnEvaluator.d.ts +61 -0
- package/src/engine/control/first-person/mastery/FootAsymmetryTurnEvaluator.d.ts.map +1 -0
- package/src/engine/control/first-person/mastery/FootAsymmetryTurnEvaluator.js +109 -0
- package/src/engine/control/first-person/mastery/MasteryEvaluator.d.ts +40 -0
- package/src/engine/control/first-person/mastery/MasteryEvaluator.d.ts.map +1 -0
- package/src/engine/control/first-person/mastery/MasteryEvaluator.js +45 -0
- package/src/engine/control/first-person/mastery/MasteryScore.d.ts +68 -0
- package/src/engine/control/first-person/mastery/MasteryScore.d.ts.map +1 -0
- package/src/engine/control/first-person/mastery/MasteryScore.js +100 -0
- package/src/engine/control/first-person/mastery/MasterySet.d.ts +60 -0
- package/src/engine/control/first-person/mastery/MasterySet.d.ts.map +1 -0
- package/src/engine/control/first-person/mastery/MasterySet.js +86 -0
- package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.d.ts +58 -0
- package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.d.ts.map +1 -0
- package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.js +83 -0
- package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.d.ts +69 -0
- package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.d.ts.map +1 -0
- package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.js +109 -0
- package/src/engine/control/first-person/math/Spring.d.ts +56 -0
- package/src/engine/control/first-person/math/Spring.d.ts.map +1 -0
- package/src/engine/control/first-person/math/Spring.js +71 -0
- package/src/engine/control/first-person/math/computeLRCBreathRate.d.ts +26 -0
- package/src/engine/control/first-person/math/computeLRCBreathRate.d.ts.map +1 -0
- package/src/engine/control/first-person/math/computeLRCBreathRate.js +41 -0
- package/src/engine/control/first-person/math/computeMassRatios.d.ts +35 -0
- package/src/engine/control/first-person/math/computeMassRatios.d.ts.map +1 -0
- package/src/engine/control/first-person/math/computeMassRatios.js +44 -0
- package/src/engine/control/first-person/pose/FirstPersonPose.d.ts +31 -1
- package/src/engine/control/first-person/pose/FirstPersonPose.d.ts.map +1 -1
- package/src/engine/control/first-person/pose/FirstPersonPose.js +49 -3
- package/src/engine/control/first-person/pose/FirstPersonPosture.d.ts +7 -0
- package/src/engine/control/first-person/pose/FirstPersonPosture.d.ts.map +1 -0
- package/src/engine/control/first-person/pose/FirstPersonPosture.js +27 -0
- package/src/engine/control/first-person/prototype_first_person_controller.js +550 -119
- package/src/engine/control/first-person/sensors/FirstPersonSensors.d.ts +58 -0
- package/src/engine/control/first-person/sensors/FirstPersonSensors.d.ts.map +1 -0
- package/src/engine/control/first-person/sensors/FirstPersonSensors.js +77 -0
- package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts +80 -0
- package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts.map +1 -0
- package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.js +196 -0
- package/src/engine/control/first-person/test/buildTestPlayer.d.ts +20 -0
- package/src/engine/control/first-person/test/buildTestPlayer.d.ts.map +1 -0
- package/src/engine/control/first-person/test/buildTestPlayer.js +28 -0
- package/src/engine/ecs/EntityManager.d.ts +2 -2
- package/src/engine/ecs/EntityManager.d.ts.map +1 -1
- package/src/engine/ecs/EntityManager.js +13 -8
- package/src/engine/ecs/System.d.ts.map +1 -1
- package/src/engine/ecs/System.js +2 -2
- package/src/engine/graphics/camera/testClippingPlaneComputation.js +0 -2
- package/src/engine/graphics/ecs/light/Light.d.ts.map +1 -1
- package/src/engine/graphics/ecs/light/Light.js +27 -0
- package/src/engine/graphics/ecs/light/LightSystem.js +1 -1
- package/src/engine/graphics/ecs/path/PathDisplaySystem.d.ts.map +1 -1
- package/src/engine/graphics/ecs/path/testPathDisplaySystem.js +0 -2
- package/src/engine/graphics/ecs/path/tube/prototypeAnimatedPathMask.js +0 -2
- package/src/engine/graphics/render/buffer/buffers/prototypeNormalFrameBuffer.js +0 -2
- package/src/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +0 -2
- package/src/engine/graphics/render/visibility/hiz/prototypeHiZ.js +0 -2
- package/src/engine/navigation/grid/find_path_on_grid_astar.d.ts.map +1 -1
- package/src/engine/navigation/grid/find_path_on_grid_astar.js +11 -2
- package/src/engine/navigation/mesh/bt_mesh_face_find_path.d.ts.map +1 -1
- package/src/engine/navigation/mesh/bt_mesh_face_find_path.js +11 -1
- package/src/engine/physics/PLAN.md +236 -0
- package/src/engine/physics/body/BodyStorage.d.ts +187 -0
- package/src/engine/physics/body/BodyStorage.d.ts.map +1 -0
- package/src/engine/physics/body/BodyStorage.js +427 -0
- package/src/engine/physics/broadphase/PairList.d.ts +62 -0
- package/src/engine/physics/broadphase/PairList.d.ts.map +1 -0
- package/src/engine/physics/broadphase/PairList.js +97 -0
- package/src/engine/physics/broadphase/aabb_transform_oriented.d.ts +30 -0
- package/src/engine/physics/broadphase/aabb_transform_oriented.d.ts.map +1 -0
- package/src/engine/physics/broadphase/aabb_transform_oriented.js +93 -0
- package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts +16 -0
- package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts.map +1 -0
- package/src/engine/physics/broadphase/compute_fat_world_aabb.js +61 -0
- package/src/engine/physics/broadphase/generate_pairs.d.ts +38 -0
- package/src/engine/physics/broadphase/generate_pairs.d.ts.map +1 -0
- package/src/engine/physics/broadphase/generate_pairs.js +101 -0
- package/src/engine/physics/contact/ManifoldStore.d.ts +226 -0
- package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -0
- package/src/engine/physics/contact/ManifoldStore.js +499 -0
- package/src/engine/physics/ecs/BodyKind.d.ts +23 -0
- package/src/engine/physics/ecs/BodyKind.d.ts.map +1 -0
- package/src/engine/physics/ecs/BodyKind.js +24 -0
- package/src/engine/physics/ecs/Collider.d.ts +98 -0
- package/src/engine/physics/ecs/Collider.d.ts.map +1 -0
- package/src/engine/physics/ecs/Collider.js +136 -0
- package/src/engine/physics/ecs/ColliderFlags.d.ts +14 -0
- package/src/engine/physics/ecs/ColliderFlags.d.ts.map +1 -0
- package/src/engine/physics/ecs/ColliderFlags.js +15 -0
- package/src/engine/physics/ecs/ColliderObserverSystem.d.ts +58 -0
- package/src/engine/physics/ecs/ColliderObserverSystem.d.ts.map +1 -0
- package/src/engine/physics/ecs/ColliderObserverSystem.js +103 -0
- package/src/engine/physics/ecs/ColliderSerializationAdapter.d.ts +25 -0
- package/src/engine/physics/ecs/ColliderSerializationAdapter.d.ts.map +1 -0
- package/src/engine/physics/ecs/ColliderSerializationAdapter.js +37 -0
- package/src/engine/physics/ecs/PhysicsEvents.d.ts +15 -0
- package/src/engine/physics/ecs/PhysicsEvents.d.ts.map +1 -0
- package/src/engine/physics/ecs/PhysicsEvents.js +16 -0
- package/src/engine/physics/ecs/PhysicsSystem.d.ts +520 -0
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -0
- package/src/engine/physics/ecs/PhysicsSystem.js +1159 -0
- package/src/engine/physics/ecs/RigidBody.d.ts +197 -0
- package/src/engine/physics/ecs/RigidBody.d.ts.map +1 -0
- package/src/engine/physics/ecs/RigidBody.js +240 -0
- package/src/engine/physics/ecs/RigidBodyFlags.d.ts +21 -0
- package/src/engine/physics/ecs/RigidBodyFlags.d.ts.map +1 -0
- package/src/engine/physics/ecs/RigidBodyFlags.js +22 -0
- package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts +28 -0
- package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts.map +1 -0
- package/src/engine/physics/ecs/RigidBodySerializationAdapter.js +81 -0
- package/src/engine/physics/ecs/SleepState.d.ts +11 -0
- package/src/engine/physics/ecs/SleepState.d.ts.map +1 -0
- package/src/engine/physics/ecs/SleepState.js +12 -0
- package/src/engine/physics/events/ContactEventBuffer.d.ts +46 -0
- package/src/engine/physics/events/ContactEventBuffer.d.ts.map +1 -0
- package/src/engine/physics/events/ContactEventBuffer.js +83 -0
- package/src/engine/physics/events/diff_manifolds.d.ts +25 -0
- package/src/engine/physics/events/diff_manifolds.d.ts.map +1 -0
- package/src/engine/physics/events/diff_manifolds.js +50 -0
- package/src/engine/physics/fluid/FluidField.d.ts +294 -16
- package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
- package/src/engine/physics/fluid/FluidField.js +510 -66
- package/src/engine/physics/fluid/FluidSimulator.d.ts +188 -5
- package/src/engine/physics/fluid/FluidSimulator.d.ts.map +1 -1
- package/src/engine/physics/fluid/FluidSimulator.js +455 -95
- package/src/engine/physics/fluid/SliceVisualiser.d.ts +29 -6
- package/src/engine/physics/fluid/SliceVisualiser.d.ts.map +1 -1
- package/src/engine/physics/fluid/SliceVisualiser.js +190 -165
- package/src/engine/physics/fluid/ecs/FluidComponent.d.ts +154 -0
- package/src/engine/physics/fluid/ecs/FluidComponent.d.ts.map +1 -0
- package/src/engine/physics/fluid/ecs/FluidComponent.js +238 -0
- package/src/engine/physics/fluid/ecs/FluidEffectorsComponent.d.ts +45 -0
- package/src/engine/physics/fluid/ecs/FluidEffectorsComponent.d.ts.map +1 -0
- package/src/engine/physics/fluid/ecs/FluidEffectorsComponent.js +89 -0
- package/src/engine/physics/fluid/ecs/FluidSystem.d.ts +107 -0
- package/src/engine/physics/fluid/ecs/FluidSystem.d.ts.map +1 -0
- package/src/engine/physics/fluid/ecs/FluidSystem.js +278 -0
- package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts +62 -1
- package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts.map +1 -1
- package/src/engine/physics/fluid/effector/AbstractFluidEffector.js +81 -6
- package/src/engine/physics/fluid/effector/GlobalFluidEffector.d.ts +17 -4
- package/src/engine/physics/fluid/effector/GlobalFluidEffector.d.ts.map +1 -1
- package/src/engine/physics/fluid/effector/GlobalFluidEffector.js +105 -12
- package/src/engine/physics/fluid/effector/ImpulseFluidEffector.d.ts +43 -0
- package/src/engine/physics/fluid/effector/ImpulseFluidEffector.d.ts.map +1 -0
- package/src/engine/physics/fluid/effector/ImpulseFluidEffector.js +210 -0
- package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts +62 -1
- package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts.map +1 -1
- package/src/engine/physics/fluid/effector/WakeFluidEffector.js +302 -8
- package/src/engine/physics/fluid/prototype.js +102 -91
- package/src/engine/physics/fluid/solver/optimal_sor_omega.d.ts +33 -0
- package/src/engine/physics/fluid/solver/optimal_sor_omega.d.ts.map +1 -0
- package/src/engine/physics/fluid/solver/optimal_sor_omega.js +41 -0
- package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts +20 -5
- package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.js +60 -38
- package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts +25 -4
- package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.js +93 -73
- package/src/engine/physics/fluid/solver/v3_grid_apply_scalar_advection.d.ts +23 -0
- package/src/engine/physics/fluid/solver/v3_grid_apply_scalar_advection.d.ts.map +1 -0
- package/src/engine/physics/fluid/solver/v3_grid_apply_scalar_advection.js +60 -0
- package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.d.ts +23 -0
- package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.d.ts.map +1 -0
- package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.js +68 -0
- package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts +30 -0
- package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts.map +1 -0
- package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.js +66 -0
- package/src/engine/physics/fluid/solver/v3_grid_patch_edges_uniform.d.ts +26 -0
- package/src/engine/physics/fluid/solver/v3_grid_patch_edges_uniform.d.ts.map +1 -0
- package/src/engine/physics/fluid/solver/v3_grid_patch_edges_uniform.js +113 -0
- package/src/engine/physics/fluid/solver/v3_grid_shift_in_place.d.ts +30 -0
- package/src/engine/physics/fluid/solver/v3_grid_shift_in_place.d.ts.map +1 -0
- package/src/engine/physics/fluid/solver/v3_grid_shift_in_place.js +107 -0
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts +49 -0
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts.map +1 -0
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.js +126 -0
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts +93 -0
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts.map +1 -0
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.js +424 -0
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.d.ts +20 -0
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.d.ts.map +1 -0
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.js +83 -0
- package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts +26 -0
- package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts.map +1 -0
- package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +70 -0
- package/src/engine/physics/gjk/expanding_polytope_algorithm.d.ts.map +1 -1
- package/src/engine/physics/gjk/expanding_polytope_algorithm.js +8 -10
- package/src/engine/physics/inertia/world_inverse_inertia.d.ts +29 -0
- package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -0
- package/src/engine/physics/inertia/world_inverse_inertia.js +79 -0
- package/src/engine/physics/integration/integrate_position.d.ts +16 -0
- package/src/engine/physics/integration/integrate_position.d.ts.map +1 -0
- package/src/engine/physics/integration/integrate_position.js +48 -0
- package/src/engine/physics/integration/integrate_velocity.d.ts +25 -0
- package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -0
- package/src/engine/physics/integration/integrate_velocity.js +79 -0
- package/src/engine/physics/integration/quat_integrate.d.ts +27 -0
- package/src/engine/physics/integration/quat_integrate.d.ts.map +1 -0
- package/src/engine/physics/integration/quat_integrate.js +62 -0
- package/src/engine/physics/island/IslandBuilder.d.ts +167 -0
- package/src/engine/physics/island/IslandBuilder.d.ts.map +1 -0
- package/src/engine/physics/island/IslandBuilder.js +411 -0
- package/src/engine/physics/island/union_find.d.ts +51 -0
- package/src/engine/physics/island/union_find.d.ts.map +1 -0
- package/src/engine/physics/island/union_find.js +76 -0
- package/src/engine/physics/narrowphase/PosedShape.d.ts +59 -0
- package/src/engine/physics/narrowphase/PosedShape.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/PosedShape.js +110 -0
- package/src/engine/physics/narrowphase/box_box_manifold.d.ts +32 -0
- package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/box_box_manifold.js +543 -0
- package/src/engine/physics/narrowphase/capsule_contacts.d.ts +122 -0
- package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/capsule_contacts.js +508 -0
- package/src/engine/physics/narrowphase/narrowphase_step.d.ts +11 -0
- package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/narrowphase_step.js +382 -0
- package/src/engine/physics/narrowphase/sphere_box_contact.d.ts +38 -0
- package/src/engine/physics/narrowphase/sphere_box_contact.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/sphere_box_contact.js +130 -0
- package/src/engine/physics/narrowphase/sphere_sphere_contact.d.ts +26 -0
- package/src/engine/physics/narrowphase/sphere_sphere_contact.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/sphere_sphere_contact.js +51 -0
- package/src/engine/physics/queries/PhysicsSurfacePoint.d.ts +83 -0
- package/src/engine/physics/queries/PhysicsSurfacePoint.d.ts.map +1 -0
- package/src/engine/physics/queries/PhysicsSurfacePoint.js +100 -0
- package/src/engine/physics/queries/raycast.d.ts +20 -0
- package/src/engine/physics/queries/raycast.d.ts.map +1 -0
- package/src/engine/physics/queries/raycast.js +249 -0
- package/src/engine/physics/solver/friction_cone.d.ts +16 -0
- package/src/engine/physics/solver/friction_cone.d.ts.map +1 -0
- package/src/engine/physics/solver/friction_cone.js +37 -0
- package/src/engine/physics/solver/solve_contacts.d.ts +36 -0
- package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -0
- package/src/engine/physics/solver/solve_contacts.js +598 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/OrderedEdge.d.ts +0 -34
- package/src/core/geom/3d/topology/struct/binary/io/edge/OrderedEdge.d.ts.map +0 -1
- package/src/core/geom/3d/topology/struct/binary/io/edge/OrderedEdge.js +0 -66
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_calc_edges.d.ts +0 -2
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_calc_edges.d.ts.map +0 -1
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_calc_edges.js +0 -54
- package/src/core/geom/3d/topology/struct/binary/io/edge/get_or_create_edge_map.d.ts +0 -2
- package/src/core/geom/3d/topology/struct/binary/io/edge/get_or_create_edge_map.d.ts.map +0 -1
- package/src/core/geom/3d/topology/struct/binary/io/edge/get_or_create_edge_map.js +0 -26
- package/src/engine/ecs/components/Motion.d.ts +0 -21
- package/src/engine/ecs/components/Motion.d.ts.map +0 -1
- package/src/engine/ecs/components/Motion.js +0 -27
- package/src/engine/ecs/components/MotionSerializationAdapter.d.ts +0 -20
- package/src/engine/ecs/components/MotionSerializationAdapter.d.ts.map +0 -1
- package/src/engine/ecs/components/MotionSerializationAdapter.js +0 -26
- package/src/engine/ecs/systems/MotionSystem.d.ts +0 -9
- package/src/engine/ecs/systems/MotionSystem.d.ts.map +0 -1
- package/src/engine/ecs/systems/MotionSystem.js +0 -29
- package/src/engine/physics/fluid/Fluid.d.ts +0 -26
- package/src/engine/physics/fluid/Fluid.d.ts.map +0 -1
- package/src/engine/physics/fluid/Fluid.js +0 -221
- package/src/engine/physics/fluid/solver/v3_grid_apply_advection_reverse.d.ts +0 -7
- package/src/engine/physics/fluid/solver/v3_grid_apply_advection_reverse.d.ts.map +0 -1
- 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
|
+
}
|